├── .github └── workflows │ ├── php-cs-fixer.yml │ ├── php.yml │ ├── tests.yml │ └── update-changelog.yml ├── .gitignore ├── .phpunit.result.cache ├── CHANGELOG.md ├── LICENSE ├── README.md ├── assets └── logo.png ├── composer.json ├── composer.lock ├── docs ├── commands.md └── php.md ├── phpunit.xml.dist ├── src ├── Abstracts │ └── MultiProcessAbstract.php ├── Classes │ └── MultiProcess.php ├── Commands │ └── InstallCommand.php ├── Config │ └── multi_process.php ├── Facades │ └── MultiProcessFacade.php ├── Interfaces │ └── MultiProcessInterface.php └── Providers │ └── MultiProcessServiceProviders.php └── tests ├── BaseTest.php └── Feature ├── CommandsTest.php └── PHPTest.php /.github/workflows/php-cs-fixer.yml: -------------------------------------------------------------------------------- 1 | name: Check & fix styling 2 | 3 | on: [push,pull_request] 4 | 5 | jobs: 6 | php-cs-fixer: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout code 11 | uses: actions/checkout@v2 12 | with: 13 | ref: ${{ github.head_ref }} 14 | 15 | - name: Run PHP Code Style Fixer 16 | uses: docker://oskarstark/php-cs-fixer-ga 17 | with: 18 | args: --config=.php-cs-fixer.dist.php --allow-risky=yes 19 | 20 | - name: Commit changes 21 | uses: stefanzweifel/git-auto-commit-action@v4 22 | with: 23 | commit_message: Fix styling 24 | -------------------------------------------------------------------------------- /.github/workflows/php.yml: -------------------------------------------------------------------------------- 1 | name: PHP Composer 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | 17 | - name: Validate composer.json and composer.lock 18 | run: composer validate --strict 19 | 20 | - name: Cache Composer packages 21 | id: composer-cache 22 | uses: actions/cache@v2 23 | with: 24 | path: vendor 25 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} 26 | restore-keys: | 27 | ${{ runner.os }}-php- 28 | - name: Install dependencies 29 | run: composer install --prefer-dist --no-progress 30 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Run tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | fail-fast: false 10 | matrix: 11 | os: [ubuntu-latest] 12 | php: [7.4, 8.0] 13 | laravel: [8.*,7.*] 14 | dependency-version: [prefer-stable] 15 | include: 16 | - testbench: ^6.23 17 | laravel: 8.* 18 | 19 | - testbench: 5.20 20 | laravel: 7.* 21 | 22 | name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} - ${{ matrix.os }} 23 | 24 | steps: 25 | - name: Checkout code 26 | uses: actions/checkout@v2 27 | 28 | - name: Setup PHP 29 | uses: shivammathur/setup-php@v2 30 | with: 31 | php-version: ${{ matrix.php }} 32 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick 33 | coverage: none 34 | 35 | - name: Install dependencies 36 | run: | 37 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update 38 | composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest 39 | - name: Execute tests 40 | run: vendor/bin/phpunit 41 | -------------------------------------------------------------------------------- /.github/workflows/update-changelog.yml: -------------------------------------------------------------------------------- 1 | name: "Update Changelog" 2 | 3 | on: 4 | release: 5 | types: [released] 6 | 7 | jobs: 8 | update: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v2 14 | with: 15 | ref: main 16 | 17 | - name: Update Changelog 18 | uses: stefanzweifel/changelog-updater-action@v1 19 | with: 20 | latest-version: ${{ github.event.release.name }} 21 | release-notes: ${{ github.event.release.body }} 22 | 23 | - name: Commit updated CHANGELOG 24 | uses: stefanzweifel/git-auto-commit-action@v4 25 | with: 26 | branch: main 27 | commit_message: Update CHANGELOG 28 | file_pattern: CHANGELOG.md 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | -------------------------------------------------------------------------------- /.phpunit.result.cache: -------------------------------------------------------------------------------- 1 | {"version":1,"defects":{"SOS\\MultiProcess\\Tests\\Feature\\CommandsTest::test_if_commands_run_successfully":4,"Warning":6},"times":{"SOS\\MultiProcess\\Tests\\Feature\\CommandsTest::test_if_commands_run_successfully":6.136,"Warning":0.012,"SOS\\MultiProcess\\Tests\\BaseTest::test_base_test":0.206,"SOS\\MultiProcess\\Tests\\Feature\\CommandsTest::test_base_test":0.038}} -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v1.2.1 - 2022-02-08 2 | 3 | - Fix the packge badges 4 | - Fix the Process class extends 5 | 6 | ## v1.2.0 - 2022-02-03 7 | 8 | - Add tasks log 9 | 10 | ## v1.1.0 - 2022-01-21 11 | 12 | - Added run php code feature. 13 | - Improved GitHub test. 14 | - Added throw exception when any task was failed. 15 | 16 | ## v1.1.0 17 | 18 | - Adding execute process from a php code. 19 | - Adding tasks activities. 20 | 21 | ## v1.0.0 22 | 23 | - First release 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Syrian Open Source 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![logo](assets/logo.png) 2 | [![PHP Composer](https://github.com/syrian-open-source/laravel-multi-process/actions/workflows/php.yml/badge.svg)](https://github.com/syrian-open-source/laravel-multi-process/actions/workflows/php.yml) 3 | [![Run tests](https://github.com/syrian-open-source/laravel-multi-process/actions/workflows/tests.yml/badge.svg)](https://github.com/syrian-open-source/laravel-multi-process/actions/workflows/tests.yml) 4 | ![Code Quality Score](https://api.codiga.io/project/30511/score/svg) 5 | 6 | # Multi Process 7 | 8 | Laravel package making you able to perform several process instead of executing them through one process 9 | Installation 10 | 11 | ##### 1 - Dependency 12 | The first step is using composer to install the package and automatically update your composer.json file, you can do this by running: 13 | 14 | ```shell 15 | composer require syrian-open-source/laravel-multi-process 16 | ``` 17 | ##### 2 - Copy the package providers to your local config with the publish command, this will publish the config: 18 | ```shell 19 | php artisan multi-process:install 20 | ``` 21 | 22 | Features 23 | ----------- 24 | - [Run process from commands](https://github.com/syrian-open-source/laravel-multi-process/blob/main/docs/commands.md) 25 | - [Run php codes](https://github.com/syrian-open-source/laravel-multi-process/blob/main/docs/php.md) 26 | 27 | 28 | Changelog 29 | --------- 30 | Please see the [CHANGELOG](https://github.com/syrian-open-source/laravel-multi-process/blob/master/CHANGELOG.md) for more information about what has changed or updated or added recently. 31 | 32 | Security 33 | -------- 34 | If you discover any security related issues, please email them first to karam2mustafa@gmail.com, 35 | if we do not fix it within a short period of time please open a new issue describing your problem. 36 | 37 | Credits 38 | ------- 39 | [karam mustafa](https://www.linkedin.com/in/karam2mustafa) 40 | 41 | About Syrian Open Source 42 | ------- 43 | The Syrian Open Source platform is the first platform on GitHub dedicated to bringing Syrian developers from different cultures and experiences together, to work on projects in different languages, tasks, and versions, and works to attract Syrian developers to contribute more under one platform to open source software, work on it, and issue it with high quality and advanced engineering features, which It stimulates the dissemination of the open-source concept in the Syrian software community, and also contributes to raising the efficiency of developers by working on distributed systems and teams. 44 | -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Syrian-Open-Source/laravel-multi-process/aaf5f35174520a7294d372436c8056437075c190/assets/logo.png -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "syrian-open-source/laravel-multi-process", 3 | "description": "Laravel package making you able to perform several process instead of executing them through one process", 4 | "license": "MIT", 5 | "keywords": [ 6 | "laravel", 7 | "multi-process", 8 | "laravel-multi-process", 9 | "syrian-open-source" 10 | ], 11 | "authors": [ 12 | { 13 | "name": "Karam Mustafa", 14 | "email": "karam2mustafa@gmail.com", 15 | "homepage": "https://github.com/karam-mustafa", 16 | "role": "Developer" 17 | } 18 | ], 19 | "require": { 20 | "phpunit/phpunit": "^9.5", 21 | "symfony/process": "^5.4" 22 | }, 23 | "autoload" : { 24 | "psr-4": { 25 | "SOS\\MultiProcess\\" : "src", 26 | "SOS\\MultiProcess\\Tests\\": "src/tests" 27 | } 28 | }, 29 | "scripts": { 30 | "test": "vendor/bin/phpunit", 31 | "test-coverage": "phpunit --coverage-html coverage" 32 | }, 33 | "extra" : { 34 | "laravel" : { 35 | "providers" : [ 36 | "SOS\\MultiProcess\\Providers\\MultiProcessServiceProviders" 37 | ] 38 | } 39 | }, 40 | "minimum-stability": "dev", 41 | "prefer-stable": true, 42 | "require-dev": { 43 | "orchestra/testbench": "^6.23" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /docs/commands.md: -------------------------------------------------------------------------------- 1 | Usage 2 | -------- 3 | * Define multiple process and execute them by start function. 4 | 5 | ```shell 6 | $process = \SOS\MultiProcess\Facades\MultiProcessFacade::setTasks( 7 | "php artisan make:model modelName", 8 | "php artisan make:model ControllerName", 9 | // and you can define unlimited commands 10 | ); 11 | $process->start() 12 | // if ypu want to see the tasks log, 13 | // you can fetch the tasks lists by calling the function 14 | ->getTasks(); 15 | 16 | ``` 17 | * Define multiple process and execute them by run function. 18 | 19 | ```shell 20 | 21 | $process = \SOS\MultiProcess\Facades\MultiProcessFacade::setTasks( 22 | "php artisan make:model modelName", 23 | "php artisan make:model ControllerName", 24 | // and you can define unlimited commands 25 | ); 26 | 27 | // run function will allows you to get the output from the execution process. 28 | $process->run() 29 | // if ypu want to see the tasks log, 30 | // you can fetch the tasks lists by calling the function 31 | ->getTasks(); 32 | 33 | ``` 34 | * Add options. 35 | 36 | ```shell 37 | 38 | // default options are in multi_process.php file. 39 | // you can change them from the file 40 | // or you can basicly added them from the setter function. 41 | $process = \SOS\MultiProcess\Facades\MultiProcessFacade::setTasks( 42 | "php artisan make:model modelName", 43 | "php artisan make:model ControllerName", 44 | // and you can define unlimited commands 45 | )->setOptions([ 46 | 'timeOut' => 60, 47 | 'ideTimeOut' => 60, 48 | 'enableOutput' => true, 49 | 'processTime' => 3, 50 | 51 | // thorw exceprtion if any task was failed. 52 | 'throwIfTaskNotSuccess' => false, 53 | ); 54 | 55 | // run or start your tasks. 56 | $process->start() 57 | // if ypu want to see the tasks log, 58 | // you can fetch the tasks lists by calling the function 59 | ->getTasks(); 60 | 61 | ``` 62 | -------------------------------------------------------------------------------- /docs/php.md: -------------------------------------------------------------------------------- 1 | Usage 2 | -------- 3 | * Define multiple process and execute them by start function, 4 | each task must be a callback function as you can see in the below example. 5 | 6 | ```shell 7 | 8 | // if you are enable the output from the options 9 | // you can see the outputs are printed. 10 | $process = \SOS\MultiProcess\Facades\MultiProcessFacade::setTasks( 11 | function () { 12 | echo 'The first task to run'; 13 | }, function () { 14 | echo 'The second task to run'; 15 | } 16 | ); 17 | $process->runPHP() 18 | // if ypu want to see the tasks log, 19 | // you can fetch the tasks lists by calling the function 20 | ->getTasks(); 21 | ``` 22 | * Add options. 23 | 24 | ```shell 25 | 26 | // default options are in multi_process.php file. 27 | // you can change them from the file 28 | // or you can basicly added them from the setter function. 29 | $process = \SOS\MultiProcess\Facades\MultiProcessFacade::setTasks( 30 | function () { 31 | echo 'The first task to run'; 32 | }, function () { 33 | echo 'The second task to run'; 34 | } 35 | ->setOptions([ 36 | 'timeOut' => 60, 37 | 'ideTimeOut' => 60, 38 | 'enableOutput' => true, 39 | 'processTime' => 3, 40 | 41 | // thorw exceprtion if any task was failed. 42 | 'throwIfTaskNotSuccess' => false, 43 | ); 44 | 45 | // run or start your tasks. 46 | $process->runPHP() 47 | // if ypu want to see the tasks log, 48 | // you can fetch the tasks lists by calling the function 49 | ->getTasks(); 50 | ``` 51 | 52 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | src/ 6 | 7 | 8 | 9 | 10 | tests 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Abstracts/MultiProcessAbstract.php: -------------------------------------------------------------------------------- 1 | 60, 34 | 'ideTimeOut' => 60, 35 | 'workingDirectory' => null, 36 | 'enableOutput' => true, 37 | 'processTime' => 3, 38 | 'throwIfTaskNotSuccess' => false, 39 | ]; 40 | /** 41 | * 42 | * @author karam mustafa 43 | * @var array 44 | */ 45 | private $processing = []; 46 | /** 47 | * 48 | * @author karam mustafa 49 | * @var int 50 | */ 51 | private $processCount = 3; 52 | /** 53 | * 54 | * @author karam mustafa 55 | * @var int 56 | */ 57 | private $waitingState = 1; 58 | /** 59 | * 60 | * @author karam mustafa 61 | * @var int 62 | */ 63 | private $processingState = 2; 64 | /** 65 | * 66 | * @author karam mustafa 67 | * @var int 68 | */ 69 | private $completedState = 3; 70 | /** 71 | * 72 | * @author karam mustafa 73 | * @var string 74 | */ 75 | private $stateKey = 'state'; 76 | /** 77 | * 78 | * @author karam mustafa 79 | * @var string 80 | */ 81 | private $commandKey = 'command'; 82 | 83 | /** 84 | * @return string 85 | * @author karam mustaf 86 | */ 87 | public function getCommandKey() 88 | { 89 | return $this->commandKey; 90 | } 91 | 92 | /** 93 | * @param string $commandKey 94 | * 95 | * @return MultiProcess 96 | * @author karam mustaf 97 | */ 98 | public function setCommandKey($commandKey) 99 | { 100 | $this->commandKey = $commandKey; 101 | 102 | return $this; 103 | } 104 | 105 | /** 106 | * @return mixed 107 | * @author karam mustaf 108 | */ 109 | public function getTasks() 110 | { 111 | return $this->tasks; 112 | } 113 | 114 | /** 115 | * @param mixed $tasks 116 | * 117 | * @return MultiProcess 118 | * @author karam mustaf 119 | */ 120 | public function setTasks(...$tasks) 121 | { 122 | foreach ($tasks as $task) { 123 | $scheduleTask = []; 124 | $scheduleTask['command'] = $task; 125 | $scheduleTask[$this->stateKey] = $this->waitingState; 126 | $this->tasks[] = $scheduleTask; 127 | } 128 | return $this; 129 | } 130 | 131 | /** 132 | * @param $key 133 | * 134 | * @return mixed 135 | * @author karam mustaf 136 | */ 137 | public function getOptions($key) 138 | { 139 | return isset($this->options[$key]) ? $this->options[$key] : $this->options; 140 | } 141 | 142 | /** 143 | * @param mixed $options 144 | * 145 | * @return MultiProcess 146 | * @author karam mustaf 147 | */ 148 | public function setOptions($options) 149 | { 150 | $this->options = array_merge($this->options, $options); 151 | 152 | return $this; 153 | } 154 | 155 | /** 156 | * display message depending on symfony returned type. 157 | * 158 | * @param $type 159 | * @param $buffer 160 | * 161 | * @author karam mustafa 162 | */ 163 | public function displayOutputMessage($type, $buffer) 164 | { 165 | if (Process::ERR === $type) { 166 | echo 'ERROR >> '.$buffer; 167 | } else { 168 | echo 'SUCCESS >> '.$buffer; 169 | } 170 | } 171 | 172 | /** 173 | * run the php codes 174 | * 175 | * @return \SOS\MultiProcess\Classes\MultiProcess 176 | * @throws \Exception 177 | * @author karam mustafa 178 | */ 179 | public function runPHP() 180 | { 181 | 182 | $this->phpProcess($this->higherOrderRun()); 183 | 184 | $this->resolveNotRunningProcess($this->higherOrderRun()); 185 | 186 | return $this; 187 | } 188 | 189 | /** 190 | * this function will execute run function in symfony component 191 | * the function will check if we must display the error or the 192 | * response status from the executed functions from the symfony classes. 193 | * 194 | * @author karam mustafa 195 | */ 196 | public function run() 197 | { 198 | $this->process($this->higherOrderRun()); 199 | 200 | $this->resolveNotRunningProcess($this->higherOrderRun()); 201 | 202 | return $this; 203 | } 204 | 205 | 206 | /** 207 | * start all process. 208 | * 209 | * @author karam mustafa 210 | */ 211 | public function start() 212 | { 213 | // define the callback function. 214 | $callback = function (Process $process) { 215 | return $process->start(); 216 | }; 217 | 218 | $this->process($callback); 219 | 220 | $this->resolveNotRunningProcess($callback); 221 | 222 | return $this; 223 | 224 | } 225 | 226 | /** 227 | * run the php codes from tasks, and each task must be a callback function. 228 | * 229 | * @param $callback 230 | * 231 | * @author karam mustafa 232 | */ 233 | private function phpProcess($callback) 234 | { 235 | while ($task = $this->checkIfCanProcess()) { 236 | 237 | $process = new PhpProcess("getCommandKey()]()} ?>"); 238 | 239 | // Add the process to the processing property 240 | $this->processing[] = $process; 241 | 242 | $callback($process); 243 | 244 | if (!$process->isSuccessful() && $this->getOptions('throwIfTaskNotSuccess')) { 245 | throw new ProcessFailedException($process); 246 | } 247 | } 248 | } 249 | 250 | /** 251 | * this function will set the require config to a symfony process component. 252 | * and run what a callback will execute. 253 | * 254 | * @param $callback 255 | * 256 | * @author karam mustafa 257 | */ 258 | private function process($callback) 259 | { 260 | while ($task = $this->checkIfCanProcess()) { 261 | 262 | $process = Process::fromShellCommandline($task[$this->getCommandKey()]) 263 | ->enableOutput() 264 | ->setTimeout($this->getOptions('timeOut')) 265 | ->setIdleTimeout($this->getOptions('ideTimeOut')) 266 | ->setWorkingDirectory(base_path()); 267 | 268 | // Add the process to the processing property 269 | $this->processing[] = $process; 270 | 271 | // run the given callback from the process argument 272 | // this callback could be a start or run function in symfony component 273 | // or might be any callback that accept Process parameter as a dependency. 274 | $callback($process); 275 | 276 | if (!$process->isSuccessful() && $this->getOptions('throwIfTaskNotSuccess')) { 277 | throw new ProcessFailedException($process); 278 | } 279 | 280 | } 281 | } 282 | 283 | /** 284 | * this function will check if the entire process is was not finished yet 285 | * if there are any process that waiting to process, run this process 286 | * and remove it from processing array 287 | * then convert this task status to finish. 288 | * 289 | * @param $callback 290 | * 291 | * @author karam mustafa 292 | */ 293 | private function resolveNotRunningProcess($callback) 294 | { 295 | while (count($this->processing) || !$this->isFinished()) { 296 | foreach ($this->processing as $i => $runningProcess) { 297 | if (!$runningProcess->isRunning()) { 298 | 299 | // Remove this task from processing list and run it. 300 | // then register the task log tell that task is now running 301 | // and when the task finished register a new log. 302 | unset($this->processing[$i]); 303 | 304 | $this->process(function (Process $process) use ($callback) { 305 | return $callback($process); 306 | }); 307 | 308 | $this->registerTaskLog($i, 'task is running'); 309 | 310 | $this->finishTask($i); 311 | } 312 | } 313 | sleep($this->getOptions('processTime')); 314 | } 315 | } 316 | 317 | /** 318 | * after each task that processed in process function. 319 | * we will find the next task that have a waiting status. 320 | * and convert it status to a processing. 321 | * 322 | * @return null 323 | * @author karam mustafa 324 | */ 325 | private function next() 326 | { 327 | foreach ($this->tasks as $i => $task) { 328 | if ($task[$this->stateKey] == $this->waitingState) { 329 | $this->tasks[$i][$this->stateKey] = $this->processingState; 330 | return $task; 331 | } 332 | } 333 | 334 | return null; 335 | } 336 | 337 | /** 338 | * convert task state to completed 339 | * 340 | * @param $key 341 | * 342 | * @author karam mustafa 343 | */ 344 | private function finishTask($key) 345 | { 346 | if (isset($this->tasks[$key])) { 347 | $this->tasks[$key]['state'] = $this->completedState; 348 | } 349 | 350 | $this->registerTaskLog($key, 'task finished'); 351 | } 352 | 353 | /** 354 | * check if the all processes are complete. 355 | * 356 | * @return bool 357 | * @author karam mustafa 358 | */ 359 | public function isFinished() 360 | { 361 | foreach ($this->tasks as $task) { 362 | if ($task['state'] !== $this->completedState) { 363 | return false; 364 | } 365 | } 366 | return true; 367 | } 368 | 369 | /** 370 | * check if there is a next task, or we are finish the all processes. 371 | * 372 | * @return bool|null 373 | * @author karam mustafa 374 | */ 375 | private function checkIfCanProcess() 376 | { 377 | $task = $this->next(); 378 | return (count($this->processing) < $this->processCount) && $task 379 | ? $task 380 | : false; 381 | } 382 | 383 | /** 384 | * return a callback that execute run function inside process component. 385 | * 386 | * @return \Closure 387 | * @author karam mustafa 388 | */ 389 | private function higherOrderRun() 390 | { 391 | return function (Process $process) { 392 | return $process->run(function ($type, $buffer) { 393 | 394 | // if we enable the output, then display this message depending on it type. 395 | if ($this->getOptions('enableOutput')) { 396 | $this->displayOutputMessage($type, $buffer); 397 | } 398 | }); 399 | }; 400 | } 401 | 402 | /** 403 | * when any task change it status, this function must register log that describe the changes. 404 | * 405 | * @param $key 406 | * @param string $message 407 | * 408 | * @author karam mustafa 409 | */ 410 | private function registerTaskLog($key, $message) 411 | { 412 | if (!isset($this->tasks[$key]['log'])) { 413 | $this->tasks[$key]['log'] = []; 414 | } 415 | 416 | array_push($this->tasks[$key]['log'], $message); 417 | } 418 | 419 | } 420 | -------------------------------------------------------------------------------- /src/Commands/InstallCommand.php: -------------------------------------------------------------------------------- 1 | info(' Install the dependencies was success'); 48 | 49 | if ($this->confirm('Would you like to show some love by starring the repo?', true)) { 50 | if (PHP_OS_FAMILY === 'Darwin') { 51 | exec("open $this->packageLink"); 52 | } 53 | if (PHP_OS_FAMILY === 'Linux') { 54 | exec("xdg-open $this->packageLink"); 55 | } 56 | if (PHP_OS_FAMILY === 'Windows') { 57 | exec("start $this->packageLink"); 58 | } 59 | 60 | $this->line('Thank you!'); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Config/multi_process.php: -------------------------------------------------------------------------------- 1 | [ 14 | 15 | // the timeout time that symfony process component 16 | // trying to execute the each command. 17 | 'timeOut' => 60, 18 | 19 | // the ide timeout time that symfony process component 20 | // trying to execute the each command. 21 | 'ideTimeOut' => 60, 22 | 23 | // dump output if you are using run method to execute your tasks 24 | 'enableOutput' => true, 25 | 26 | // The time in seconds that the package tries to perform the un executed tasks. 27 | 'processTime' => 3, 28 | 29 | ], 30 | ]; 31 | -------------------------------------------------------------------------------- /src/Facades/MultiProcessFacade.php: -------------------------------------------------------------------------------- 1 | publishesPackages(); 21 | $this->resolveCommands(); 22 | $this->registerFacades(); 23 | } 24 | 25 | /** 26 | * 27 | * 28 | * @author karam mustafa 29 | */ 30 | public function register() 31 | { 32 | } 33 | 34 | /** 35 | * register all facade classes 36 | */ 37 | protected function registerFacades() 38 | { 39 | $this->app->singleton('MultiProcessFacade', function () { 40 | return new MultiProcess(); 41 | }); 42 | } 43 | 44 | /** 45 | * publish files 46 | * 47 | * @author karam mustafa 48 | */ 49 | protected function publishesPackages() 50 | { 51 | $this->publishes([ 52 | __DIR__.'/../Config/multi_process.php' => config_path('multi_process.php'), 53 | ], 'multi-process-config'); 54 | } 55 | 56 | /** 57 | * find and register all package commands 58 | * 59 | * @author karam mustafa 60 | */ 61 | private function resolveCommands() 62 | { 63 | if ($this->app->runningInConsole()) { 64 | $this->commands([ 65 | InstallCommand::class, 66 | ]); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/BaseTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/Feature/CommandsTest.php: -------------------------------------------------------------------------------- 1 | setTasks( 24 | "php artisan make:model MultiProcessTestModel", 25 | "php artisan make:model MultiProcessTestController" 26 | )->setOptions([ 27 | 'enableOutput' => false 28 | ]); 29 | 30 | foreach ($processor->start()->getTasks() as $task) { 31 | $this->assertEquals($task['state'], $completedState); 32 | 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/Feature/PHPTest.php: -------------------------------------------------------------------------------- 1 | setTasks( 24 | function () { 25 | echo 'process 1'; 26 | }, 27 | function () { 28 | echo 'process 2'; 29 | }, 30 | function () { 31 | echo 'process 3'; 32 | } 33 | ); 34 | 35 | foreach ($processor->runPHP()->getTasks() as $task) { 36 | $this->assertEquals($task['state'], $completedState); 37 | } 38 | 39 | } 40 | } 41 | --------------------------------------------------------------------------------