├── .gitignore ├── .scrutinizer.yml ├── Api ├── ChunkSizeCalculatorInterface.php ├── CustomerIdsProviderInterface.php ├── Data │ ├── HtmlInterface.php │ ├── ProcessInterface.php │ └── UrlInterface.php ├── Report │ ├── CliReportManagerInterface.php │ ├── ReportGeneratorInterface.php │ ├── ReportSenderInterface.php │ └── WebapiReportManagerInterface.php └── TimerInterface.php ├── Console └── Command │ ├── GenerateReports.php │ ├── StartCliReportingService.php │ └── StartWebapiReportingService.php ├── Exception └── TimerException.php ├── LICENSE ├── Model ├── Adapter │ └── ReactPHP │ │ ├── ClientFactory.php │ │ └── ProcessFactory.php ├── ChunkSizeCalculator.php ├── Data │ ├── Html.php │ ├── Process.php │ └── Url.php ├── FakeCustomerIdsProvider.php ├── Report │ ├── CliReportManager.php │ ├── ReportGenerator.php │ ├── ReportSender.php │ └── WebapiReportManager.php └── Timer.php ├── README.md ├── Standalone ├── ChildProcess │ ├── AsynchronousProcessRunner.php │ ├── HalfAsynchronousProcessRunner.php │ ├── ProcessRunnerInterface.php │ ├── SynchronousProcessRunner.php │ └── processes │ │ ├── pi │ │ ├── primes │ │ ├── random │ │ └── sleep ├── Http │ ├── AsynchronousClient.php │ ├── ClientInterface.php │ ├── HalfAsynchronousClient.php │ ├── SynchronousClient.php │ └── UrlProvider.php └── bin │ ├── childprocess │ └── http ├── Test └── Unit │ ├── Console │ └── Command │ │ ├── GenerateReportsTest.php │ │ ├── StartCliReportingServiceTest.php │ │ └── StartWebapiReportingServiceTest.php │ ├── Model │ ├── Adapter │ │ └── ReactPHP │ │ │ ├── ClientFactoryTest.php │ │ │ └── ProcessFactoryTest.php │ ├── ChunkSizeCalculatorTest.php │ ├── Data │ │ ├── HtmlTest.php │ │ ├── ProcessTest.php │ │ └── UrlTest.php │ ├── FakeCustomerIdsProviderTest.php │ ├── Report │ │ ├── CliReportManagerTest.php │ │ └── WebapiReportManagerTest.php │ └── TimerTest.php │ └── Standalone │ ├── ChildProcess │ ├── AsynchronousProcessRunnerTest.php │ ├── HalfAsynchronousProcessRunnerTest.php │ └── SynchronousProcessRunnerTest.php │ └── Http │ ├── AsynchronousClientTest.php │ ├── HalfAsynchronousClientTest.php │ ├── SynchronousClientTest.php │ └── UrlProviderTest.php ├── composer.json ├── composer.lock ├── docs ├── magento_cli_1.png ├── magento_cli_3.png └── standalone_cli.png ├── etc ├── di.xml ├── module.xml └── webapi.xml └── registration.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | .idea 3 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | checks: 2 | php: 3 | code_rating: true 4 | duplication: true 5 | excluded_dependencies: 6 | - magento/framework 7 | - magento/module-catalog-inventory 8 | - magento/module-cron 9 | - magento/module-integration 10 | - magento/module-rss 11 | - magento/module-theme 12 | - magento/module-customer 13 | - magento/module-gift-message 14 | - magento/module-page-cache 15 | - magento/module-sales-sequence 16 | - magento/module-user 17 | - magento/module-authorization 18 | - magento/module-developer 19 | - magento/module-grouped-product 20 | - magento/module-quote 21 | - magento/module-security 22 | - magento/module-wishlist 23 | - magento/module-catalog-import-export 24 | - magento/module-directory 25 | - magento/module-indexer 26 | - magento/module-require-js 27 | - magento/module-shipping 28 | - magento/module-cms 29 | - magento/module-backend 30 | - magento/module-catalog 31 | - magento/module-media-storage 32 | - magento/module-store 33 | - magento/module-backup 34 | - magento/module-cms-url-rewrite 35 | - magento/module-reports 36 | - magento/module-translation 37 | - magento/module-bundle 38 | - magento/module-downloadable 39 | - magento/module-sales 40 | - magento/module-ui 41 | - magento/module-checkout 42 | - magento/module-product-alert 43 | - magento/module-variable 44 | - magento/module-eav 45 | - magento/module-contact 46 | - magento/module-newsletter 47 | - magento/module-sales-rule 48 | - magento/module-deploy 49 | - magento/module-payment 50 | - magento/module-url-rewrite 51 | 52 | filter: 53 | excluded_paths: 54 | - "Test/" 55 | 56 | build: 57 | dependencies: 58 | before: 59 | - 'echo "{\"http-basic\":{\"repo.magento.com\":{\"username\":\"${MAGENTO_USERNAME}\",\"password\":\"${MAGENTO_PASSWORD}\"}}}" > auth.json' -------------------------------------------------------------------------------- /Api/ChunkSizeCalculatorInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Api; 12 | 13 | /** 14 | * Interface ChunkSizeCalculatorInterface 15 | * @package MSlwk\ReactPhpPlayground\Api 16 | */ 17 | interface ChunkSizeCalculatorInterface 18 | { 19 | /** 20 | * @param array $elements 21 | * @param int $numberOfParts 22 | * @return int 23 | */ 24 | public function calculateChunkSize(array $elements, int $numberOfParts): int; 25 | } 26 | -------------------------------------------------------------------------------- /Api/CustomerIdsProviderInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Api; 12 | 13 | /** 14 | * Interface CustomerIdsProviderInterface 15 | * @package MSlwk\ReactPhpPlayground\Api 16 | */ 17 | interface CustomerIdsProviderInterface 18 | { 19 | /** 20 | * @return int[] 21 | */ 22 | public function getCustomerIds(): array; 23 | } 24 | -------------------------------------------------------------------------------- /Api/Data/HtmlInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Api\Data; 12 | 13 | /** 14 | * Interface HtmlInterface 15 | * @package MSlwk\ReactPhpPlayground\Api\Data 16 | */ 17 | interface HtmlInterface 18 | { 19 | /** 20 | * @return string 21 | */ 22 | public function getHtml(): string; 23 | } 24 | -------------------------------------------------------------------------------- /Api/Data/ProcessInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Api\Data; 12 | 13 | /** 14 | * Interface ProcessInterface 15 | * @package MSlwk\ReactPhpPlayground\Api\Data 16 | */ 17 | interface ProcessInterface 18 | { 19 | /** 20 | * @return string 21 | */ 22 | public function getCommand(): string; 23 | } 24 | -------------------------------------------------------------------------------- /Api/Data/UrlInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Api\Data; 12 | 13 | /** 14 | * Interface UrlInterface 15 | * @package MSlwk\ReactPhpPlayground\Api\Data 16 | */ 17 | interface UrlInterface 18 | { 19 | /** 20 | * @return string 21 | */ 22 | public function getUrl(): string; 23 | } 24 | -------------------------------------------------------------------------------- /Api/Report/CliReportManagerInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Api\Report; 12 | 13 | /** 14 | * Interface CliReportManagerInterface 15 | * @package MSlwk\ReactPhpPlayground\Api\Report 16 | */ 17 | interface CliReportManagerInterface 18 | { 19 | /** 20 | * @param int[] $customerIds 21 | * @return void 22 | */ 23 | public function generateAndSendReportForCustomers(array $customerIds): void; 24 | } 25 | -------------------------------------------------------------------------------- /Api/Report/ReportGeneratorInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Api\Report; 12 | 13 | /** 14 | * Interface ReportGeneratorInterface 15 | * @package MSlwk\ReactPhpPlayground\Api\Report 16 | */ 17 | interface ReportGeneratorInterface 18 | { 19 | /** 20 | * @param int $customerId 21 | * @return string 22 | */ 23 | public function generateReport(int $customerId): string; 24 | } 25 | -------------------------------------------------------------------------------- /Api/Report/ReportSenderInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Api\Report; 12 | 13 | /** 14 | * Interface ReportSenderInterface 15 | * @package MSlwk\ReactPhpPlayground\Api\Report 16 | */ 17 | interface ReportSenderInterface 18 | { 19 | /** 20 | * @param string $report 21 | * @return void 22 | */ 23 | public function sendReport(string $report): void; 24 | } 25 | -------------------------------------------------------------------------------- /Api/Report/WebapiReportManagerInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Api\Report; 12 | 13 | /** 14 | * Interface WebapiReportManagerInterface 15 | * @package MSlwk\ReactPhpPlayground\Api\Report 16 | */ 17 | interface WebapiReportManagerInterface 18 | { 19 | /** 20 | * @param int[] $customerIds 21 | * @return string[] 22 | */ 23 | public function generateAndSendReportForCustomers(array $customerIds): array; 24 | } 25 | -------------------------------------------------------------------------------- /Api/TimerInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Api; 12 | 13 | use MSlwk\ReactPhpPlayground\Exception\TimerException; 14 | 15 | /** 16 | * Interface TimerInterface 17 | * @package MSlwk\ReactPhpPlayground\Api 18 | */ 19 | interface TimerInterface 20 | { 21 | /** 22 | * @return void 23 | */ 24 | public function startTimer(): void; 25 | 26 | /** 27 | * @return void 28 | * @throws TimerException 29 | */ 30 | public function stopTimer(): void; 31 | 32 | /** 33 | * @return float 34 | * @throws TimerException 35 | */ 36 | public function getExecutionTimeInSeconds(): float; 37 | } 38 | -------------------------------------------------------------------------------- /Console/Command/GenerateReports.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Console\Command; 12 | 13 | use Magento\Framework\Serialize\Serializer\Json; 14 | use MSlwk\ReactPhpPlayground\Api\Report\CliReportManagerInterface; 15 | use Symfony\Component\Console\Command\Command; 16 | use Symfony\Component\Console\Input\InputArgument; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | 20 | /** 21 | * Class GenerateReports 22 | * @package MSlwk\ReactPhpPlayground\Console\Command 23 | */ 24 | class GenerateReports extends Command 25 | { 26 | const COMMAND_NAME = 'mslwk:generate-reports'; 27 | const COMMAND_DESCRIPTION = 'Generate reports for customers with IDs supplied'; 28 | const ARGUMENT_CUSTOMER_IDS = 'customer-ids'; 29 | 30 | /** 31 | * @var Json 32 | */ 33 | private $jsonHandler; 34 | 35 | /** 36 | * @var CliReportManagerInterface 37 | */ 38 | private $reportManager; 39 | 40 | /** 41 | * GenerateReports constructor. 42 | * @param Json $jsonHandler 43 | * @param CliReportManagerInterface $reportManager 44 | * @param null $name 45 | */ 46 | public function __construct( 47 | Json $jsonHandler, 48 | CliReportManagerInterface $reportManager, 49 | $name = null 50 | ) { 51 | parent::__construct($name); 52 | $this->jsonHandler = $jsonHandler; 53 | $this->reportManager = $reportManager; 54 | } 55 | 56 | /** 57 | * {@inheritdoc} 58 | */ 59 | protected function configure() 60 | { 61 | $this->setName(self::COMMAND_NAME) 62 | ->setDescription(self::COMMAND_DESCRIPTION) 63 | ->addArgument( 64 | self::ARGUMENT_CUSTOMER_IDS, 65 | InputArgument::REQUIRED 66 | ); 67 | } 68 | 69 | /** 70 | * @param InputInterface $input 71 | * @param OutputInterface $output 72 | * @return void 73 | */ 74 | protected function execute(InputInterface $input, OutputInterface $output) 75 | { 76 | $customerIds = $this->jsonHandler->unserialize($input->getArgument(self::ARGUMENT_CUSTOMER_IDS)); 77 | $this->reportManager->generateAndSendReportForCustomers($customerIds); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Console/Command/StartCliReportingService.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Console\Command; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\ChunkSizeCalculatorInterface; 14 | use MSlwk\ReactPhpPlayground\Api\CustomerIdsProviderInterface; 15 | use MSlwk\ReactPhpPlayground\Api\TimerInterface; 16 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ProcessFactory; 17 | use Symfony\Component\Console\Command\Command; 18 | use Symfony\Component\Console\Input\InputArgument; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | use Magento\Framework\Serialize\Serializer\Json; 22 | use React\EventLoop\Factory; 23 | 24 | /** 25 | * Class StartCliReportingService 26 | * @package MSlwk\ReactPhpPlayground\Console\Command 27 | */ 28 | class StartCliReportingService extends Command 29 | { 30 | const COMMAND_NAME = 'mslwk:cli-reporting-start'; 31 | const COMMAND_DESCRIPTION = 'Start asynchronous CLI reporting service'; 32 | const ARGUMENT_NUMBER_OF_THREADS = 'threads'; 33 | 34 | /** 35 | * @var TimerInterface 36 | */ 37 | private $timer; 38 | 39 | /** 40 | * @var CustomerIdsProviderInterface 41 | */ 42 | private $customerIdsProvider; 43 | 44 | /** 45 | * @var LoopInterface 46 | */ 47 | private $loop; 48 | 49 | /** 50 | * @var ProcessFactory 51 | */ 52 | private $processFactory; 53 | 54 | /** 55 | * @var Json 56 | */ 57 | private $jsonHandler; 58 | 59 | /** 60 | * @var ChunkSizeCalculatorInterface 61 | */ 62 | private $chunkSizeCalculator; 63 | 64 | /** 65 | * StartCliReportingService constructor. 66 | * @param TimerInterface $timer 67 | * @param CustomerIdsProviderInterface $customerIdsProvider 68 | * @param Factory $loopFactory 69 | * @param ProcessFactory $processFactory 70 | * @param Json $jsonHandler 71 | * @param ChunkSizeCalculatorInterface $chunkSizeCalculator 72 | * @param null $name 73 | */ 74 | public function __construct( 75 | TimerInterface $timer, 76 | CustomerIdsProviderInterface $customerIdsProvider, 77 | Factory $loopFactory, 78 | ProcessFactory $processFactory, 79 | Json $jsonHandler, 80 | ChunkSizeCalculatorInterface $chunkSizeCalculator, 81 | $name = null 82 | ) { 83 | parent::__construct($name); 84 | $this->timer = $timer; 85 | $this->customerIdsProvider = $customerIdsProvider; 86 | $this->loop = $loopFactory::create(); 87 | $this->processFactory = $processFactory; 88 | $this->jsonHandler = $jsonHandler; 89 | $this->chunkSizeCalculator = $chunkSizeCalculator; 90 | } 91 | 92 | /** 93 | * {@inheritdoc} 94 | */ 95 | protected function configure() 96 | { 97 | $this->setName(self::COMMAND_NAME) 98 | ->setDescription(self::COMMAND_DESCRIPTION) 99 | ->addArgument( 100 | self::ARGUMENT_NUMBER_OF_THREADS, 101 | InputArgument::REQUIRED, 102 | 'Number of threads for running the export process' 103 | ); 104 | } 105 | 106 | /** 107 | * @param InputInterface $input 108 | * @param OutputInterface $output 109 | * @return void 110 | */ 111 | protected function execute(InputInterface $input, OutputInterface $output) 112 | { 113 | $numberOfThreads = (int)$input->getArgument(self::ARGUMENT_NUMBER_OF_THREADS); 114 | $customerIds = $this->customerIdsProvider->getCustomerIds(); 115 | 116 | $this->timer->startTimer(); 117 | 118 | $this->startProcesses($customerIds, $numberOfThreads); 119 | 120 | $this->timer->stopTimer(); 121 | 122 | $output->writeln("Process finished after {$this->timer->getExecutionTimeInSeconds()} seconds"); 123 | } 124 | 125 | /** 126 | * @param int[] $customerIds 127 | * @param int $numberOfThreads 128 | */ 129 | protected function startProcesses(array $customerIds, int $numberOfThreads): void 130 | { 131 | $chunkSize = $this->chunkSizeCalculator->calculateChunkSize($customerIds, $numberOfThreads); 132 | $threadedCustomerIds = array_chunk($customerIds, $chunkSize); 133 | foreach ($threadedCustomerIds as $customerIdsForSingleThread) { 134 | $this->createProcessDefinition($this->getFullCommand($customerIdsForSingleThread)); 135 | } 136 | $this->loop->run(); 137 | } 138 | 139 | /** 140 | * @param string $command 141 | */ 142 | protected function createProcessDefinition(string $command): void 143 | { 144 | $reactProcess = $this->processFactory->create($command); 145 | $reactProcess->start($this->loop); 146 | 147 | $reactProcess->stdout->on('data', function ($chunk) { 148 | echo $chunk; 149 | }); 150 | } 151 | 152 | /** 153 | * @param int[] $customerIds 154 | * @return string 155 | */ 156 | protected function getFullCommand(array $customerIds): string 157 | { 158 | return sprintf( 159 | ' %s/bin/magento %s %s', 160 | BP, 161 | GenerateReports::COMMAND_NAME, 162 | $this->jsonHandler->serialize($customerIds) 163 | ); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /Console/Command/StartWebapiReportingService.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Console\Command; 12 | 13 | use Magento\Framework\Serialize\Serializer\Json; 14 | use Magento\Store\Model\StoreManagerInterface; 15 | use MSlwk\ReactPhpPlayground\Api\ChunkSizeCalculatorInterface; 16 | use MSlwk\ReactPhpPlayground\Api\CustomerIdsProviderInterface; 17 | use MSlwk\ReactPhpPlayground\Api\TimerInterface; 18 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ClientFactory; 19 | use React\EventLoop\Factory; 20 | use React\EventLoop\LoopInterface; 21 | use Symfony\Component\Console\Command\Command; 22 | use Symfony\Component\Console\Input\InputArgument; 23 | use Symfony\Component\Console\Input\InputInterface; 24 | use Symfony\Component\Console\Output\OutputInterface; 25 | use React\HttpClient\Response; 26 | 27 | /** 28 | * Class StartWebapiReportingService 29 | * @package MSlwk\ReactPhpPlayground\Console\Command 30 | */ 31 | class StartWebapiReportingService extends Command 32 | { 33 | const COMMAND_NAME = 'mslwk:webapi-reporting-start'; 34 | const COMMAND_DESCRIPTION = 'Start asynchronous WebAPI reporting service'; 35 | const ARGUMENT_NUMBER_OF_THREADS = 'threads'; 36 | 37 | const API_ENDPOINT_PATH = 'rest/V1/mslwk/customer-report/generate'; 38 | 39 | /** 40 | * @var TimerInterface 41 | */ 42 | private $timer; 43 | 44 | /** 45 | * @var CustomerIdsProviderInterface 46 | */ 47 | private $customerIdsProvider; 48 | 49 | /** 50 | * @var LoopInterface 51 | */ 52 | private $loop; 53 | 54 | /** 55 | * @var ClientFactory 56 | */ 57 | private $clientFactory; 58 | 59 | /** 60 | * @var Json 61 | */ 62 | private $jsonHandler; 63 | 64 | /** 65 | * @var StoreManagerInterface 66 | */ 67 | private $storeManager; 68 | 69 | /** 70 | * @var ChunkSizeCalculatorInterface 71 | */ 72 | private $chunkSizeCalculator; 73 | 74 | /** 75 | * StartWebapiReportingService constructor. 76 | * @param TimerInterface $timer 77 | * @param CustomerIdsProviderInterface $customerIdsProvider 78 | * @param Factory $loopFactory 79 | * @param ClientFactory $clientFactory 80 | * @param Json $jsonHandler 81 | * @param StoreManagerInterface $storeManager 82 | * @param ChunkSizeCalculatorInterface $chunkSizeCalculator 83 | * @param null $name 84 | */ 85 | public function __construct( 86 | TimerInterface $timer, 87 | CustomerIdsProviderInterface $customerIdsProvider, 88 | Factory $loopFactory, 89 | ClientFactory $clientFactory, 90 | Json $jsonHandler, 91 | StoreManagerInterface $storeManager, 92 | ChunkSizeCalculatorInterface $chunkSizeCalculator, 93 | $name = null 94 | ) { 95 | parent::__construct($name); 96 | $this->timer = $timer; 97 | $this->customerIdsProvider = $customerIdsProvider; 98 | $this->loop = $loopFactory::create(); 99 | $this->clientFactory = $clientFactory; 100 | $this->jsonHandler = $jsonHandler; 101 | $this->storeManager = $storeManager; 102 | $this->chunkSizeCalculator = $chunkSizeCalculator; 103 | } 104 | 105 | /** 106 | * {@inheritdoc} 107 | */ 108 | protected function configure() 109 | { 110 | $this->setName(self::COMMAND_NAME) 111 | ->setDescription(self::COMMAND_DESCRIPTION) 112 | ->addArgument( 113 | self::ARGUMENT_NUMBER_OF_THREADS, 114 | InputArgument::REQUIRED, 115 | 'Number of threads for running the export process' 116 | ); 117 | } 118 | 119 | /** 120 | * @param InputInterface $input 121 | * @param OutputInterface $output 122 | * @return void 123 | */ 124 | protected function execute(InputInterface $input, OutputInterface $output) 125 | { 126 | $customerIds = $this->customerIdsProvider->getCustomerIds(); 127 | $numberOfThreads = (int)$input->getArgument(self::ARGUMENT_NUMBER_OF_THREADS); 128 | 129 | $this->timer->startTimer(); 130 | 131 | $this->startProcesses($customerIds, $numberOfThreads); 132 | 133 | $this->timer->stopTimer(); 134 | 135 | $output->writeln("Process finished after {$this->timer->getExecutionTimeInSeconds()} seconds"); 136 | } 137 | 138 | /** 139 | * @param array $customerIds 140 | * @param int $numberOfThreads 141 | */ 142 | protected function startProcesses(array $customerIds, int $numberOfThreads): void 143 | { 144 | $chunkSize = $this->chunkSizeCalculator->calculateChunkSize($customerIds, $numberOfThreads); 145 | $threadedCustomerIds = array_chunk($customerIds, $chunkSize); 146 | foreach ($threadedCustomerIds as $customerIdsForSingleThread) { 147 | $this->createRequestDefinition($customerIdsForSingleThread); 148 | } 149 | $this->loop->run(); 150 | } 151 | 152 | /** 153 | * @param int[] $customerIds 154 | */ 155 | protected function createRequestDefinition(array $customerIds): void 156 | { 157 | $client = $this->clientFactory->create($this->loop); 158 | $data = $this->jsonHandler->serialize(['customerIds' => $customerIds]); 159 | $request = $client->request( 160 | 'POST', 161 | $this->getRequestUrl(), 162 | [ 163 | 'Content-Type' => 'application/json', 164 | 'Content-Length' => strlen($data) 165 | ] 166 | ); 167 | $request->write($data); 168 | $request->on('response', function (Response $response) use (&$htmlObjectArray) { 169 | $data = ''; 170 | $response->on( 171 | 'data', 172 | function ($chunk) use (&$data) { 173 | $data .= $chunk; 174 | } 175 | )->on( 176 | 'end', 177 | function () use (&$data) { 178 | foreach ($this->jsonHandler->unserialize($data) as $message) { 179 | echo $message; 180 | } 181 | } 182 | ); 183 | }); 184 | $request->end(); 185 | } 186 | 187 | /** 188 | * @return string 189 | */ 190 | protected function getRequestUrl(): string 191 | { 192 | return $this->storeManager->getStore()->getBaseUrl() . self::API_ENDPOINT_PATH; 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /Exception/TimerException.php: -------------------------------------------------------------------------------- 1 | 6 | * Github: https://github.com/maciejslawik 7 | */ 8 | 9 | namespace MSlwk\ReactPhpPlayground\Exception; 10 | 11 | use Exception; 12 | 13 | /** 14 | * Class TimerException 15 | * @package MSlwk\ReactPhpPlayground\Exception 16 | */ 17 | class TimerException extends Exception 18 | { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Maciej Sławik 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /Model/Adapter/ReactPHP/ClientFactory.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP; 12 | 13 | use React\EventLoop\LoopInterface; 14 | use React\HttpClient\Client; 15 | 16 | /** 17 | * Class ClientFactory 18 | * @package MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP 19 | */ 20 | class ClientFactory 21 | { 22 | /** 23 | * @param LoopInterface $loop 24 | * @return Client 25 | */ 26 | public function create(LoopInterface $loop): Client 27 | { 28 | return new Client($loop); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Model/Adapter/ReactPHP/ProcessFactory.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP; 12 | 13 | use React\ChildProcess\Process; 14 | 15 | /** 16 | * Class ProcessFactory 17 | * @package MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP 18 | */ 19 | class ProcessFactory 20 | { 21 | /** 22 | * @param string $command 23 | * @return Process 24 | */ 25 | public function create(string $command): Process 26 | { 27 | return new Process($command); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Model/ChunkSizeCalculator.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Model; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\ChunkSizeCalculatorInterface; 14 | 15 | /** 16 | * Class ChunkSizeCalculator 17 | * @package MSlwk\ReactPhpPlayground\Model 18 | */ 19 | class ChunkSizeCalculator implements ChunkSizeCalculatorInterface 20 | { 21 | /** 22 | * @param array $elements 23 | * @param int $numberOfParts 24 | * @return int 25 | */ 26 | public function calculateChunkSize(array $elements, int $numberOfParts): int 27 | { 28 | $numberOfChunks = (int)ceil(count($elements) / $numberOfParts); 29 | return $numberOfChunks > 0 ? $numberOfChunks : 1; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Model/Data/Html.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Model\Data; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\HtmlInterface; 14 | 15 | /** 16 | * Class Html 17 | * @package MSlwk\ReactPhpPlayground\Model\Data 18 | */ 19 | class Html implements HtmlInterface 20 | { 21 | /** 22 | * @var string 23 | */ 24 | private $html; 25 | 26 | /** 27 | * Html constructor. 28 | * @param string $html 29 | */ 30 | public function __construct(string $html) 31 | { 32 | $this->html = $html; 33 | } 34 | 35 | /** 36 | * @return string 37 | */ 38 | public function getHtml(): string 39 | { 40 | return $this->html; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Model/Data/Process.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | 12 | namespace MSlwk\ReactPhpPlayground\Model\Data; 13 | 14 | use MSlwk\ReactPhpPlayground\Api\Data\ProcessInterface; 15 | 16 | /** 17 | * Class Process 18 | * @package MSlwk\ReactPhpPlayground\Model\Data 19 | */ 20 | class Process implements ProcessInterface 21 | { 22 | /** 23 | * @var string 24 | */ 25 | private $command; 26 | 27 | /** 28 | * Process constructor. 29 | * @param string $command 30 | */ 31 | public function __construct(string $command) 32 | { 33 | $this->command = $command; 34 | } 35 | 36 | /** 37 | * @return string 38 | */ 39 | public function getCommand(): string 40 | { 41 | return $this->command; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Model/Data/Url.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Model\Data; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\UrlInterface; 14 | 15 | /** 16 | * Class Url 17 | * @package MSlwk\ReactPhpPlayground\Model\Data 18 | */ 19 | class Url implements UrlInterface 20 | { 21 | /** 22 | * @var string 23 | */ 24 | private $url; 25 | 26 | /** 27 | * Url constructor. 28 | * @param string $url 29 | */ 30 | public function __construct(string $url) 31 | { 32 | $this->url = $url; 33 | } 34 | 35 | /** 36 | * @return string 37 | */ 38 | public function getUrl(): string 39 | { 40 | return $this->url; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Model/FakeCustomerIdsProvider.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Model; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\CustomerIdsProviderInterface; 14 | 15 | /** 16 | * Class FakeCustomerIdsProvider 17 | * @package MSlwk\ReactPhpPlayground\Model 18 | */ 19 | class FakeCustomerIdsProvider implements CustomerIdsProviderInterface 20 | { 21 | /** 22 | * @return int[] 23 | */ 24 | public function getCustomerIds(): array 25 | { 26 | return [ 27 | 1, 28 | 2, 29 | 3, 30 | 4, 31 | 5, 32 | 6, 33 | 7, 34 | 8 35 | ]; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Model/Report/CliReportManager.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Model\Report; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Report\ReportGeneratorInterface; 14 | use MSlwk\ReactPhpPlayground\Api\Report\CliReportManagerInterface; 15 | use MSlwk\ReactPhpPlayground\Api\Report\ReportSenderInterface; 16 | 17 | /** 18 | * Class CliReportManager 19 | * @package MSlwk\ReactPhpPlayground\Model\Report 20 | */ 21 | class CliReportManager implements CliReportManagerInterface 22 | { 23 | /** 24 | * @var ReportGeneratorInterface 25 | */ 26 | private $reportGenerator; 27 | 28 | /** 29 | * @var ReportSenderInterface 30 | */ 31 | private $reportSender; 32 | 33 | /** 34 | * CliReportManager constructor. 35 | * @param ReportGeneratorInterface $reportGenerator 36 | * @param ReportSenderInterface $reportSender 37 | */ 38 | public function __construct( 39 | ReportGeneratorInterface $reportGenerator, 40 | ReportSenderInterface $reportSender 41 | ) { 42 | $this->reportGenerator = $reportGenerator; 43 | $this->reportSender = $reportSender; 44 | } 45 | 46 | /** 47 | * @param int[] $customerIds 48 | * @return void 49 | */ 50 | public function generateAndSendReportForCustomers(array $customerIds): void 51 | { 52 | foreach ($customerIds as $customerId) { 53 | $report = $this->reportGenerator->generateReport($customerId); 54 | $this->reportSender->sendReport($report); 55 | echo "Reporting process finished for customer: {$customerId}\n"; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Model/Report/ReportGenerator.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Model\Report; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Report\ReportGeneratorInterface; 14 | 15 | /** 16 | * Class ReportGenerator 17 | * @package MSlwk\ReactPhpPlayground\Model\Report 18 | */ 19 | class ReportGenerator implements ReportGeneratorInterface 20 | { 21 | /** 22 | * @param int $customerId 23 | * @return string 24 | * @codeCoverageIgnore 25 | */ 26 | public function generateReport(int $customerId): string 27 | { 28 | /** 29 | * Report is being generated 30 | */ 31 | $loopSize = 31500; 32 | 33 | $primes = []; 34 | 35 | for ($i = 2; $i < $loopSize; $i++) { 36 | for ($j = 2; $j < $i; $j++) { 37 | if ($i % $j == 0) { 38 | break; 39 | } 40 | } 41 | if ($i === $j) { 42 | $primes[] = $i; 43 | } 44 | } 45 | 46 | return ''; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Model/Report/ReportSender.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Model\Report; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Report\ReportSenderInterface; 14 | 15 | /** 16 | * Class ReportSender 17 | * @package MSlwk\ReactPhpPlayground\Model\Report 18 | */ 19 | class ReportSender implements ReportSenderInterface 20 | { 21 | /** 22 | * @param string $report 23 | * @return void 24 | * @codeCoverageIgnore 25 | */ 26 | public function sendReport(string $report): void 27 | { 28 | /** 29 | * Report is being sent, waiting for 3rd-party service 30 | */ 31 | sleep(1); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Model/Report/WebapiReportManager.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Model\Report; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Report\ReportGeneratorInterface; 14 | use MSlwk\ReactPhpPlayground\Api\Report\WebapiReportManagerInterface; 15 | use MSlwk\ReactPhpPlayground\Api\Report\ReportSenderInterface; 16 | 17 | /** 18 | * Class WebapiReportManager 19 | * @package MSlwk\ReactPhpPlayground\Model\Report 20 | */ 21 | class WebapiReportManager implements WebapiReportManagerInterface 22 | { 23 | /** 24 | * @var ReportGeneratorInterface 25 | */ 26 | private $reportGenerator; 27 | 28 | /** 29 | * @var ReportSenderInterface 30 | */ 31 | private $reportSender; 32 | 33 | /** 34 | * WebapiReportManager constructor. 35 | * @param ReportGeneratorInterface $reportGenerator 36 | * @param ReportSenderInterface $reportSender 37 | */ 38 | public function __construct( 39 | ReportGeneratorInterface $reportGenerator, 40 | ReportSenderInterface $reportSender 41 | ) { 42 | $this->reportGenerator = $reportGenerator; 43 | $this->reportSender = $reportSender; 44 | } 45 | 46 | /** 47 | * @param int[] $customerIds 48 | * @return string[] 49 | */ 50 | public function generateAndSendReportForCustomers(array $customerIds): array 51 | { 52 | $messages = []; 53 | foreach ($customerIds as $customerId) { 54 | $report = $this->reportGenerator->generateReport($customerId); 55 | $this->reportSender->sendReport($report); 56 | $messages[] = "Reporting process finished for customer: {$customerId}\n"; 57 | } 58 | return $messages; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Model/Timer.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Model; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\TimerInterface; 14 | use MSlwk\ReactPhpPlayground\Exception\TimerException; 15 | 16 | /** 17 | * Class Timer 18 | * @package MSlwk\ReactPhpPlayground\Model 19 | */ 20 | class Timer implements TimerInterface 21 | { 22 | /** 23 | * @var float 24 | */ 25 | private $timeStart = 0.0; 26 | 27 | /** 28 | * @var float 29 | */ 30 | private $timeStop = 0.0; 31 | 32 | /** 33 | * @return void 34 | */ 35 | public function startTimer(): void 36 | { 37 | $this->timeStart = microtime(true); 38 | } 39 | 40 | /** 41 | * @return void 42 | * @throws TimerException 43 | */ 44 | public function stopTimer(): void 45 | { 46 | if (!$this->timeStart) { 47 | throw new TimerException('Timer not started'); 48 | } 49 | $this->timeStop = microtime(true); 50 | } 51 | 52 | /** 53 | * @return float 54 | * @throws TimerException 55 | */ 56 | public function getExecutionTimeInSeconds(): float 57 | { 58 | if (!$this->timeStart || !$this->timeStop) { 59 | throw new TimerException('Execution time cannot be calculated'); 60 | } 61 | $executionTime = $this->timeStop - $this->timeStart; 62 | $this->timeStart = 0.0; 63 | $this->timeStop = 0.0; 64 | return $executionTime; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://scrutinizer-ci.com/g/maciejslawik/reactphp-playground-magento2/badges/build.png?b=master)](https://scrutinizer-ci.com/g/maciejslawik/reactphp-playground-magento2/build-status/master) 2 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/maciejslawik/reactphp-playground-magento2/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/maciejslawik/reactphp-playground-magento2/?branch=master) 3 | [![Latest Stable Version](https://poser.pugx.org/mslwk/module-reactphp-playground/v/stable)](https://packagist.org/packages/mslwk/module-reactphp-playground) 4 | [![License](https://poser.pugx.org/mslwk/module-reactphp-playground/license)](https://packagist.org/packages/mslwk/module-reactphp-playground) 5 | [![Total Downloads](https://poser.pugx.org/mslwk/module-reactphp-playground/downloads)](https://packagist.org/packages/mslwk/module-reactphp-playground) 6 | 7 | # Magento 2 ReactPHP Playground # 8 | 9 | Magento 2 module which showcases how to run resource-heavy processes asynchronously using 10 | multiple threads with ReactPHP ChildProcess and HttpClient libraries. 11 | 12 | ## Prerequisites ## 13 | 14 | * Magento 2.2 or higher 15 | * PHP 7.1 16 | 17 | ## Installing ## 18 | 19 | You can install the module by downloading a .zip file and unpacking it inside 20 | ``app/code/MSlwk/ReactPhpPlayground`` directory inside your Magento 21 | or via Composer (recommended). 22 | 23 | To install the module via Composer simply run 24 | ``` 25 | composer require mslwk/module-reactphp-playground 26 | ``` 27 | 28 | Than enable the module by running these command in the root of your Magento installation 29 | ``` 30 | bin/magento module:enable MSlwk_ReactPhpPlayground 31 | bin/magento setup:upgrade 32 | ``` 33 | 34 | ## Usage ## 35 | 36 | #### Non-Magento scripts #### 37 | 38 | The module contains PHP CLI scripts which don't require Magento. They present the potential differences 39 | between the same calculations run on 1, 2 and 4 threads. 40 | 41 | * To run HttpClient example start the ``Standalone/bin/http`` script 42 | * To run ChildProcess example start the ``Standalone/bin/childprocess`` script 43 | 44 | #### Magento commands #### 45 | 46 | The module contains 2 commands available via ``bin/magento``. You can choose the number of threads to use. 47 | 48 | * To run HttpClient example use 49 | ``` 50 | bin/magento mslwk:webapi-reporting-start <> 51 | ``` 52 | 53 | * To run ChildProcess example use 54 | ``` 55 | bin/magento mslwk:cli-reporting-start <> 56 | ``` 57 | 58 | ## Authors 59 | 60 | * **Maciej Sławik** - https://github.com/maciejslawik 61 | 62 | ## License 63 | 64 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details 65 | 66 | ## Screenshots 67 | 68 | ![Alt text](docs/standalone_cli.png?raw=true "Standalone script using ChildProcess run on 1, 2 and 4 threads") 69 | 70 | ![Alt text](docs/magento_cli_1.png?raw=true "Magento script using ChildProcess run on 1 thread") 71 | 72 | ![Alt text](docs/magento_cli_3.png?raw=true "Magento script using ChildProcess run on 3 threads") -------------------------------------------------------------------------------- /Standalone/ChildProcess/AsynchronousProcessRunner.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Standalone\ChildProcess; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\ProcessInterface; 14 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ProcessFactory; 15 | use MSlwk\TypeSafeArray\ObjectArray; 16 | use React\EventLoop\LoopInterface; 17 | 18 | /** 19 | * Class AsynchronousProcessRunner 20 | * @package MSlwk\ReactPhpPlayground\Standalone\ChildProcess 21 | */ 22 | class AsynchronousProcessRunner implements ProcessRunnerInterface 23 | { 24 | /** 25 | * @var LoopInterface 26 | */ 27 | private $loop; 28 | 29 | /** 30 | * @var ProcessFactory 31 | */ 32 | private $processFactory; 33 | 34 | /** 35 | * AsynchronousProcessRunner constructor. 36 | * @param LoopInterface $loop 37 | * @param ProcessFactory $processFactory 38 | */ 39 | public function __construct( 40 | LoopInterface $loop, 41 | ProcessFactory $processFactory 42 | ) { 43 | $this->loop = $loop; 44 | $this->processFactory = $processFactory; 45 | } 46 | 47 | /** 48 | * @param ObjectArray $processes 49 | * @return void 50 | */ 51 | public function runProcesses(ObjectArray $processes): void 52 | { 53 | /** @var ProcessInterface $process */ 54 | foreach ($processes as $process) { 55 | $this->createProcessDefinition($process); 56 | } 57 | $this->loop->run(); 58 | } 59 | 60 | /** 61 | * @codeCoverageIgnore 62 | * @param ProcessInterface $process 63 | * @return void 64 | */ 65 | protected function createProcessDefinition(ProcessInterface $process): void 66 | { 67 | $reactProcess = $this->processFactory->create($process->getCommand()); 68 | $reactProcess->start($this->loop); 69 | 70 | $reactProcess->stdout->on('data', function ($chunk) { 71 | echo $chunk; 72 | }); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Standalone/ChildProcess/HalfAsynchronousProcessRunner.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl) 9 | */ 10 | 11 | 12 | namespace MSlwk\ReactPhpPlayground\Standalone\ChildProcess; 13 | 14 | use MSlwk\ReactPhpPlayground\Api\Data\ProcessInterface; 15 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ProcessFactory; 16 | use MSlwk\TypeSafeArray\ObjectArray; 17 | use React\EventLoop\LoopInterface; 18 | 19 | /** 20 | * Class HalfAsynchronousProcessRunner 21 | * @package MSlwk\ReactPhpPlayground\Standalone\ChildProcess 22 | */ 23 | class HalfAsynchronousProcessRunner implements ProcessRunnerInterface 24 | { 25 | /** 26 | * @var LoopInterface 27 | */ 28 | private $loop; 29 | 30 | /** 31 | * @var ProcessFactory 32 | */ 33 | private $processFactory; 34 | 35 | /** 36 | * AsynchronousProcessRunner constructor. 37 | * @param LoopInterface $loop 38 | * @param ProcessFactory $processFactory 39 | */ 40 | public function __construct( 41 | LoopInterface $loop, 42 | ProcessFactory $processFactory 43 | ) { 44 | $this->loop = $loop; 45 | $this->processFactory = $processFactory; 46 | } 47 | 48 | /** 49 | * @param ObjectArray $processes 50 | * @return void 51 | */ 52 | public function runProcesses(ObjectArray $processes): void 53 | { 54 | for ($i = 0; $i < ($processes->count() / 2); $i++) { 55 | $this->createProcessDefinition($processes->offsetGet($i)); 56 | } 57 | $this->loop->run(); 58 | 59 | for ($i; $i < ($processes->count()); $i++) { 60 | $this->createProcessDefinition($processes->offsetGet($i)); 61 | } 62 | $this->loop->run(); 63 | } 64 | 65 | /** 66 | * @codeCoverageIgnore 67 | * @param ProcessInterface $process 68 | * @return void 69 | */ 70 | protected function createProcessDefinition(ProcessInterface $process): void 71 | { 72 | $reactProcess = $this->processFactory->create($process->getCommand()); 73 | $reactProcess->start($this->loop); 74 | 75 | $reactProcess->stdout->on('data', function ($chunk) { 76 | echo $chunk; 77 | }); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Standalone/ChildProcess/ProcessRunnerInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Standalone\ChildProcess; 12 | 13 | use MSlwk\TypeSafeArray\ObjectArray; 14 | 15 | /** 16 | * Interface ProcessRunnerInterface 17 | * @package MSlwk\ReactPhpPlayground\Standalone\ChildProcess 18 | */ 19 | interface ProcessRunnerInterface 20 | { 21 | /** 22 | * @param ObjectArray $processes 23 | * @return void 24 | */ 25 | public function runProcesses(ObjectArray $processes): void; 26 | } 27 | -------------------------------------------------------------------------------- /Standalone/ChildProcess/SynchronousProcessRunner.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Standalone\ChildProcess; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\ProcessInterface; 14 | use MSlwk\TypeSafeArray\ObjectArray; 15 | 16 | /** 17 | * Class SynchronousProcessRunner 18 | * @package MSlwk\ReactPhpPlayground\Standalone\ChildProcess 19 | */ 20 | class SynchronousProcessRunner implements ProcessRunnerInterface 21 | { 22 | /** 23 | * @param ObjectArray $processes 24 | * @return void 25 | */ 26 | public function runProcesses(ObjectArray $processes): void 27 | { 28 | /** @var ProcessInterface $process */ 29 | foreach ($processes as $process) { 30 | $output = $this->execWrapper($process->getCommand()); 31 | echo $output . PHP_EOL; 32 | } 33 | } 34 | 35 | /** 36 | * @codeCoverageIgnore 37 | * @param string $command 38 | * @return string 39 | */ 40 | protected function execWrapper(string $command): string 41 | { 42 | return exec($command); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Standalone/ChildProcess/processes/pi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 9 | * Github: https://github.com/maciejslawik 10 | */ 11 | 12 | 13 | $pi = 4; 14 | $top = 4; 15 | $bottom = 3; 16 | $minus = true; 17 | $accuracy = 50000000; 18 | 19 | for ($i = 0; $i < $accuracy; $i++) { 20 | $pi += ($minus ? -($top / $bottom) : ($top / $bottom)); 21 | $minus = ($minus ? false : true); 22 | $bottom += 2; 23 | } 24 | 25 | echo 'Pi ~= ' . $pi . PHP_EOL; 26 | -------------------------------------------------------------------------------- /Standalone/ChildProcess/processes/primes: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 9 | * Github: https://github.com/maciejslawik 10 | */ 11 | 12 | $loopSize = 70000; 13 | 14 | $primes = []; 15 | 16 | for ($i = 2; $i < $loopSize; $i++) { 17 | for ($j = 2; $j < $i; $j++) { 18 | if ($i % $j == 0) { 19 | break; 20 | } 21 | } 22 | if ($i === $j) { 23 | $primes[] = $i; 24 | } 25 | } 26 | 27 | echo 'Primes found: ' . count($primes) . PHP_EOL; 28 | -------------------------------------------------------------------------------- /Standalone/ChildProcess/processes/random: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 9 | * Github: https://github.com/maciejslawik 10 | */ 11 | 12 | $loopSize = 50000000; 13 | 14 | for ($i = 0; $i < $loopSize; $i++) { 15 | rand(); 16 | } 17 | 18 | echo 'Randomizer run 50000000 times' . PHP_EOL; 19 | -------------------------------------------------------------------------------- /Standalone/ChildProcess/processes/sleep: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 9 | * Github: https://github.com/maciejslawik 10 | */ 11 | 12 | sleep(3); 13 | 14 | echo 'Slept 3 seconds' . PHP_EOL; 15 | -------------------------------------------------------------------------------- /Standalone/Http/AsynchronousClient.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Standalone\Http; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\HtmlInterface; 14 | use MSlwk\ReactPhpPlayground\Api\Data\UrlInterface; 15 | use MSlwk\ReactPhpPlayground\Model\Data\Html; 16 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ClientFactory; 17 | use MSlwk\TypeSafeArray\ObjectArray; 18 | use MSlwk\TypeSafeArray\ObjectArrayFactory; 19 | use React\EventLoop\LoopInterface; 20 | use React\HttpClient\Response; 21 | 22 | /** 23 | * Class AsynchronousClient 24 | * @package MSlwk\ReactPhpPlayground\Standalone\Http 25 | */ 26 | class AsynchronousClient implements ClientInterface 27 | { 28 | /** 29 | * @var LoopInterface 30 | */ 31 | private $loop; 32 | 33 | /** 34 | * @var ClientFactory 35 | */ 36 | private $clientFactory; 37 | 38 | /** 39 | * @var ObjectArrayFactory 40 | */ 41 | private $objectArrayFactory; 42 | 43 | /** 44 | * AsynchronousClient constructor. 45 | * @param LoopInterface $loop 46 | * @param ClientFactory $clientFactory 47 | * @param ObjectArrayFactory $objectArrayFactory 48 | */ 49 | public function __construct( 50 | LoopInterface $loop, 51 | ClientFactory $clientFactory, 52 | ObjectArrayFactory $objectArrayFactory 53 | ) { 54 | $this->loop = $loop; 55 | $this->clientFactory = $clientFactory; 56 | $this->objectArrayFactory = $objectArrayFactory; 57 | } 58 | 59 | /** 60 | * @param ObjectArray $urls 61 | * @return ObjectArray 62 | */ 63 | public function getContent(ObjectArray $urls): ObjectArray 64 | { 65 | $htmlObjectArray = $this->objectArrayFactory->create(HtmlInterface::class); 66 | /** @var UrlInterface $url */ 67 | foreach ($urls as $url) { 68 | $this->createRequestDefinition($url, $htmlObjectArray); 69 | } 70 | $this->loop->run(); 71 | return $htmlObjectArray; 72 | } 73 | 74 | /** 75 | * @codeCoverageIgnore 76 | * @param UrlInterface $url 77 | * @param ObjectArray $htmlObjectArray 78 | * @return void 79 | */ 80 | private function createRequestDefinition(UrlInterface $url, ObjectArray &$htmlObjectArray): void 81 | { 82 | $client = $this->clientFactory->create($this->loop); 83 | $request = $client->request('GET', $url->getUrl()); 84 | $request->on('response', function (Response $response) use (&$htmlObjectArray) { 85 | $data = ''; 86 | $response->on( 87 | 'data', 88 | function ($chunk) use (&$data) { 89 | $data .= $chunk; 90 | } 91 | )->on( 92 | 'end', 93 | function () use (&$htmlObjectArray, &$data) { 94 | $htmlObjectArray->add(new Html($data)); 95 | } 96 | ); 97 | }); 98 | $request->end(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Standalone/Http/ClientInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Standalone\Http; 12 | 13 | use MSlwk\TypeSafeArray\ObjectArray; 14 | 15 | /** 16 | * Interface ClientInterface 17 | * @package MSlwk\ReactPhpPlayground\Standalone\Http 18 | */ 19 | interface ClientInterface 20 | { 21 | /** 22 | * @param ObjectArray $urls 23 | * @return ObjectArray 24 | */ 25 | public function getContent(ObjectArray $urls): ObjectArray; 26 | } 27 | -------------------------------------------------------------------------------- /Standalone/Http/HalfAsynchronousClient.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Standalone\Http; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\HtmlInterface; 14 | use MSlwk\ReactPhpPlayground\Api\Data\UrlInterface; 15 | use MSlwk\ReactPhpPlayground\Model\Data\Html; 16 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ClientFactory; 17 | use MSlwk\TypeSafeArray\ObjectArray; 18 | use MSlwk\TypeSafeArray\ObjectArrayFactory; 19 | use React\EventLoop\LoopInterface; 20 | use React\HttpClient\Response; 21 | 22 | /** 23 | * Class HalfAsynchronousClient 24 | * @package MSlwk\ReactPhpPlayground\Standalone\Http 25 | */ 26 | class HalfAsynchronousClient implements ClientInterface 27 | { 28 | /** 29 | * @var LoopInterface 30 | */ 31 | private $loop; 32 | 33 | /** 34 | * @var ClientFactory 35 | */ 36 | private $clientFactory; 37 | 38 | /** 39 | * @var ObjectArrayFactory 40 | */ 41 | private $objectArrayFactory; 42 | 43 | /** 44 | * HalfAsynchronousClient constructor. 45 | * @param LoopInterface $loop 46 | * @param ClientFactory $clientFactory 47 | * @param ObjectArrayFactory $objectArrayFactory 48 | */ 49 | public function __construct( 50 | LoopInterface $loop, 51 | ClientFactory $clientFactory, 52 | ObjectArrayFactory $objectArrayFactory 53 | ) { 54 | $this->loop = $loop; 55 | $this->clientFactory = $clientFactory; 56 | $this->objectArrayFactory = $objectArrayFactory; 57 | } 58 | 59 | /** 60 | * @param ObjectArray $urls 61 | * @return ObjectArray 62 | */ 63 | public function getContent(ObjectArray $urls): ObjectArray 64 | { 65 | $htmlObjectArray = $this->objectArrayFactory->create(HtmlInterface::class); 66 | 67 | for ($i = 0; $i < ($urls->count() / 2); $i++) { 68 | $this->createRequestDefinition($urls->offsetGet($i), $htmlObjectArray); 69 | } 70 | $this->loop->run(); 71 | 72 | for ($i; $i < ($urls->count()); $i++) { 73 | $this->createRequestDefinition($urls->offsetGet($i), $htmlObjectArray); 74 | } 75 | $this->loop->run(); 76 | 77 | return $htmlObjectArray; 78 | } 79 | 80 | /** 81 | * @codeCoverageIgnore 82 | * @param UrlInterface $url 83 | * @param ObjectArray $htmlObjectArray 84 | * @return void 85 | */ 86 | private function createRequestDefinition(UrlInterface $url, ObjectArray &$htmlObjectArray): void 87 | { 88 | $client = $this->clientFactory->create($this->loop); 89 | $request = $client->request('GET', $url->getUrl()); 90 | $request->on('response', function (Response $response) use (&$htmlObjectArray) { 91 | $data = ''; 92 | $response->on( 93 | 'data', 94 | function ($chunk) use (&$data) { 95 | $data .= $chunk; 96 | } 97 | )->on( 98 | 'end', 99 | function () use (&$htmlObjectArray, &$data) { 100 | $htmlObjectArray->add(new Html($data)); 101 | } 102 | ); 103 | }); 104 | $request->end(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Standalone/Http/SynchronousClient.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Standalone\Http; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\HtmlInterface; 14 | use MSlwk\ReactPhpPlayground\Api\Data\UrlInterface; 15 | use MSlwk\ReactPhpPlayground\Model\Data\Html; 16 | use MSlwk\TypeSafeArray\ObjectArray; 17 | use MSlwk\TypeSafeArray\ObjectArrayFactory; 18 | 19 | /** 20 | * Class SynchronousClient 21 | * @package MSlwk\ReactPhpPlayground\Standalone\Http 22 | */ 23 | class SynchronousClient implements ClientInterface 24 | { 25 | /** 26 | * @var ObjectArrayFactory 27 | */ 28 | private $objectArrayFactory; 29 | 30 | /** 31 | * SynchronousClient constructor. 32 | * @param ObjectArrayFactory $objectArrayFactory 33 | */ 34 | public function __construct(ObjectArrayFactory $objectArrayFactory) 35 | { 36 | $this->objectArrayFactory = $objectArrayFactory; 37 | } 38 | 39 | /** 40 | * @param ObjectArray $urls 41 | * @return ObjectArray 42 | */ 43 | public function getContent(ObjectArray $urls): ObjectArray 44 | { 45 | $htmlObjectArray = $this->objectArrayFactory->create(HtmlInterface::class); 46 | /** @var UrlInterface $url */ 47 | foreach ($urls as $url) { 48 | $html = $this->fileGetContentsWrapper($url); 49 | $htmlObjectArray->add(new Html($html)); 50 | } 51 | return $htmlObjectArray; 52 | } 53 | 54 | /** 55 | * @codeCoverageIgnore 56 | * @param UrlInterface $url 57 | * @return bool|string 58 | */ 59 | protected function fileGetContentsWrapper(UrlInterface $url) 60 | { 61 | $html = file_get_contents($url->getUrl()); 62 | return $html; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Standalone/Http/UrlProvider.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Standalone\Http; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\UrlInterface; 14 | use MSlwk\ReactPhpPlayground\Model\Data\Url; 15 | use MSlwk\TypeSafeArray\ObjectArray; 16 | use MSlwk\TypeSafeArray\ObjectArrayFactory; 17 | 18 | /** 19 | * Trait UrlProvider 20 | * @package MSlwk\ReactPhpPlayground\Standalone\Http 21 | */ 22 | class UrlProvider 23 | { 24 | /** 25 | * @var ObjectArrayFactory 26 | */ 27 | private $objectArrayFactory; 28 | 29 | /** 30 | * UrlProvider constructor. 31 | * @param ObjectArrayFactory $objectArrayFactory 32 | */ 33 | public function __construct(ObjectArrayFactory $objectArrayFactory) 34 | { 35 | $this->objectArrayFactory = $objectArrayFactory; 36 | } 37 | 38 | /** 39 | * @return ObjectArray 40 | */ 41 | public function getUrls(): ObjectArray 42 | { 43 | $urls = [ 44 | 'https://magento.com', 45 | 'https://marketplace.magento.com', 46 | 'https://u.magento.com', 47 | 'https://devdocs.magento.com', 48 | 'https://github.com/magento/magento2', 49 | 'https://pl.meet-magento.com/pl/' 50 | ]; 51 | 52 | $urlObjectArray = $this->objectArrayFactory->create(UrlInterface::class); 53 | foreach ($urls as $url) { 54 | $urlObjectArray->add(new Url($url)); 55 | } 56 | return $urlObjectArray; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Standalone/bin/childprocess: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 9 | * Github: https://github.com/maciejslawik 10 | */ 11 | 12 | use MSlwk\ReactPhpPlayground\Api\Data\ProcessInterface; 13 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ProcessFactory; 14 | use MSlwk\ReactPhpPlayground\Model\Data\Process; 15 | use MSlwk\ReactPhpPlayground\Model\Timer; 16 | use MSlwk\ReactPhpPlayground\Standalone\ChildProcess\AsynchronousProcessRunner; 17 | use MSlwk\ReactPhpPlayground\Standalone\ChildProcess\HalfAsynchronousProcessRunner; 18 | use MSlwk\ReactPhpPlayground\Standalone\ChildProcess\ProcessRunnerInterface; 19 | use MSlwk\ReactPhpPlayground\Standalone\ChildProcess\SynchronousProcessRunner; 20 | use MSlwk\TypeSafeArray\ObjectArrayFactory; 21 | use React\EventLoop\Factory; 22 | 23 | require_once __DIR__ . '/../../../../../../vendor/autoload.php'; 24 | 25 | $objectArrayFactory = new ObjectArrayFactory(); 26 | $timer = new Timer(); 27 | $processFactory = new ProcessFactory(); 28 | $loop = Factory::create(); 29 | 30 | $synchronousRunner = new SynchronousProcessRunner(); 31 | $halfAsynchronousRunner = new HalfAsynchronousProcessRunner($loop, $processFactory); 32 | $asynchronousRunner = new AsynchronousProcessRunner($loop, $processFactory); 33 | 34 | $processes = $objectArrayFactory->create(ProcessInterface::class); 35 | $processes->add(new Process(__DIR__ . '/../ChildProcess/processes/pi')); 36 | $processes->add(new Process(__DIR__ . '/../ChildProcess/processes/primes')); 37 | $processes->add(new Process(__DIR__ . '/../ChildProcess/processes/random')); 38 | $processes->add(new Process(__DIR__ . '/../ChildProcess/processes/sleep')); 39 | 40 | $runners = [ 41 | $synchronousRunner, 42 | $halfAsynchronousRunner, 43 | $asynchronousRunner 44 | ]; 45 | 46 | /** @var ProcessRunnerInterface $runner */ 47 | foreach ($runners as $runner) { 48 | $timer->startTimer(); 49 | $runner->runProcesses($processes); 50 | $timer->stopTimer(); 51 | echo '--------------------------------------------------------------------------------------------------' . PHP_EOL; 52 | echo "\033[0;32mExecution time for " 53 | . get_class($runner) 54 | . ': ' 55 | . $timer->getExecutionTimeInSeconds() 56 | . " seconds\033[0m" 57 | . PHP_EOL; 58 | } 59 | -------------------------------------------------------------------------------- /Standalone/bin/http: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 9 | * Github: https://github.com/maciejslawik 10 | */ 11 | 12 | use MSlwk\ReactPhpPlayground\Model\Timer; 13 | use MSlwk\ReactPhpPlayground\Standalone\Http\AsynchronousClient; 14 | use MSlwk\ReactPhpPlayground\Standalone\Http\ClientInterface; 15 | use MSlwk\ReactPhpPlayground\Standalone\Http\HalfAsynchronousClient; 16 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ClientFactory; 17 | use MSlwk\ReactPhpPlayground\Standalone\Http\SynchronousClient; 18 | use MSlwk\ReactPhpPlayground\Standalone\Http\UrlProvider; 19 | use MSlwk\TypeSafeArray\ObjectArrayFactory; 20 | use React\EventLoop\Factory; 21 | 22 | require_once __DIR__ . '/../../../../../../vendor/autoload.php'; 23 | 24 | $objectArrayFactory = new ObjectArrayFactory(); 25 | $urlProvider = new UrlProvider($objectArrayFactory); 26 | $clientFactory = new ClientFactory(); 27 | $synchronousClient = new SynchronousClient($objectArrayFactory); 28 | $halfAsynchronousClient = new HalfAsynchronousClient(Factory::create(), $clientFactory, $objectArrayFactory); 29 | $asynchronousClient = new AsynchronousClient(Factory::create(), $clientFactory, $objectArrayFactory); 30 | $timer = new Timer(); 31 | 32 | $clients = $objectArrayFactory->create( 33 | ClientInterface::class, 34 | [ 35 | $synchronousClient, 36 | $halfAsynchronousClient, 37 | $asynchronousClient 38 | ] 39 | ); 40 | 41 | /** @var ClientInterface $client */ 42 | foreach ($clients as $client) { 43 | $timer->startTimer(); 44 | $htmls = $client->getContent($urlProvider->getUrls()); 45 | $timer->stopTimer(); 46 | echo '--------------------------------------------------------------------------------------------------' . PHP_EOL; 47 | echo "\033[0;32mExecution time for " 48 | . get_class($client) 49 | . ': ' 50 | . $timer->getExecutionTimeInSeconds() 51 | . " seconds\033[0m" 52 | . PHP_EOL; 53 | } 54 | -------------------------------------------------------------------------------- /Test/Unit/Console/Command/GenerateReportsTest.php: -------------------------------------------------------------------------------- 1 | 7 | * Github: https://github.com/maciejslawik 8 | */ 9 | 10 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Console\Command; 11 | 12 | use MSlwk\ReactPhpPlayground\Console\Command\GenerateReports; 13 | use PHPUnit\Framework\TestCase; 14 | use Magento\Framework\Serialize\Serializer\Json; 15 | use MSlwk\ReactPhpPlayground\Api\Report\CliReportManagerInterface; 16 | use ReflectionClass; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use PHPUnit_Framework_MockObject_MockObject; 20 | 21 | /** 22 | * Class GenerateReportsTest 23 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Console\Command 24 | */ 25 | class GenerateReportsTest extends TestCase 26 | { 27 | /** 28 | * @var PHPUnit_Framework_MockObject_MockObject|Json 29 | */ 30 | private $jsonHandler; 31 | 32 | /** 33 | * @var PHPUnit_Framework_MockObject_MockObject|CliReportManagerInterface 34 | */ 35 | private $reportManager; 36 | 37 | /** 38 | * @var PHPUnit_Framework_MockObject_MockObject|InputInterface 39 | */ 40 | private $input; 41 | 42 | /** 43 | * @var PHPUnit_Framework_MockObject_MockObject|OutputInterface 44 | */ 45 | private $output; 46 | 47 | /** 48 | * @var GenerateReports 49 | */ 50 | private $command; 51 | 52 | /** 53 | * @return void 54 | */ 55 | protected function setUp() 56 | { 57 | $this->jsonHandler = $this->getMockBuilder(Json::class) 58 | ->disableOriginalConstructor() 59 | ->getMock(); 60 | $this->reportManager = $this->getMockBuilder(CliReportManagerInterface::class) 61 | ->getMock(); 62 | $this->input = $this->getMockBuilder(InputInterface::class) 63 | ->getMock(); 64 | $this->output = $this->getMockBuilder(OutputInterface::class) 65 | ->getMock(); 66 | 67 | $this->command = new GenerateReports( 68 | $this->jsonHandler, 69 | $this->reportManager 70 | ); 71 | } 72 | 73 | /** 74 | * @test 75 | */ 76 | public function testCommandHasCorrectName() 77 | { 78 | $this->assertEquals(GenerateReports::COMMAND_NAME, $this->command->getName()); 79 | } 80 | 81 | /** 82 | * @test 83 | */ 84 | public function testCommandHasCorrectDescription() 85 | { 86 | $this->assertEquals(GenerateReports::COMMAND_DESCRIPTION, $this->command->getDescription()); 87 | } 88 | 89 | /** 90 | * @test 91 | */ 92 | public function testExecute() 93 | { 94 | $customerIds = [1, 2]; 95 | $this->input->expects($this->once()) 96 | ->method('getArgument') 97 | ->with(GenerateReports::ARGUMENT_CUSTOMER_IDS) 98 | ->willReturn('json'); 99 | $this->jsonHandler->expects($this->once()) 100 | ->method('unserialize') 101 | ->with('json') 102 | ->willReturn($customerIds); 103 | $this->reportManager->expects($this->once()) 104 | ->method('generateAndSendReportForCustomers') 105 | ->with($customerIds); 106 | 107 | $reflection = new ReflectionClass(get_class($this->command)); 108 | $method = $reflection->getMethod('execute'); 109 | $method->setAccessible(true); 110 | $method->invokeArgs($this->command, [$this->input, $this->output]); 111 | 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Test/Unit/Console/Command/StartCliReportingServiceTest.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Console\Command; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\ChunkSizeCalculatorInterface; 14 | use MSlwk\ReactPhpPlayground\Console\Command\StartCliReportingService; 15 | use PHPUnit\Framework\TestCase; 16 | use Magento\Framework\Serialize\Serializer\Json; 17 | use PHPUnit_Framework_MockObject_MockObject; 18 | use MSlwk\ReactPhpPlayground\Api\CustomerIdsProviderInterface; 19 | use MSlwk\ReactPhpPlayground\Api\TimerInterface; 20 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ProcessFactory; 21 | use React\EventLoop\Factory; 22 | 23 | /** 24 | * Class StartCliReportingServiceTest 25 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Console\Command 26 | */ 27 | class StartCliReportingServiceTest extends TestCase 28 | { 29 | /** 30 | * @var StartCliReportingService 31 | */ 32 | private $command; 33 | 34 | /** 35 | * @return void 36 | */ 37 | protected function setUp() 38 | { 39 | /** @var PHPUnit_Framework_MockObject_MockObject|TimerInterface $timer */ 40 | $timer = $this->getMockBuilder(TimerInterface::class) 41 | ->getMock(); 42 | /** @var PHPUnit_Framework_MockObject_MockObject|CustomerIdsProviderInterface $customerIdsProvider */ 43 | $customerIdsProvider = $this->getMockBuilder(CustomerIdsProviderInterface::class) 44 | ->getMock(); 45 | $loopFactory = new Factory(); 46 | /** @var PHPUnit_Framework_MockObject_MockObject|ProcessFactory $processFactory */ 47 | $processFactory = $this->getMockBuilder(ProcessFactory::class) 48 | ->disableOriginalConstructor() 49 | ->getMock(); 50 | /** @var PHPUnit_Framework_MockObject_MockObject|Json $jsonHandler */ 51 | $jsonHandler = $this->getMockBuilder(Json::class) 52 | ->disableOriginalConstructor() 53 | ->getMock(); 54 | /** @var PHPUnit_Framework_MockObject_MockObject|ChunkSizeCalculatorInterface $chunkSizeCalculator */ 55 | $chunkSizeCalculator = $this->getMockBuilder(ChunkSizeCalculatorInterface::class) 56 | ->getMock(); 57 | 58 | $this->command = new StartCliReportingService( 59 | $timer, 60 | $customerIdsProvider, 61 | $loopFactory, 62 | $processFactory, 63 | $jsonHandler, 64 | $chunkSizeCalculator 65 | ); 66 | } 67 | 68 | /** 69 | * @test 70 | */ 71 | public function testCommandHasCorrectName() 72 | { 73 | $this->assertEquals(StartCliReportingService::COMMAND_NAME, $this->command->getName()); 74 | } 75 | 76 | /** 77 | * @test 78 | */ 79 | public function testCommandHasCorrectDescription() 80 | { 81 | $this->assertEquals(StartCliReportingService::COMMAND_DESCRIPTION, $this->command->getDescription()); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Test/Unit/Console/Command/StartWebapiReportingServiceTest.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Console\Command; 12 | 13 | use Magento\Store\Model\StoreManagerInterface; 14 | use MSlwk\ReactPhpPlayground\Api\ChunkSizeCalculatorInterface; 15 | use MSlwk\ReactPhpPlayground\Console\Command\StartWebapiReportingService; 16 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ClientFactory; 17 | use PHPUnit\Framework\TestCase; 18 | use Magento\Framework\Serialize\Serializer\Json; 19 | use PHPUnit_Framework_MockObject_MockObject; 20 | use MSlwk\ReactPhpPlayground\Api\CustomerIdsProviderInterface; 21 | use MSlwk\ReactPhpPlayground\Api\TimerInterface; 22 | use React\EventLoop\Factory; 23 | 24 | /** 25 | * Class StartWebapiReportingServiceTest 26 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Console\Command 27 | */ 28 | class StartWebapiReportingServiceTest extends TestCase 29 | { 30 | /** 31 | * @var StartWebapiReportingService 32 | */ 33 | private $command; 34 | 35 | /** 36 | * @return void 37 | */ 38 | protected function setUp() 39 | { 40 | /** @var PHPUnit_Framework_MockObject_MockObject|TimerInterface $timer */ 41 | $timer = $this->getMockBuilder(TimerInterface::class) 42 | ->getMock(); 43 | /** @var PHPUnit_Framework_MockObject_MockObject|CustomerIdsProviderInterface $customerIdsProvider */ 44 | $customerIdsProvider = $this->getMockBuilder(CustomerIdsProviderInterface::class) 45 | ->getMock(); 46 | $loopFactory = new Factory(); 47 | /** @var PHPUnit_Framework_MockObject_MockObject|ClientFactory $clientFactory */ 48 | $clientFactory = $this->getMockBuilder(ClientFactory::class) 49 | ->disableOriginalConstructor() 50 | ->getMock(); 51 | /** @var PHPUnit_Framework_MockObject_MockObject|Json $jsonHandler */ 52 | $jsonHandler = $this->getMockBuilder(Json::class) 53 | ->disableOriginalConstructor() 54 | ->getMock(); 55 | /** @var PHPUnit_Framework_MockObject_MockObject|StoreManagerInterface $storeManager */ 56 | $storeManager = $this->getMockBuilder(StoreManagerInterface::class) 57 | ->getMock(); 58 | /** @var PHPUnit_Framework_MockObject_MockObject|ChunkSizeCalculatorInterface $chunkSizeCalculator */ 59 | $chunkSizeCalculator = $this->getMockBuilder(ChunkSizeCalculatorInterface::class) 60 | ->getMock(); 61 | 62 | $this->command = new StartWebapiReportingService( 63 | $timer, 64 | $customerIdsProvider, 65 | $loopFactory, 66 | $clientFactory, 67 | $jsonHandler, 68 | $storeManager, 69 | $chunkSizeCalculator 70 | ); 71 | } 72 | 73 | /** 74 | * @test 75 | */ 76 | public function testCommandHasCorrectName() 77 | { 78 | $this->assertEquals(StartWebapiReportingService::COMMAND_NAME, $this->command->getName()); 79 | } 80 | 81 | /** 82 | * @test 83 | */ 84 | public function testCommandHasCorrectDescription() 85 | { 86 | $this->assertEquals(StartWebapiReportingService::COMMAND_DESCRIPTION, $this->command->getDescription()); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Test/Unit/Model/Adapter/ReactPHP/ClientFactoryTest.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl) 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Model\Adapter\ReactPHP; 12 | 13 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ClientFactory; 14 | use PHPUnit\Framework\TestCase; 15 | use React\EventLoop\LoopInterface; 16 | use React\HttpClient\Client; 17 | 18 | /** 19 | * Class ClientFactoryTest 20 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Model\Adapter\ReactPHP 21 | */ 22 | class ClientFactoryTest extends TestCase 23 | { 24 | /** 25 | * @test 26 | */ 27 | public function testFactoryReturnsCorrectObject() 28 | { 29 | $loop = $this->getMockBuilder(LoopInterface::class) 30 | ->getMock(); 31 | $factory = new ClientFactory(); 32 | 33 | $result = $factory->create($loop); 34 | 35 | $this->assertInstanceOf(Client::class, $result); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Test/Unit/Model/Adapter/ReactPHP/ProcessFactoryTest.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl) 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Model\Adapter\ReactPHP; 12 | 13 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ProcessFactory; 14 | use PHPUnit\Framework\TestCase; 15 | use React\ChildProcess\Process; 16 | 17 | /** 18 | * Class ProcessFactoryTest 19 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Model\Adapter\ReactPHP 20 | */ 21 | class ProcessFactoryTest extends TestCase 22 | { 23 | /** 24 | * @test 25 | */ 26 | public function testFactoryReturnsCorrectObject() 27 | { 28 | $command = 'ps aux'; 29 | $factory = new ProcessFactory(); 30 | 31 | $result = $factory->create($command); 32 | 33 | $this->assertInstanceOf(Process::class, $result); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Test/Unit/Model/ChunkSizeCalculatorTest.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Model; 12 | 13 | use MSlwk\ReactPhpPlayground\Model\ChunkSizeCalculator; 14 | use PHPUnit\Framework\TestCase; 15 | 16 | /** 17 | * Class ChunkSizeCalculatorTest 18 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Model 19 | */ 20 | class ChunkSizeCalculatorTest extends TestCase 21 | { 22 | /** 23 | * @test 24 | * @param array $elements 25 | * @param int $numberOfThreads 26 | * @param int $expected 27 | * @dataProvider chunksDataProvider 28 | */ 29 | public function testCalculateNumberOfChunks(array $elements, int $numberOfThreads, int $expected) 30 | { 31 | $calculator = new ChunkSizeCalculator(); 32 | 33 | $this->assertEquals($expected, $calculator->calculateChunkSize($elements, $numberOfThreads)); 34 | } 35 | 36 | /** 37 | * @return array 38 | */ 39 | public function chunksDataProvider() 40 | { 41 | return [ 42 | [ 43 | [ 44 | 1, 45 | 2, 46 | 3, 47 | 4, 48 | 5, 49 | 6, 50 | 7 51 | ], 52 | 3, 53 | 3 54 | ], 55 | [ 56 | [ 57 | 1, 58 | 2, 59 | 3, 60 | 4, 61 | 5, 62 | 6 63 | ], 64 | 5, 65 | 2 66 | ], 67 | [ 68 | [ 69 | 1, 70 | 2, 71 | 3 72 | ], 73 | 5, 74 | 1 75 | ] 76 | ]; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Test/Unit/Model/Data/HtmlTest.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl) 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Model\Data; 12 | 13 | use MSlwk\ReactPhpPlayground\Model\Data\Html; 14 | use PHPUnit\Framework\TestCase; 15 | 16 | /** 17 | * Class HtmlTest 18 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Model\Data 19 | */ 20 | class HtmlTest extends TestCase 21 | { 22 | /** 23 | * @test 24 | */ 25 | public function testGetHtml() 26 | { 27 | $html = ''; 28 | $htmlObject = new Html($html); 29 | 30 | $this->assertEquals($html, $htmlObject->getHtml()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Test/Unit/Model/Data/ProcessTest.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl) 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Model\Data; 12 | 13 | use MSlwk\ReactPhpPlayground\Model\Data\Process; 14 | use PHPUnit\Framework\TestCase; 15 | 16 | /** 17 | * Class ProcessTest 18 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Model\Data 19 | */ 20 | class ProcessTest extends TestCase 21 | { 22 | /** 23 | * @test 24 | */ 25 | public function testGetCommand() 26 | { 27 | $command = 'ps aux'; 28 | $commandObject = new Process($command); 29 | 30 | $this->assertEquals($command, $commandObject->getCommand()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Test/Unit/Model/Data/UrlTest.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl) 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Model\Data; 12 | 13 | use MSlwk\ReactPhpPlayground\Model\Data\Url; 14 | use PHPUnit\Framework\TestCase; 15 | 16 | /** 17 | * Class UrlTest 18 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Model\Data 19 | */ 20 | class UrlTest extends TestCase 21 | { 22 | /** 23 | * @test 24 | */ 25 | public function testGetUrl() 26 | { 27 | $url = 'https://magento.com'; 28 | $urlObject = new Url($url); 29 | 30 | $this->assertEquals($url, $urlObject->getUrl()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Test/Unit/Model/FakeCustomerIdsProviderTest.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Model; 12 | 13 | use MSlwk\ReactPhpPlayground\Model\FakeCustomerIdsProvider; 14 | use PHPUnit\Framework\TestCase; 15 | 16 | /** 17 | * Class FakeCustomerIdsProviderTest 18 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Model 19 | */ 20 | class FakeCustomerIdsProviderTest extends TestCase 21 | { 22 | /** 23 | * @test 24 | */ 25 | public function testProviderReturnsArrayOfInts() 26 | { 27 | $idsProvider = new FakeCustomerIdsProvider(); 28 | $result = $idsProvider->getCustomerIds(); 29 | 30 | foreach ($result as $id) { 31 | $this->assertInternalType('int', $id); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Test/Unit/Model/Report/CliReportManagerTest.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Model\Report; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Report\ReportGeneratorInterface; 14 | use MSlwk\ReactPhpPlayground\Api\Report\ReportSenderInterface; 15 | use MSlwk\ReactPhpPlayground\Model\Report\CliReportManager; 16 | use PHPUnit\Framework\TestCase; 17 | use PHPUnit_Framework_MockObject_MockObject; 18 | 19 | /** 20 | * Class CliReportManagerTest 21 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Model\Report 22 | */ 23 | class CliReportManagerTest extends TestCase 24 | { 25 | /** 26 | * @var PHPUnit_Framework_MockObject_MockObject|ReportGeneratorInterface 27 | */ 28 | private $reportGenerator; 29 | 30 | /** 31 | * @var PHPUnit_Framework_MockObject_MockObject|ReportSenderInterface 32 | */ 33 | private $reportSender; 34 | 35 | /** 36 | * @var CliReportManager 37 | */ 38 | private $reportManager; 39 | 40 | /** 41 | * @return void 42 | */ 43 | protected function setUp() 44 | { 45 | $this->reportGenerator = $this->getMockBuilder(ReportGeneratorInterface::class) 46 | ->getMock(); 47 | $this->reportSender = $this->getMockBuilder(ReportSenderInterface::class) 48 | ->getMock(); 49 | 50 | $this->reportManager = new CliReportManager( 51 | $this->reportGenerator, 52 | $this->reportSender 53 | ); 54 | } 55 | 56 | /** 57 | * @test 58 | */ 59 | public function testSendAndGenerateReports() 60 | { 61 | $customerIds = [ 62 | 1, 63 | 2, 64 | 3 65 | ]; 66 | $report = 'report'; 67 | $this->reportGenerator->expects($this->exactly(3)) 68 | ->method('generateReport') 69 | ->withConsecutive([1], [2], [3]) 70 | ->willReturn($report); 71 | $this->reportSender->expects($this->exactly(3)) 72 | ->method('sendReport') 73 | ->with($report); 74 | 75 | $this->reportManager->generateAndSendReportForCustomers($customerIds); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Test/Unit/Model/Report/WebapiReportManagerTest.php: -------------------------------------------------------------------------------- 1 | 8 | * Github: https://github.com/maciejslawik 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Model\Report; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Report\ReportGeneratorInterface; 14 | use MSlwk\ReactPhpPlayground\Api\Report\ReportSenderInterface; 15 | use MSlwk\ReactPhpPlayground\Model\Report\WebapiReportManager; 16 | use PHPUnit\Framework\TestCase; 17 | use PHPUnit_Framework_MockObject_MockObject; 18 | 19 | /** 20 | * Class WebapiReportManagerTest 21 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Model\Report 22 | */ 23 | class WebapiReportManagerTest extends TestCase 24 | { 25 | /** 26 | * @var PHPUnit_Framework_MockObject_MockObject|ReportGeneratorInterface 27 | */ 28 | private $reportGenerator; 29 | 30 | /** 31 | * @var PHPUnit_Framework_MockObject_MockObject|ReportSenderInterface 32 | */ 33 | private $reportSender; 34 | 35 | /** 36 | * @var WebapiReportManager 37 | */ 38 | private $reportManager; 39 | 40 | /** 41 | * @return void 42 | */ 43 | protected function setUp() 44 | { 45 | $this->reportGenerator = $this->getMockBuilder(ReportGeneratorInterface::class) 46 | ->getMock(); 47 | $this->reportSender = $this->getMockBuilder(ReportSenderInterface::class) 48 | ->getMock(); 49 | 50 | $this->reportManager = new WebapiReportManager( 51 | $this->reportGenerator, 52 | $this->reportSender 53 | ); 54 | } 55 | 56 | /** 57 | * @test 58 | */ 59 | public function testSendAndGenerateReports() 60 | { 61 | $customerIds = [ 62 | 1, 63 | 2, 64 | 3 65 | ]; 66 | $report = 'report'; 67 | $this->reportGenerator->expects($this->exactly(3)) 68 | ->method('generateReport') 69 | ->withConsecutive([1], [2], [3]) 70 | ->willReturn($report); 71 | $this->reportSender->expects($this->exactly(3)) 72 | ->method('sendReport') 73 | ->with($report); 74 | 75 | $result = $this->reportManager->generateAndSendReportForCustomers($customerIds); 76 | 77 | $this->assertEquals(3, count($result)); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Test/Unit/Model/TimerTest.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl) 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Model; 12 | 13 | use MSlwk\ReactPhpPlayground\Exception\TimerException; 14 | use MSlwk\ReactPhpPlayground\Model\Timer; 15 | use PHPUnit\Framework\TestCase; 16 | 17 | /** 18 | * Class TimerTest 19 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Model 20 | */ 21 | class TimerTest extends TestCase 22 | { 23 | /** 24 | * @var Timer 25 | */ 26 | private $timer; 27 | 28 | /** 29 | * @return void 30 | */ 31 | protected function setUp() 32 | { 33 | $this->timer = new Timer(); 34 | } 35 | 36 | /** 37 | * @test 38 | * @throws TimerException 39 | */ 40 | public function testTimerCalculatesEexecutionTime() 41 | { 42 | $this->timer->startTimer(); 43 | $this->timer->stopTimer(); 44 | 45 | $this->assertGreaterThan(0.0, $this->timer->getExecutionTimeInSeconds()); 46 | } 47 | 48 | /** 49 | * @test 50 | * @throws TimerException 51 | */ 52 | public function testCannotStopTimerWithoutStarting() 53 | { 54 | $this->expectException(TimerException::class); 55 | $this->timer->stopTimer(); 56 | } 57 | 58 | /** 59 | * @test 60 | * @throws TimerException 61 | */ 62 | public function testCannotCalculateTimeWithoutStartingTimer() 63 | { 64 | $this->expectException(TimerException::class); 65 | $this->timer->getExecutionTimeInSeconds(); 66 | } 67 | 68 | /** 69 | * @test 70 | * @throws TimerException 71 | */ 72 | public function testCannotCalculateTimeWithoutStoppingTimer() 73 | { 74 | $this->expectException(TimerException::class); 75 | $this->timer->startTimer(); 76 | $this->timer->getExecutionTimeInSeconds(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Test/Unit/Standalone/ChildProcess/AsynchronousProcessRunnerTest.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl) 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Standalone\ChildProcess; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\ProcessInterface; 14 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ProcessFactory; 15 | use MSlwk\ReactPhpPlayground\Model\Data\Process; 16 | use MSlwk\ReactPhpPlayground\Standalone\ChildProcess\AsynchronousProcessRunner; 17 | use MSlwk\TypeSafeArray\ObjectArray; 18 | use PHPUnit\Framework\TestCase; 19 | use PHPUnit_Framework_MockObject_MockObject; 20 | use React\EventLoop\LoopInterface; 21 | 22 | /** 23 | * Class AsynchronousProcessRunnerTest 24 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Standalone\ChildProcess 25 | */ 26 | class AsynchronousProcessRunnerTest extends TestCase 27 | { 28 | /** 29 | * @var PHPUnit_Framework_MockObject_MockObject|LoopInterface 30 | */ 31 | private $loop; 32 | 33 | /** 34 | * @var PHPUnit_Framework_MockObject_MockObject|ProcessFactory 35 | */ 36 | private $processFactory; 37 | 38 | /** 39 | * @var PHPUnit_Framework_MockObject_MockObject|AsynchronousProcessRunner 40 | */ 41 | private $asynchronousRunner; 42 | 43 | /** 44 | * @return void 45 | */ 46 | protected function setUp() 47 | { 48 | $this->loop = $this->getMockBuilder(LoopInterface::class) 49 | ->getMock(); 50 | $this->processFactory = $this->getMockBuilder(ProcessFactory::class) 51 | ->disableOriginalConstructor() 52 | ->getMock(); 53 | 54 | $this->asynchronousRunner = $this->getMockBuilder(AsynchronousProcessRunner::class) 55 | ->setConstructorArgs( 56 | [ 57 | 'loop' => $this->loop, 58 | 'processFactory' => $this->processFactory 59 | ] 60 | ) 61 | ->setMethods(['createProcessDefinition']) 62 | ->getMock(); 63 | } 64 | 65 | /** 66 | * @test 67 | */ 68 | public function testRunProcesses() 69 | { 70 | /** @var PHPUnit_Framework_MockObject_MockObject|ObjectArray $processArray */ 71 | $processArray = $this->getMockBuilder(ObjectArray::class) 72 | ->setConstructorArgs( 73 | [ 74 | 'type' => ProcessInterface::class, 75 | 'objects' => [new Process('process'), new Process('process')] 76 | ] 77 | ) 78 | ->setMethods(null) 79 | ->getMock(); 80 | 81 | $this->asynchronousRunner->expects($this->exactly(2)) 82 | ->method('createProcessDefinition'); 83 | $this->loop->expects($this->once()) 84 | ->method('run'); 85 | 86 | $this->asynchronousRunner->runProcesses($processArray); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Test/Unit/Standalone/ChildProcess/HalfAsynchronousProcessRunnerTest.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl) 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Standalone\ChildProcess; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\ProcessInterface; 14 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ProcessFactory; 15 | use MSlwk\ReactPhpPlayground\Model\Data\Process; 16 | use MSlwk\ReactPhpPlayground\Standalone\ChildProcess\HalfAsynchronousProcessRunner; 17 | use MSlwk\TypeSafeArray\ObjectArray; 18 | use PHPUnit\Framework\TestCase; 19 | use PHPUnit_Framework_MockObject_MockObject; 20 | use React\EventLoop\LoopInterface; 21 | 22 | /** 23 | * Class HalfAsynchronousProcessRunnerTest 24 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Standalone\ChildProcess 25 | */ 26 | class HalfAsynchronousProcessRunnerTest extends TestCase 27 | { 28 | /** 29 | * @var PHPUnit_Framework_MockObject_MockObject|LoopInterface 30 | */ 31 | private $loop; 32 | 33 | /** 34 | * @var PHPUnit_Framework_MockObject_MockObject|ProcessFactory 35 | */ 36 | private $processFactory; 37 | 38 | /** 39 | * @var PHPUnit_Framework_MockObject_MockObject|HalfAsynchronousProcessRunner 40 | */ 41 | private $halfAsynchronousRunner; 42 | 43 | /** 44 | * @return void 45 | */ 46 | protected function setUp() 47 | { 48 | $this->loop = $this->getMockBuilder(LoopInterface::class) 49 | ->getMock(); 50 | $this->processFactory = $this->getMockBuilder(ProcessFactory::class) 51 | ->disableOriginalConstructor() 52 | ->getMock(); 53 | 54 | $this->halfAsynchronousRunner = $this->getMockBuilder(HalfAsynchronousProcessRunner::class) 55 | ->setConstructorArgs( 56 | [ 57 | 'loop' => $this->loop, 58 | 'processFactory' => $this->processFactory 59 | ] 60 | ) 61 | ->setMethods(['createProcessDefinition']) 62 | ->getMock(); 63 | } 64 | 65 | /** 66 | * @test 67 | */ 68 | public function testRunProcesses() 69 | { 70 | /** @var PHPUnit_Framework_MockObject_MockObject|ObjectArray $processArray */ 71 | $processArray = $this->getMockBuilder(ObjectArray::class) 72 | ->setConstructorArgs( 73 | [ 74 | 'type' => ProcessInterface::class, 75 | 'objects' => [new Process('process'), new Process('process')] 76 | ] 77 | ) 78 | ->setMethods(null) 79 | ->getMock(); 80 | 81 | $this->halfAsynchronousRunner->expects($this->exactly(2)) 82 | ->method('createProcessDefinition'); 83 | $this->loop->expects($this->exactly(2)) 84 | ->method('run'); 85 | 86 | $this->halfAsynchronousRunner->runProcesses($processArray); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Test/Unit/Standalone/ChildProcess/SynchronousProcessRunnerTest.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl) 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Standalone\ChildProcess; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\ProcessInterface; 14 | use MSlwk\ReactPhpPlayground\Model\Data\Process; 15 | use MSlwk\ReactPhpPlayground\Standalone\ChildProcess\SynchronousProcessRunner; 16 | use MSlwk\TypeSafeArray\ObjectArray; 17 | use PHPUnit\Framework\TestCase; 18 | use PHPUnit_Framework_MockObject_MockObject; 19 | 20 | /** 21 | * Class SynchronousProcessRunnerTest 22 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Standalone\ChildProcess 23 | */ 24 | class SynchronousProcessRunnerTest extends TestCase 25 | { 26 | /** 27 | * @test 28 | */ 29 | public function testRunProcesses() 30 | { 31 | /** @var PHPUnit_Framework_MockObject_MockObject|ObjectArray $processArray */ 32 | $processArray = $this->getMockBuilder(ObjectArray::class) 33 | ->setConstructorArgs( 34 | [ 35 | 'type' => ProcessInterface::class, 36 | 'objects' => [new Process('process')] 37 | ] 38 | ) 39 | ->setMethods(null) 40 | ->getMock(); 41 | /** @var PHPUnit_Framework_MockObject_MockObject|SynchronousProcessRunner $synchronousRunner */ 42 | $synchronousRunner = $this->getMockBuilder(SynchronousProcessRunner::class) 43 | ->disableOriginalConstructor() 44 | ->setMethods(['execWrapper']) 45 | ->getMock(); 46 | $synchronousRunner->expects($this->once()) 47 | ->method('execWrapper') 48 | ->with('process') 49 | ->willReturn(''); 50 | 51 | $synchronousRunner->runProcesses($processArray); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Test/Unit/Standalone/Http/AsynchronousClientTest.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl) 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Standalone\Http; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\HtmlInterface; 14 | use MSlwk\ReactPhpPlayground\Api\Data\UrlInterface; 15 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ClientFactory; 16 | use MSlwk\ReactPhpPlayground\Model\Data\Url; 17 | use MSlwk\ReactPhpPlayground\Standalone\Http\AsynchronousClient; 18 | use MSlwk\TypeSafeArray\ObjectArray; 19 | use MSlwk\TypeSafeArray\ObjectArrayFactory; 20 | use PHPUnit\Framework\TestCase; 21 | use PHPUnit_Framework_MockObject_MockObject; 22 | use React\EventLoop\LoopInterface; 23 | use React\HttpClient\Client; 24 | use React\HttpClient\Request; 25 | 26 | /** 27 | * Class AsynchronousClientTest 28 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Standalone\Http 29 | */ 30 | class AsynchronousClientTest extends TestCase 31 | { 32 | /** 33 | * @var PHPUnit_Framework_MockObject_MockObject|LoopInterface 34 | */ 35 | private $loop; 36 | 37 | /** 38 | * @var PHPUnit_Framework_MockObject_MockObject|ClientFactory 39 | */ 40 | private $clientFactory; 41 | 42 | /** 43 | * @var PHPUnit_Framework_MockObject_MockObject|ObjectArrayFactory 44 | */ 45 | private $objectArrayFactory; 46 | 47 | /** 48 | * @var AsynchronousClient 49 | */ 50 | private $asynchronousClient; 51 | 52 | /** 53 | * @return void 54 | */ 55 | protected function setUp() 56 | { 57 | $this->loop = $this->getMockBuilder(LoopInterface::class) 58 | ->getMock(); 59 | $this->clientFactory = $this->getMockBuilder(ClientFactory::class) 60 | ->disableOriginalConstructor() 61 | ->getMock(); 62 | $this->objectArrayFactory = $this->getMockBuilder(ObjectArrayFactory::class) 63 | ->disableOriginalConstructor() 64 | ->getMock(); 65 | 66 | $this->asynchronousClient = new AsynchronousClient( 67 | $this->loop, 68 | $this->clientFactory, 69 | $this->objectArrayFactory 70 | ); 71 | } 72 | 73 | /** 74 | * @test 75 | */ 76 | public function testGetContent() 77 | { 78 | /** @var PHPUnit_Framework_MockObject_MockObject|ObjectArray $htmlObjectArray */ 79 | $htmlObjectArray = $this->getMockBuilder(ObjectArray::class) 80 | ->setConstructorArgs( 81 | [ 82 | 'type' => HtmlInterface::class 83 | ] 84 | ) 85 | ->setMethods(null) 86 | ->getMock(); 87 | /** @var PHPUnit_Framework_MockObject_MockObject|ObjectArray $urlObjectArray */ 88 | $urlObjectArray = $this->getMockBuilder(ObjectArray::class) 89 | ->setConstructorArgs( 90 | [ 91 | 'type' => UrlInterface::class, 92 | 'objects' => [new Url('url')] 93 | ] 94 | ) 95 | ->setMethods(null) 96 | ->getMock(); 97 | $this->objectArrayFactory->expects($this->once()) 98 | ->method('create') 99 | ->willReturn($htmlObjectArray); 100 | $client = $this->getMockBuilder(Client::class) 101 | ->disableOriginalConstructor() 102 | ->getMock(); 103 | $this->clientFactory->expects($this->once()) 104 | ->method('create') 105 | ->with($this->loop) 106 | ->willReturn($client); 107 | $request = $this->getMockBuilder(Request::class) 108 | ->disableOriginalConstructor() 109 | ->getMock(); 110 | $client->expects($this->once()) 111 | ->method('request') 112 | ->willReturn($request); 113 | $request->expects($this->once()) 114 | ->method('end'); 115 | $request->expects($this->once()) 116 | ->method('on'); 117 | $this->loop->expects($this->once()) 118 | ->method('run'); 119 | 120 | $result = $this->asynchronousClient->getContent($urlObjectArray); 121 | 122 | $this->assertInstanceOf(ObjectArray::class, $result); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Test/Unit/Standalone/Http/HalfAsynchronousClientTest.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl) 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Standalone\Http; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\HtmlInterface; 14 | use MSlwk\ReactPhpPlayground\Api\Data\UrlInterface; 15 | use MSlwk\ReactPhpPlayground\Model\Adapter\ReactPHP\ClientFactory; 16 | use MSlwk\ReactPhpPlayground\Model\Data\Url; 17 | use MSlwk\ReactPhpPlayground\Standalone\Http\HalfAsynchronousClient; 18 | use MSlwk\TypeSafeArray\ObjectArray; 19 | use MSlwk\TypeSafeArray\ObjectArrayFactory; 20 | use PHPUnit\Framework\TestCase; 21 | use PHPUnit_Framework_MockObject_MockObject; 22 | use React\EventLoop\LoopInterface; 23 | use React\HttpClient\Client; 24 | use React\HttpClient\Request; 25 | 26 | /** 27 | * Class HalfHalfAsynchronousClientTest 28 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Standalone\Http 29 | */ 30 | class HalfHalfAsynchronousClientTest extends TestCase 31 | { 32 | /** 33 | * @var PHPUnit_Framework_MockObject_MockObject|LoopInterface 34 | */ 35 | private $loop; 36 | 37 | /** 38 | * @var PHPUnit_Framework_MockObject_MockObject|ClientFactory 39 | */ 40 | private $clientFactory; 41 | 42 | /** 43 | * @var PHPUnit_Framework_MockObject_MockObject|ObjectArrayFactory 44 | */ 45 | private $objectArrayFactory; 46 | 47 | /** 48 | * @var HalfAsynchronousClient 49 | */ 50 | private $halfHalfAsynchronousClient; 51 | 52 | /** 53 | * @return void 54 | */ 55 | protected function setUp() 56 | { 57 | $this->loop = $this->getMockBuilder(LoopInterface::class) 58 | ->getMock(); 59 | $this->clientFactory = $this->getMockBuilder(ClientFactory::class) 60 | ->disableOriginalConstructor() 61 | ->getMock(); 62 | $this->objectArrayFactory = $this->getMockBuilder(ObjectArrayFactory::class) 63 | ->disableOriginalConstructor() 64 | ->getMock(); 65 | 66 | $this->halfHalfAsynchronousClient = new HalfAsynchronousClient( 67 | $this->loop, 68 | $this->clientFactory, 69 | $this->objectArrayFactory 70 | ); 71 | } 72 | 73 | /** 74 | * @test 75 | */ 76 | public function testGetContent() 77 | { 78 | /** @var PHPUnit_Framework_MockObject_MockObject|ObjectArray $htmlObjectArray */ 79 | $htmlObjectArray = $this->getMockBuilder(ObjectArray::class) 80 | ->setConstructorArgs( 81 | [ 82 | 'type' => HtmlInterface::class 83 | ] 84 | ) 85 | ->setMethods(null) 86 | ->getMock(); 87 | /** @var PHPUnit_Framework_MockObject_MockObject|ObjectArray $urlObjectArray */ 88 | $urlObjectArray = $this->getMockBuilder(ObjectArray::class) 89 | ->setConstructorArgs( 90 | [ 91 | 'type' => UrlInterface::class, 92 | 'objects' => [new Url('url'), new Url('url')] 93 | ] 94 | ) 95 | ->setMethods(null) 96 | ->getMock(); 97 | $this->objectArrayFactory->expects($this->once()) 98 | ->method('create') 99 | ->willReturn($htmlObjectArray); 100 | $client = $this->getMockBuilder(Client::class) 101 | ->disableOriginalConstructor() 102 | ->getMock(); 103 | $this->clientFactory->expects($this->exactly(2)) 104 | ->method('create') 105 | ->with($this->loop) 106 | ->willReturn($client); 107 | $request = $this->getMockBuilder(Request::class) 108 | ->disableOriginalConstructor() 109 | ->getMock(); 110 | $client->expects($this->exactly(2)) 111 | ->method('request') 112 | ->willReturn($request); 113 | $request->expects($this->exactly(2)) 114 | ->method('end'); 115 | $request->expects($this->exactly(2)) 116 | ->method('on'); 117 | $this->loop->expects($this->exactly(2)) 118 | ->method('run'); 119 | 120 | $result = $this->halfHalfAsynchronousClient->getContent($urlObjectArray); 121 | 122 | $this->assertInstanceOf(ObjectArray::class, $result); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Test/Unit/Standalone/Http/SynchronousClientTest.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl) 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Standalone\Http; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\HtmlInterface; 14 | use MSlwk\ReactPhpPlayground\Api\Data\UrlInterface; 15 | use MSlwk\ReactPhpPlayground\Model\Data\Url; 16 | use MSlwk\ReactPhpPlayground\Standalone\Http\SynchronousClient; 17 | use MSlwk\TypeSafeArray\ObjectArray; 18 | use MSlwk\TypeSafeArray\ObjectArrayFactory; 19 | use PHPUnit\Framework\TestCase; 20 | use PHPUnit_Framework_MockObject_MockObject; 21 | 22 | /** 23 | * Class SynchronousClientTest 24 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Standalone\Http 25 | */ 26 | class SynchronousClientTest extends TestCase 27 | { 28 | /** 29 | * @test 30 | */ 31 | public function testRun() 32 | { 33 | /** @var PHPUnit_Framework_MockObject_MockObject|ObjectArrayFactory $objectArrayFactory */ 34 | $objectArrayFactory = $this->getMockBuilder(ObjectArrayFactory::class) 35 | ->disableOriginalConstructor() 36 | ->getMock(); 37 | $htmlObjectArray = $this->getMockBuilder(ObjectArray::class) 38 | ->setConstructorArgs( 39 | [ 40 | 'type' => HtmlInterface::class 41 | ] 42 | ) 43 | ->setMethods(null) 44 | ->getMock(); 45 | $objectArrayFactory->expects($this->once()) 46 | ->method('create') 47 | ->with(HtmlInterface::class) 48 | ->willReturn($htmlObjectArray); 49 | /** @var PHPUnit_Framework_MockObject_MockObject|ObjectArray $urls */ 50 | $urls = $this->getMockBuilder(ObjectArray::class) 51 | ->setConstructorArgs( 52 | [ 53 | 'type' => UrlInterface::class, 54 | 'objects' => [ 55 | new Url('') 56 | ] 57 | ] 58 | ) 59 | ->setMethods(null) 60 | ->getMock(); 61 | 62 | /** @var PHPUnit_Framework_MockObject_MockObject|SynchronousClient $runner */ 63 | $runner = $this->getMockBuilder(SynchronousClient::class) 64 | ->setConstructorArgs( 65 | [ 66 | 'objectArrayFactory' => $objectArrayFactory 67 | ] 68 | ) 69 | ->setMethods(['fileGetContentsWrapper']) 70 | ->getMock(); 71 | $runner->expects($this->once()) 72 | ->method('fileGetContentsWrapper') 73 | ->willReturn(''); 74 | 75 | $result = $runner->getContent($urls); 76 | $this->assertEquals(1, $result->count()); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Test/Unit/Standalone/Http/UrlProviderTest.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (C) 2018 Lizard Media (http://lizardmedia.pl) 9 | */ 10 | 11 | namespace MSlwk\ReactPhpPlayground\Test\Unit\Standalone\Http; 12 | 13 | use MSlwk\ReactPhpPlayground\Api\Data\UrlInterface; 14 | use MSlwk\ReactPhpPlayground\Standalone\Http\UrlProvider; 15 | use MSlwk\TypeSafeArray\ObjectArray; 16 | use MSlwk\TypeSafeArray\ObjectArrayFactory; 17 | use PHPUnit\Framework\TestCase; 18 | use PHPUnit_Framework_MockObject_MockObject; 19 | 20 | /** 21 | * Class UrlProviderTest 22 | * @package MSlwk\ReactPhpPlayground\Test\Unit\Standalone\Http 23 | */ 24 | class UrlProviderTest extends TestCase 25 | { 26 | /** 27 | * @test 28 | */ 29 | public function testGetUrls() 30 | { 31 | /** @var PHPUnit_Framework_MockObject_MockObject|ObjectArrayFactory $objectArrayFactory */ 32 | $objectArrayFactory = $this->getMockBuilder(ObjectArrayFactory::class) 33 | ->disableOriginalConstructor() 34 | ->getMock(); 35 | $urlProvider = new UrlProvider($objectArrayFactory); 36 | 37 | $objectArray = $this->getMockBuilder(ObjectArray::class) 38 | ->setConstructorArgs( 39 | [ 40 | 'type' => UrlInterface::class 41 | ] 42 | ) 43 | ->setMethods(null) 44 | ->getMock(); 45 | 46 | $objectArrayFactory->expects($this->once()) 47 | ->method('create') 48 | ->willReturn($objectArray); 49 | 50 | $result = $urlProvider->getUrls(); 51 | 52 | $this->assertInstanceOf(ObjectArray::class, $result); 53 | $this->assertEquals(6, $result->count()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mslwk/module-reactphp-playground", 3 | "description": "ReactPHP playground module for Magento 2", 4 | "type": "magento2-module", 5 | "version": "1.0.0", 6 | "license": [ 7 | "MIT" 8 | ], 9 | "authors": [ 10 | { 11 | "name": "Maciej Sławik", 12 | "email": "maciekslawik@gmail.com" 13 | } 14 | ], 15 | "require": { 16 | "php": "^7.1.0", 17 | "magento/framework": ">=101.0.0", 18 | "magento/module-store": ">=100.0.0", 19 | "mslwk/php-typesafe-array": "^1.0", 20 | "react/http-client": "^0.5.9", 21 | "react/child-process": "^0.5.2" 22 | }, 23 | "require-dev": { 24 | "phpunit/phpunit": ">=7.0.0" 25 | }, 26 | "repositories": [ 27 | { 28 | "type": "composer", 29 | "url": "https://repo.magento.com/" 30 | } 31 | ], 32 | "autoload": { 33 | "files": [ 34 | "registration.php" 35 | ], 36 | "psr-4": { 37 | "MSlwk\\ReactPhpPlayground\\": "" 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /docs/magento_cli_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maciejslawik/reactphp-playground-magento2/9b637230792513b8fc01638f0629e9b3f19a25db/docs/magento_cli_1.png -------------------------------------------------------------------------------- /docs/magento_cli_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maciejslawik/reactphp-playground-magento2/9b637230792513b8fc01638f0629e9b3f19a25db/docs/magento_cli_3.png -------------------------------------------------------------------------------- /docs/standalone_cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maciejslawik/reactphp-playground-magento2/9b637230792513b8fc01638f0629e9b3f19a25db/docs/standalone_cli.png -------------------------------------------------------------------------------- /etc/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 11 | 13 | 15 | 17 | 19 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | MSlwk\ReactPhpPlayground\Console\Command\GenerateReports 33 | MSlwk\ReactPhpPlayground\Console\Command\StartCliReportingService 35 | MSlwk\ReactPhpPlayground\Console\Command\StartWebapiReportingService 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Magento\Store\Model\StoreManagerInterface\Proxy 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /etc/webapi.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /registration.php: -------------------------------------------------------------------------------- 1 | 6 | * Github: https://github.com/maciejslawik 7 | */ 8 | \Magento\Framework\Component\ComponentRegistrar::register( 9 | \Magento\Framework\Component\ComponentRegistrar::MODULE, 10 | 'MSlwk_ReactPhpPlayground', 11 | __DIR__ 12 | ); 13 | --------------------------------------------------------------------------------