commit edca706fa6062881f7efa3048be58c6edd4be59b Author: ionHaze Date: Thu Dec 26 17:47:33 2019 +0300 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..65fc6d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/*.sublime* +/vendor \ No newline at end of file diff --git a/Command/StatusesCommand.php b/Command/StatusesCommand.php new file mode 100644 index 0000000..6918af9 --- /dev/null +++ b/Command/StatusesCommand.php @@ -0,0 +1,90 @@ +setName('statuses:update') + ->setDescription('Update statuses') + ->addArgument('accountId', InputArgument::OPTIONAL, 'Choose account, or make it for all'); + } + + public function __construct(EntityManagerInterface $em, ModuleManager $moduleManager) + { + $this->em = $em; + $this->moduleManager = $moduleManager; + + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + if (!$this->lock()) { + $output->writeln('The command is already running in another process.'); + + return 0; + } + + $accountId = $input->getArgument('accountId') + ? (int) $input->getArgument('accountId') + : null; + + $paginator = []; + if (null !== $accountId) { + $paginator = [$this->em->getRepository($this->getConnectionClass())->find($accountId)]; + } else { + $accountQuery = $this->em->createQuery(' + SELECT account + FROM ' . Account::class . ' account + WHERE + account.isActive = true + AND account.isFreeze != true + ') + ->setFirstResult(0) + ->setMaxResults(100); + $paginator = new Paginator($accountQuery); + } + + $count = 0; + foreach ($paginator as $account) { + try { + $count += $this->moduleManager + ->setAccount($account) + ->updateStatuses() + ; + } catch (\Exception $e) { + $output->writeln( + "Failed to update statuses for account {$account->getCrmUrl()}[{$account->getId()}]" + ); + $output->writeln("Error: {$e->getMessage()}"); + } + } + + $output->writeln(" {$count} statuses updated."); + + $this->release(); + } +} diff --git a/Command/UpdateModuleConfigurationCommand.php b/Command/UpdateModuleConfigurationCommand.php new file mode 100644 index 0000000..37f38b6 --- /dev/null +++ b/Command/UpdateModuleConfigurationCommand.php @@ -0,0 +1,91 @@ +setName('configuration:update') + ->setDescription('Update module configuration') + ->addArgument('accountId', InputArgument::OPTIONAL, 'Choose account, or make it for all'); + } + + public function __construct(EntityManagerInterface $em, ModuleManager $manager) + { + $this->em = $em; + $this->manager = $manager; + + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + if (!$this->lock()) { + $output->writeln('The command is already running in another process.'); + + return 0; + } + + $accountId = $input->getArgument('accountId') + ? (int) $input->getArgument('accountId') + : null; + + $paginator = []; + if (null !== $accountId) { + $paginator = [$this->em->getRepository($this->getConnectionClass())->find($accountId)]; + } else { + $accountQuery = $this->em->createQuery(' + SELECT account + FROM ' . Account::class . ' account + WHERE + account.isActive = true + AND account.isFreeze != true + ') + ->setFirstResult(0) + ->setMaxResults(100); + $paginator = new Paginator($accountQuery); + } + + $count = 0; + foreach ($paginator as $account) { + try { + $this->manager + ->setAccount($account) + ->updateModuleConfiguration() + ; + ++$count; + } catch (\Exception $e) { + $output->writeln( + "Failed to update configuration for account {$account->getCrmUrl()}[{$account->getId()}]" + ); + $output->writeln("Error: {$e->getMessage()}"); + } + } + + $output->writeln(" {$count} modules updated."); + + $this->release(); + } +} diff --git a/Controller/AdminController.php b/Controller/AdminController.php new file mode 100644 index 0000000..42a8a4f --- /dev/null +++ b/Controller/AdminController.php @@ -0,0 +1,414 @@ +entityManager = $entityManager; + $this->knpPaginator = $knpPaginator; + $this->openSsl = $openSsl; + $this->flashBag = $flashBag; + } + + /** + * @return string + */ + private function getShortBundle() + { + return strtr('Intaro\DeliveryModuleBundle', ['\\' => '']); + } + + /** + * @return string + */ + private function getNameService() + { + $bundle = explode('\\', 'Intaro\DeliveryModuleBundle'); + + return strtr(end($bundle), ['Bundle' => '']); + } + + /** + * @param Request $request + * + * @return Response + */ + public function listAction(Request $request) + { + $clientsQuery = $this->entityManager->createQuery(' + SELECT connection + FROM ' . $this->getConnectionClass() . ' connection + '); + + $pagination = $this->knpPaginator->paginate( + $clientsQuery, + $request->query->getInt('page', 1), + 20 + ); + + return $this->render( + $this->getShortBundle() . ':Connection:list.html.twig', + ['pagination' => $pagination, 'route' => $this->getRoute()] + ); + } + + /** + * @param Request $request + * + * @return Response + */ + public function newAction(Request $request) + { + $this->denyAccessUnlessGranted('ROLE_DEVELOPER'); + + $connectionClass = $this->getConnectionClass(); + $connection = new $connectionClass(); + $connection->setEncoder($this->openSsl); + $connectionTypeClass = 'Intaro\DeliveryModuleBundle\Form\ConnectionType'; + $form = $this->createForm($connectionTypeClass, $connection, [ + 'container' => $this->container, + 'is_admin' => true, + ]); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $connection->generateClientId(); + $this->actualizeWebhooks($connection); + $this->entityManager->persist($connection); + $this->entityManager->flush(); + + return $this->redirectToRoute($this->getRoute() . '_admin_edit', [ + 'connectionId' => $connection->getId(), + ]); + } + + return $this->render( + $this->getShortBundle() . ':Connection:edit.html.twig', + ['route' => $this->getRoute(), 'form' => $form->createView()] + ); + } + + /** + * @param Request $request + * @param string $connectionId + * + * @return Response + */ + public function editAction(Request $request, $connectionId) + { + $connection = $this->entityManager + ->getRepository($this->getConnectionClass()) + ->find($connectionId); + if (null === $connection) { + throw $this->createNotFoundException(); + } + + $connectionTypeClass = 'Intaro\DeliveryModuleBundle\Form\ConnectionType'; + $form = $this->createForm($connectionTypeClass, $connection, [ + 'container' => $this->container, + 'is_admin' => true, + ]); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->actualizeWebhooks($connection); + $this->entityManager->flush(); + + return $this->redirectToRoute($this->getRoute() . '_admin_edit', [ + 'connectionId' => $connection->getId(), + ]); + } + + return $this->render( + $this->getShortBundle() . ':Connection:edit.html.twig', + [ + 'route' => $this->getRoute(), + 'connection' => $connection, + 'form' => $form->createView(), + ] + ); + } + + /** + * @param Request $request + * @param string $connectionId + * + * @return Response + * + * @throws \Exception + */ + public function updateConfigurationAction(Request $request, $connectionId) + { + $this->denyAccessUnlessGranted('ROLE_DEVELOPER'); + + $api = $this->getDeliveryApi(); + + $connection = $this->entityManager + ->getRepository($this->getConnectionClass()) + ->find($connectionId); + + $api->setConnection($connection); + $result = $api->updateConfiguration(); + + if (isset($result['success']) && $result['success']) { + $this->flashBag->add('notice', 'ChangesWereSaved'); + } else { + $this->flashBag->add('error', 'ChangesWereNotSaved'); + } + + return $this->redirectToRoute($this->getRoute() . '_admin_edit', [ + 'connectionId' => $connection->getId(), + ]); + } + + /** + * @param Request $request + * + * @return Response + */ + public function parcelListAction(Request $request) + { + $parcelsQuery = $this->entityManager->createQuery(' + SELECT parcel + FROM ' . $this->getParcelClass() . ' parcel + '); + + $pagination = $this->knpPaginator->paginate( + $parcelsQuery, + $request->query->getInt('page', 1), + 20 + ); + + return $this->render( + $this->getShortBundle() . ':Parcel:list.html.twig', + ['route' => $this->getRoute(), 'pagination' => $pagination] + ); + } + + /** + * @param Request $request + * + * @return Response + */ + public function parcelNewAction(Request $request) + { + $this->denyAccessUnlessGranted('ROLE_DEVELOPER'); + + $parcelClass = $this->getParcelClass(); + $parcel = new $parcelClass(); + $parcelTypeClass = 'Intaro\DeliveryModuleBundle\Form\ParcelType'; + $form = $this->createForm($parcelTypeClass, $parcel, [ + 'connection_class' => $this->getConnectionClass(), + ]); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->entityManager->persist($parcel); + $this->entityManager->flush(); + + return $this->redirectToRoute($this->getRoute() . '_admin_parcel_list'); + } + + return $this->render( + $this->getShortBundle() . ':Parcel:edit.html.twig', + ['form' => $form->createView(), 'parcel' => $parcel] + ); + } + + /** + * @param Request $request + * @param string $parcelId + * + * @return Response + */ + public function parcelEditAction(Request $request, $parcelId) + { + $parcel = $this->entityManager + ->getRepository($this->getParcelClass()) + ->find(['id' => $parcelId]); + + $parcelTypeClass = 'Intaro\DeliveryModuleBundle\Form\ParcelType'; + $form = $this->createForm($parcelTypeClass, $parcel, [ + 'connection_class' => $this->getConnectionClass(), + ]); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->entityManager->flush(); + + return $this->redirectToRoute($this->getRoute() . '_admin_parcel_list'); + } + + return $this->render( + $this->getShortBundle() . ':Parcel:edit.html.twig', + ['form' => $form->createView(), 'parcel' => $parcel] + ); + } + + /** + * @param Request $request + * + * @return Response + * + * @throws \Exception + */ + public function connectAction(Request $request) + { + $api = $this->getDeliveryApi(); + + $referer = $request->headers->get('referer'); + $account = $request->query->get('account'); + $accountUrl = null; + if (!empty($account)) { + $accountUrl = null === parse_url($account, PHP_URL_HOST) + ? null : 'https://' . parse_url($account, PHP_URL_HOST); + } + + if ( + !empty($request->request->get('clientId')) + || !empty($request->attributes->get('clientId')) + ) { + if (!empty($request->request->get('clientId'))) { + $clientId = $request->request->get('clientId'); + } else { + $clientId = $request->attributes->get('clientId'); + } + + $connection = $this->entityManager + ->getRepository($this->getConnectionClass()) + ->findOneBy([ + 'clientId' => $clientId, + ]); + $accountUrl = $connection->getCrmUrl(); + } else { + $class = $this->getConnectionClass(); + $connection = new $class(); + $connection + ->setLanguage($request->getLocale()) + ->setEncoder($this->openSsl); + } + + $connectionTypeClass = 'Intaro\DeliveryModuleBundle\Form\ConnectionType'; + $form = $this->createForm($connectionTypeClass, $connection, [ + 'container' => $this->container, + 'is_admin' => false, + ]); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $connectionIsCreated = true; + if (empty($connection->getClientId())) { + $connection->generateClientId(); + $connectionIsCreated = false; + } + + $api->setConnection($connection); + $this->actualizeWebhooks($connection); + $result = $api->updateConfiguration(); + if (isset($result['success']) && $result['success']) { + if (!$connectionIsCreated) { + $this->entityManager->persist($connection); + } + $this->entityManager->flush(); + + return $this->redirect($connection->getCrmUrl() . '/admin/integration/list'); + } else { + $srcLogo = $request->getUriForPath( + '/bundles/delivery' + . strtolower($this->getNameService()) + . '/images/' + . strtolower($this->getNameService()) + . '.svg' + ); + + return $this->render( + 'DeliveryCoreBundle:Connection:configure_error.html.twig', + [ + 'referer' => $referer, + 'errors' => $result, + 'title_delivery' => $this->getNameService(), + 'src_logo_delivery' => $srcLogo, + ] + ); + } + } + + return $this->render( + $this->getShortBundle() . ':Connection:configure.html.twig', + [ + 'route' => $this->getRoute(), + 'form' => $form->createView(), + 'account' => $accountUrl, + ] + ); + } + + /** + * Actualize webhooks + * + * @param Connection $connection + */ + protected function actualizeWebhooks(Connection $connection) + { + } +} diff --git a/Controller/ApiController.php b/Controller/ApiController.php new file mode 100644 index 0000000..026ca20 --- /dev/null +++ b/Controller/ApiController.php @@ -0,0 +1,458 @@ +entityManager = $entityManager; + $this->jmsSerializer = $jmsSerializer; + $this->moduleManager = $moduleManager; + $this->deliveryOrderManager = $deliveryOrderManager; + + $request = $requestStack->getCurrentRequest(); + if ($request->isMethod('post')) { + $clientId = $request->request->get('clientId'); + } else { + $clientId = $request->query->get('clientId'); + } + + $account = $entityManager->getRepository(Account::class) + ->findOneBy(['id' => $clientId]); + if (null === $account) { + return $this->getInvalidResponse('ClientId not found', 404); + } + + $this->moduleManager->setAccount($account); + } + + public function activityAction(Request $request): JsonResponse + { + $activity = $request->request->get('activity'); + + try { + $requestModel = $this->jmsSerializer->deserialize( + $activity, + IntegrationModule::class, + 'json', + DeserializationContext::create()->setGroups(['activity']) + ); + } catch (JmsException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } + + $this->account->setActive($requestModel->active); + $this->account->setFreeze($requestModel->freeze); + + $systemUrl = $request->request->get('systemUrl'); + $this->account->setCrmUrl($systemUrl); + + $this->entityManager->flush(); + + return $this->getSucessfullResponse(); + } + + public function calculateAction(Request $request): JsonResponse + { + if ( + false === $this->moduleManager->getAccount()->getIsActive() + || false !== $this->moduleManager->getAccount()->getIsFreeze() + ) { + return $this->getInvalidResponse('Account is not active', 403); + } + + $requestData = $request->request->get('calculate'); + try { + $requestModel = $this->jmsSerializer->deserialize( + $requestData, + RequestCalculate::class, + 'json', + DeserializationContext::create()->setGroups(['get', 'request']) + ); + } catch (JmsException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } + + try { + $responseModel = $this->doCalculate($requestModel); + } catch (Exception\ValidationException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } catch (Exception\ApiException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } + + return $this->getSucessfullResponse($responseModel); + } + + public function saveAction(Request $request): JsonResponse + { + if ( + false === $this->moduleManager->getAccount()->getIsActive() + || false !== $this->moduleManager->getAccount()->getIsFreeze() + ) { + return $this->getInvalidResponse('Account is not active', 403); + } + + $requestData = $request->request->get('save'); + try { + $requestModel = $this->jmsSerializer->deserialize( + $requestData, + RequestSave::class, + 'json', + DeserializationContext::create()->setGroups(['get', 'request']) + ); + } catch (JmsException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } + + $delivery = $this->deliveryOrderManager->findOneBy([ + 'account' => $this->account, + 'orderId' => $requestModel->order, + ]); + + // ищем доставки, созданные без заказа в запросе get + if (null === $delivery) { + $parcel = $this->deliveryOrderManager + ->findOneBy(['account' => $this->account, 'trackId' => $requestModel->deliveryId]); + } + + try { + $responseModel = $this->doSave($requestModel, $delivery); + } catch (Exception\ValidationException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } catch (Exception\ApiException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } catch (\InvalidArgumentException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } + + if (null === $delivery) { + $deliveryClass = $this->deliveryOrderManager->create(); + $delivery = new $deliveryClass(); + } + + $delivery + ->setAccount($this->moduleManager->getAccount()) + ->setOrderId($requestModel->order) + ->setExternalId($responseModel->deliveryId) + ->setTrackNumber($responseModel->trackNumber) + ; + + if (is_array($responseModel->additionalData)) { + foreach ($responseModel->additionalData as $key => $value) { + $setter = 'set' . ucfirst($key); + if (is_callable([$delivery, $setter])) { + $delivery->$setter($value); + } + } + } + + if (empty($delivery->getId())) { + $this->entityManager->persist($delivery); + } + $this->entityManager->flush(); + + return $this->getSucessfullResponse($responseModel); + } + + public function getAction(Request $request): JsonResponse + { + if ( + false === $this->moduleManager->getAccount()->getIsActive() + || false !== $this->moduleManager->getAccount()->getIsFreeze() + ) { + return $this->getInvalidResponse('Account is not active', 403); + } + + $externalId = $request->query->get('deliveryId'); + if (null === $externalId || empty($externalId)) { + return $this->getInvalidResponse('DeliveryId is required', 400); + } + + try { + $responseModel = $this->doGet($externalId); + } catch (Exception\ValidationException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } catch (Exception\ApiException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } + + return $this->getSucessfullResponse($responseModel); + } + + public function deleteAction(Request $request): JsonResponse + { + if ( + false === $this->moduleManager->getAccount()->getIsActive() + || false !== $this->moduleManager->getAccount()->getIsFreeze() + ) { + return $this->getInvalidResponse('Account is not active', 403); + } + + $requestData = $request->request->get('delete'); + try { + $requestModel = $this->jmsSerializer->deserialize( + $requestData, + RequestDelete::class, + 'json', + DeserializationContext::create()->setGroups(['get', 'request']) + ); + } catch (JmsException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } + + $delivery = $this->deliveryOrderManager->findOneBy([ + 'account' => $this->account, + 'externalId' => $requestModel->deliveryId, + ]); + + if (null === $delivery) { + return $this->getInvalidResponse("Delivery {$requestModel->deliveryId} not found", 404); + } + + try { + $this->doDelete($requestModel, $delivery); + } catch (Exception\ValidationException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } catch (Exception\ApiException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } + + $this->entityManager->remove($delivery); + $this->entityManager->flush(); + + return $this->getSucessfullResponse(); + } + + public function printAction(Request $request): Response + { + if ( + false === $this->moduleManager->getAccount()->getIsActive() + || false !== $this->moduleManager->getAccount()->getIsFreeze() + ) { + return $this->getInvalidResponse('Account is not active', 403); + } + + $requestData = $request->request->get('print'); + try { + $requestModel = $this->jmsSerializer->deserialize( + $requestData, + RequestPrint::class, + 'json', + DeserializationContext::create()->setGroups(['get', 'request']) + ); + } catch (JmsException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } + + try { + $plateData = $this->doPrint($requestModel); + } catch (Exception\ValidationException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } catch (Exception\ApiException $e) { + return $this->getInvalidResponse($e->getMessage(), 500); + } + + if (is_array($plateData)) { + $tmpFilename = tempnam(sys_get_temp_dir(), 'zip'); + $labelArchive = new \ZipArchive(); + $labelArchive->open($tmpFilename, \ZipArchive::CREATE); + foreach ($plateData as $fileName => $plate) { + $labelArchive->addFromString($fileName, $plate); + } + $labelArchive->close(); + $contents = file_get_contents($tmpFilename); + unlink($tmpFilename); + + $response = new Response($contents); + $response->headers->set('Content-Type', 'application/zip'); + } else { + $response = new Response($plateData); + $response->headers->set('Content-Type', 'application/pdf'); + } + + return $response; + } + + public function shipmentSaveAction(Request $request): JsonResponse + { + if ( + false === $this->moduleManager->getAccount()->getIsActive() + || false !== $this->moduleManager->getAccount()->getIsFreeze() + ) { + return $this->getInvalidResponse('Account is not active', 403); + } + + $requestData = $request->request->get('shipmentSave'); + try { + $requestModel = $this->jmsSerializer->deserialize( + $requestData, + RequestShipmentSave::class, + 'json', + DeserializationContext::create()->setGroups(['get', 'request']) + ); + } catch (JmsException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } + + try { + $responseModel = $this->doShipmentSave($requestModel); + } catch (Exception\ValidationException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } catch (Exception\ApiException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } catch (\InvalidArgumentException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } + + return $this->getSucessfullResponse($responseModel); + } + + public function shipmentDeleteAction(Request $request): JsonResponse + { + if ( + false === $this->moduleManager->getAccount()->getIsActive() + || false !== $this->moduleManager->getAccount()->getIsFreeze() + ) { + return $this->getInvalidResponse('Account is not active', 403); + } + + $requestData = $request->request->get('shipmentDelete'); + try { + $requestModel = $this->jmsSerializer->deserialize( + $requestData, + RequestShipmentDelete::class, + 'json', + DeserializationContext::create()->setGroups(['get', 'request']) + ); + } catch (JmsException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } + + try { + $this->doShipmentDelete($requestModel); + } catch (Exception\ValidationException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } catch (Exception\ApiException $e) { + return $this->getInvalidResponse($e->getMessage(), 400); + } + + return $this->getSucessfullResponse(); + } + + protected function getSucessfullResponse($responseResult = null): JsonResponse + { + if (is_array($responseResult)) { + $response = new ResponseCalculateSuccessful(); + } else { + $response = new ResponseSuccessful(); + } + $response->result = $responseResult; + + $responseData = $this->jmsSerializer + ->serialize($response, 'json', SerializationContext::create()->setGroups(['response'])); + + return new JsonResponse(json_decode($responseData, true)); + } + + protected function getInvalidResponse(string $message, int $statusCode): JsonResponse + { + if ($statusCode >= 500) { + //корректно отдается в crm только в окружении prod + throw new SymfonyException\HttpException( + $statusCode, + json_encode(['success' => false, 'errorMsg' => $message]) + ); + } + + return new JsonResponse([ + 'success' => false, + 'errorMsg' => $message, + ], $statusCode); + } + + protected function doCalculate(RequestCalculate $requestModel): ResponseCalculate + { + return $this->moduleManager->calculateDelivery($requestModel); + } + + protected function doGet(string $externalId): ResponseLoadDeliveryData + { + return $this->moduleManager->getDelivery($externalId); + } + + protected function doSave(RequestSave $requestModel, DeliveryOrder $delivery = null): ResponseSave + { + return $this->moduleManager->saveDelivery($requestModel, $delivery); + } + + protected function doDelete(RequestDelete $requestModel, DeliveryOrder $delivery): bool + { + return $this->moduleManager->deleteDelivery($requestModel, $delivery); + } + + protected function doShipmentSave(RequestShipmentSave $requestModel): ResponseShipmentSave + { + return $this->moduleManager->saveShipment($requestModel); + } + + protected function doShipmentDelete(RequestShipmentDelete $requestModel): bool + { + return $this->moduleManager->deleteShipment($requestModel); + } + + protected function doPrint(RequestPrint $requestModel) + { + return $this->moduleManager->printDocument($requestModel); + } +} diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php new file mode 100644 index 0000000..d3c1855 --- /dev/null +++ b/DependencyInjection/Configuration.php @@ -0,0 +1,55 @@ +root('retailcrm_delivery_module'); + + $rootNode + ->arrayNode('module') + ->scalarNode('integration_code') + ->isRequired() + ->end() + ->arrayNode('locales') + ->requiresAtLeastOneElement() + ->useAttributeAsKey('locale') + + ->prototype('array') + ->children() + ->scalarNode('name') + ->isRequired() + ->end() + ->scalarNode('logo') + ->isRequired() + ->end() + ->end() + ->end() + ->scalarNode('countries') + ->cannotBeEmpty() + ->defaultValue(['ru']) + ->end() + ->cannotBeEmpty() + ->end() + ->scalarNode('module_manager_class') + ->isRequired() + ->end() + ->scalarNode('delivery_order_class') + ->isRequired() + ->end() + ; + + return $treeBuilder; + } +} diff --git a/DependencyInjection/DeliveryCoreExtension.php b/DependencyInjection/DeliveryCoreExtension.php new file mode 100644 index 0000000..1a0226d --- /dev/null +++ b/DependencyInjection/DeliveryCoreExtension.php @@ -0,0 +1,44 @@ +load('services.xml'); + + $configuration = new Configuration(); + $config = $this->processConfiguration($configuration, $configs); + + $container->setParameter( + 'retailcrm.delivery_module.module_configuration', + $config['module'] + ); + $container->setParameter( + 'retailcrm.delivery_module.module_manager.class', + $config['module_manager_class'] + ); + $container->setParameter( + 'retailcrm.delivery_module.delivery_order.class', + $config['delivery_order_class'] + ); + } +} diff --git a/Entity/Account.php b/Entity/Account.php new file mode 100644 index 0000000..b034180 --- /dev/null +++ b/Entity/Account.php @@ -0,0 +1,174 @@ +") + */ + protected $createdAt; + + /** + * @var string + * + * @ORM\Column(name="crm_url", type="string", length=255, nullable=false) + * @Serializer\Groups({"get", "connect"}) + * @Serializer\Type("string") + */ + protected $crmUrl; + + /** + * @var string + * + * @ORM\Column(name="crm_api_key", type="string", length=255, nullable=false) + * @Serializer\Groups({"get", "connect"}) + * @Serializer\Type("string") + */ + protected $crmApiKey; + + /** + * @var bool + * + * @ORM\Column(name="active", type="boolean", options={"default"=true}) + */ + protected $active; + + /** + * @var bool + * + * @ORM\Column(name="freezed", type="boolean", options={"default"=false}) + */ + protected $freeze; + + /** + * @var string + * + * @ORM\Column(name="language", type="string", length=255, nullable=true) + */ + protected $language; + + public function __construct() + { + $this->id = Uuid::uuid4(); + $this->createdAt = new \DateTime(); + $this->active = false; + $this->freeze = false; + } + + public function getId(): UuidInterface + { + return $this->id; + } + + public function getCreatedAt(): \DateTime + { + return $this->createdAt; + } + + public function setCreatedAt(\DateTime $createdAt): self + { + $this->createdAt = $createdAt; + + return $this; + } + + public function getCrmUrl(): ?string + { + return $this->crmUrl; + } + + public function setCrmUrl(?string $crmUrl): self + { + $this->crmUrl = rtrim($crmUrl, '/'); + + return $this; + } + + public function getCrmApiKey(): ?string + { + return $this->crmApiKey; + } + + public function setCrmApiKey(?string $crmApiKey): self + { + $this->crmApiKey = $crmApiKey; + + return $this; + } + + public function setActive(bool $active): self + { + $this->active = $active; + + return $this; + } + + public function isActive(): bool + { + return $this->active; + } + + public function setFreeze(bool $freeze): self + { + $this->freeze = $freeze; + + return $this; + } + + public function isFreeze(): bool + { + return $this->freeze; + } + + /** + * @Serializer\VirtualProperty + * @Serializer\Type("boolean") + * @Serializer\Groups({"get"}) + * @Serializer\SerializedName("isEnabled") + */ + public function isEnabled(): bool + { + return !$this->freeze && $this->active; + } + + public function setLanguage(string $language): self + { + $this->language = $language; + + return $this; + } + + public function getLanguage(): ?string + { + return $this->language; + } +} diff --git a/Entity/DeliveryOrder.php b/Entity/DeliveryOrder.php new file mode 100644 index 0000000..9dee71d --- /dev/null +++ b/Entity/DeliveryOrder.php @@ -0,0 +1,117 @@ +ended = false; + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + public function setAccount(Account $account): self + { + $this->account = $account; + + return $this; + } + + public function getAccount(): ?Account + { + return $this->account; + } + + public function setOrderId(int $orderId): self + { + $this->orderId = $orderId; + + return $this; + } + + public function getOrderId(): int + { + return $this->orderId; + } + + public function setExternalId(string $externalId): self + { + $this->externalId = $externalId; + + return $this; + } + + public function getExternalId(): string + { + return $this->externalId; + } + + public function setEnded(bool $ended): self + { + $this->ended = $ended; + + return $this; + } + + public function getTrackNumber(): string + { + return $this->externalId; + } + + public function setTrackNumber(string $trackNumber): self + { + return $this; + } + + public function getEnded(): bool + { + return $this->ended; + } +} diff --git a/EventListener/SerializeListener.php b/EventListener/SerializeListener.php new file mode 100644 index 0000000..66f1c01 --- /dev/null +++ b/EventListener/SerializeListener.php @@ -0,0 +1,30 @@ + Events::PRE_SERIALIZE, 'method' => 'onPreSerialize', 'class' => ResponseResult::class], + ]; + } + + public function onPreSerialize(PreSerializeEvent $event) + { + if (is_object($event->getObject())) { + $event->setType(get_class($event->getObject())); + } else { + $event->setType('string'); + } + } +} diff --git a/Exception/AbstractException.php b/Exception/AbstractException.php new file mode 100644 index 0000000..e81c1c7 --- /dev/null +++ b/Exception/AbstractException.php @@ -0,0 +1,7 @@ +add('connectionId', null, [ + 'label' => 'label.connectionId', + 'required' => true, + 'attr' => [ + 'placeholder' => 'label.connectionId' + ] + ]) + ->add('crmKey', null, [ + 'label' => 'label.crmKey', + 'required' => true, + 'attr' => [ + 'placeholder' => 'label.crmKey' + ] + ]); + } +} diff --git a/Form/ConnectionType.php b/Form/ConnectionType.php new file mode 100644 index 0000000..cb38352 --- /dev/null +++ b/Form/ConnectionType.php @@ -0,0 +1,78 @@ +add('crmUrl', TextType::class, [ + 'label' => 'label.crmUrl', + 'required' => true, + 'attr' => [ + 'placeholder' => 'label.crmUrl', + 'pattern' => '^(https?:\/\/)?([\da-z0-9\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$', + ], + 'translation_domain' => 'messages' + ]) + ->add('crmKey', TextType::class, [ + 'label' => 'label.crmKey', + 'required' => true, + 'attr' => [ + 'placeholder' => 'label.crmKey' + ], + 'translation_domain' => 'messages' + ]) + ->add('isActive', CheckboxType::class, [ + 'label' => 'label.isActive', + 'required' => false, + 'translation_domain' => 'messages' + ]) + ->add('language', ChoiceType::class, [ + 'label' => 'label.language', + 'choices' => [ + 'RU' => 'ru', + 'EN' => 'en', + 'ES' => 'es' + ], + 'required' => true, + 'translation_domain' => 'messages' + ]) + ->add('isFreeze', CheckboxType::class, [ + 'label' => 'label.isFreeze', + 'required' => false, + 'translation_domain' => 'messages' + ]); + + if ($options['is_admin']) { + $builder + ->add('debug', CheckboxType::class, [ + 'label' => 'label.debug', + 'required' => false, + 'translation_domain' => 'messages' + ]); + } + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired(['container', 'is_admin']); + } +} diff --git a/Form/ParcelType.php b/Form/ParcelType.php new file mode 100644 index 0000000..5861f7a --- /dev/null +++ b/Form/ParcelType.php @@ -0,0 +1,63 @@ +add( + 'connection', + EntityType::class, + [ + 'class' => $options['connection_class'], + 'label' => 'label.connection', + 'translation_domain' => 'messages' + ] + ) + ->add( + 'orderId', + TextType::class, + [ + 'label' => 'label.orderId', + 'translation_domain' => 'messages' + ] + ) + ->add( + 'trackId', + TextType::class, + [ + 'label' => 'label.trackId', + 'translation_domain' => 'messages' + ] + ) + ->add( + 'isClosed', + CheckboxType::class, + [ + 'required' => false, + 'label' => 'label.isClosed', + 'translation_domain' => 'messages' + ] + ); + } + + /** + * {@inheritDoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired(['connection_class']); + } +} diff --git a/IntaroRetailCRMDeliveryModuleBundle.php b/IntaroRetailCRMDeliveryModuleBundle.php new file mode 100644 index 0000000..f069420 --- /dev/null +++ b/IntaroRetailCRMDeliveryModuleBundle.php @@ -0,0 +1,9 @@ +") + */ + public $actions; + + /** + * Допустивые типы плательщиков за доставку + * @var array + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("payerType") + * @Serializer\Type("array") + */ + public $payerType; + + /** + * Максимальное количество заказов при печати документов + * @var integer + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("platePrintLimit") + * @Serializer\Type("integer") + */ + public $platePrintLimit = 100; + + /** + * В методе calculate расчитывается стоимость доставки + * @var boolean + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("rateDeliveryCost") + * @Serializer\Type("boolean") + */ + public $rateDeliveryCost = true; + + /** + * Разрешить использование упаковок + * @var boolean + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("allowPackages") + * @Serializer\Type("boolean") + */ + public $allowPackages = false; + + /** + * Доставка наложенным платежом доступна/не доступна + * @var boolean + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("codAvailable") + * @Serializer\Type("boolean") + */ + public $codAvailable = false; + + /** + * Возможен самопривоз на терминал. + * @var boolean + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("selfShipmentAvailable") + * @Serializer\Type("boolean") + */ + public $selfShipmentAvailable = false; + + /** + * Разрешить отдельно передавать трек номер + * @var string + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("allowTrackNumber") + * @Serializer\Type("boolean") + */ + public $allowTrackNumber; + + /** + * Список стран откуда можно отправить посылку. Если массив пустой, то нет ограничения на страны + * @var array + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("availableCountries") + * @Serializer\Type("array") + */ + public $availableCountries; + + /** + * Список обязательных полей заказа + * @var array + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("requiredFields") + * @Serializer\Type("array") + */ + public $requiredFields; + + /** + * Список статусов службы доставки + * @var Status[] + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("statusList") + * @Serializer\Type("array") + */ + public $statusList; + + /** + * Список печатных форм, предоставляемых службой + * @var Plate[] + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("plateList") + * @Serializer\Type("array") + */ + public $plateList; + + /** + * Список дополнительных полей, необходимых для оформления доставки + * @var DeliveryDataField[] + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("deliveryDataFieldList") + * @Serializer\Type("array") + */ + public $deliveryDataFieldList; + + /** + * Список дополнительных полей, необходимых для заявки на отгрузку + * @var DeliveryDataField[] + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("shipmentDataFieldList") + * @Serializer\Type("array") + */ + public $shipmentDataFieldList; +} diff --git a/Model/Coordinates.php b/Model/Coordinates.php new file mode 100644 index 0000000..aea4842 --- /dev/null +++ b/Model/Coordinates.php @@ -0,0 +1,28 @@ +") + */ + public $phones; + + /** + * E-mail + * @var string + * + * @Serializer\Groups({"get"}) + * @Serializer\SerializedName("email") + * @Serializer\Type("string") + */ + public $email; +} diff --git a/Model/DeliveryAddress.php b/Model/DeliveryAddress.php new file mode 100644 index 0000000..1bf45cc --- /dev/null +++ b/Model/DeliveryAddress.php @@ -0,0 +1,249 @@ +") + * @Serializer\Groups({"set", "get", "orderHistory", "history-reference", "calculate"}) + * @Serializer\Accessor(getter="getFrom", setter="setFrom") + * + * @var \DateTime|null + */ + protected $from; + + /** + * Время доставки "до" + * + * @Serializer\SerializedName("to") + * @Serializer\Type("DateTime<'H:i'>") + * @Serializer\Groups({"set", "get", "orderHistory", "history-reference", "calculate"}) + * @Serializer\Accessor(getter="getTo", setter="setTo") + * + * @var \DateTime|null + */ + protected $to; + + /** + * Время доставки (произвольный текст) + * + * @Serializer\SerializedName("custom") + * @Serializer\Type("string") + * @Serializer\Groups({"set", "get", "orderHistory", "history-reference", "calculate"}) + * + * @var string|null + */ + protected $custom; + + /** + * @param null|string|\DateTime $from + * @param null|string|\DateTime $to + * @param null|string $custom + * + * @return self + */ + public function __construct($from = null, $to = null, $custom = null) + { + $this->setFrom($from); + $this->setTo($to); + $this->setCustom($custom); + } + + /** + * Разбор строки со временем доставки + * + * @param string $time + * + * @return self + */ + public static function fromString($time) + { + $result = new self(); + $result->setString($time); + + return $result; + } + + /** + * @return \DateTime|null + */ + public function getFrom() + { + if ($this->from) { + $this->from->setDate(1970, 01, 01); + + if ('00:00:00' === $this->from->format('H:i:s')) { + return null; + } + } + + return $this->from; + } + + /** + * @param \DateTime|string|null $from + * + * @return $this + */ + public function setFrom($from) + { + $this->from = $this->ensureTime($from); + $this->ensureConsistency(); + + return $this; + } + + /** + * @return \DateTime|null + */ + public function getTo() + { + if ($this->to) { + $this->to->setDate(1970, 01, 01); + + if ('23:59:59' === $this->to->format('H:i:s')) { + return null; + } + } + + return $this->to; + } + + /** + * @param \DateTime|string|null $to + * + * @return $this + */ + public function setTo($to) + { + $this->to = $this->ensureTime($to); + $this->ensureConsistency(); + + return $this; + } + + /** + * @return string + */ + public function getCustom() + { + return $this->custom; + } + + /** + * @param string $custom + * + * @return $this + */ + public function setCustom($custom) + { + $this->custom = $custom; + + return $this; + } + + /** + * @param string $time + * + * @return $this + */ + public function setString($time) + { + // точное время: 12.30, 12:30 + $exactPattern = '/^в?\s*(\d{2}[:\.]\d{2})$/u'; + // диапазон времени: 12-13, c 12.00 по 13:00 + $rangePattern = '/^с?\s*(?P\d{2}[:\.]?\d{0,2})\s*(-|по|до)\s*(?P\d{2}[:\.]?\d{0,2})/u'; + // диапазон времени: c 12.00 + $rangeFromPattern = '/^с?\s*(?P\d{2}[:\.]?\d{0,2})/u'; + // диапазон времени: до 13:00 + $rangeToPattern = '/^(-|по|до)\s*(?P\d{2}[:\.]?\d{0,2})/u'; + + if (preg_match($exactPattern, $time, $matches)) { + $timeObj = new \DateTime($matches[1]); + $this->setFrom(clone $timeObj); + $this->setTo(clone $timeObj); + } elseif (preg_match($rangePattern, $time, $matches)) { + $from = $matches['from']; + $to = $matches['to']; + + $from = preg_match($exactPattern, $from) ? $from : $from . ':00'; + $to = preg_match($exactPattern, $to) ? $to : $to . ':00'; + + try { + $this->setFrom(new \DateTime($from)); + $this->setTo(new \DateTime($to)); + } catch (\Exception $e) { + $this->setFrom(null); + $this->setTo(null); + $this->setCustom($time); + } + } elseif (preg_match($rangeFromPattern, $time, $matches)) { + $from = $matches['from']; + $from = preg_match($exactPattern, $from) ? $from : $from . ':00'; + + try { + $this->setFrom(new \DateTime($from)); + $this->setTo(null); + } catch (\Exception $e) { + $this->setFrom(null); + $this->setTo(null); + $this->setCustom($time); + } + } elseif (preg_match($rangeToPattern, $time, $matches)) { + $to = $matches['to']; + $to = preg_match($exactPattern, $to) ? $to : $to . ':00'; + + try { + $this->setFrom(null); + $this->setTo(new \DateTime($to)); + } catch (\Exception $e) { + $this->setFrom(null); + $this->setTo(null); + $this->setCustom($time); + } + } else { + $this->setFrom(null); + $this->setTo(null); + $this->setCustom($time); + } + + return $this; + } + + /** + * @return string + */ + public function getString() + { + $from = $this->getFrom(); + $to = $this->getTo(); + $custom = $this->getCustom(); + + if (!($from || $to)) { + return (string) $custom; + } + + $fromPrint = $from ? $from->format('H:i') : null; + $toPrint = $to ? $to->format('H:i') : null; + + if ($fromPrint && $fromPrint === $toPrint) { + return 'в ' . $fromPrint; + } + + $str = ''; + if ($fromPrint) { + $str .= 'с ' . $fromPrint; + } + if ($toPrint) { + $str .= ' до ' . $toPrint; + } + + return trim($str); + } + + /** + * Проверяет, соответствует ли время доставки диапазону из настроек + * + * @param array $range + * @return bool + */ + public function equalsRange(array $range) + { + $fromEquals = false; + $toEquals = false; + + $from = $this->getFrom(); + $to = $this->getTo(); + + if ($from) { + if (isset($range['from'])) { + $fromEquals = $from->format('H:i') === $range['from']; + } + } else { + if (!isset($range['from']) || + !$range['from'] || + $range['from'] === '00:00' || + $range['from'] === '00:00:00' + ) { + $fromEquals = true; + } + } + + if ($to) { + if (isset($range['to'])) { + $toEquals = $to->format('H:i') === $range['to']; + } + } else { + if (!isset($range['to']) || + !$range['to'] || + $range['from'] === '23:59' || + $range['from'] === '23:59:59' + ) { + $toEquals = true; + } + } + + return $fromEquals && $toEquals; + } + + /** + * @return bool + */ + public function isEmpty() + { + return !($this->from || $this->to || $this->custom); + } + + /** + * @return string + */ + public function __toString() + { + return $this->getString(); + } + + protected function ensureTime($time) + { + if ($time) { + if (!$time instanceof \DateTime) { + $time = new \DateTime((string) $time); + } + $time->setDate(1970, 01, 01); + } + + return $time; + } + + /** + * Если для времени доставки указана только одна граница диапазона, то присвоим другой значение по умолчанию + */ + protected function ensureConsistency() + { + $from = $this->getFrom(); + $to = $this->getTo(); + + if ($from === null && $to !== null) { + $this->from = new \DateTime('1970-01-01T00:00:00'); + } elseif ($to === null && $from !== null) { + $this->to = new \DateTime('1970-01-01T23:59:59'); + } elseif ($to === null && $from === null) { + $this->to = null; + $this->from = null; + } + } +} diff --git a/Model/IntegrationConfiguration.php b/Model/IntegrationConfiguration.php new file mode 100644 index 0000000..0b514c5 --- /dev/null +++ b/Model/IntegrationConfiguration.php @@ -0,0 +1,128 @@ +") + */ + public $actions; + + /** + * Список стран для которых доступен модуль + * @var array + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("availableCountries") + * @Serializer\Type("array") + */ + public $availableCountries; + + /** + * URL настроек модуля + * @var string + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("accountUrl") + * @Serializer\Type("string") + */ + public $accountUrl; + + /** + * Массив конфигураций интеграций + * @var array + * + * @Serializer\Groups({"set", "get"}) + * @Serializer\SerializedName("integrations") + * @Serializer\Type("array") + */ + public $integrations; +} diff --git a/Model/Manager.php b/Model/Manager.php new file mode 100644 index 0000000..41bf3ec --- /dev/null +++ b/Model/Manager.php @@ -0,0 +1,68 @@ +") + */ + public $items; + + public function __construct($weight = null, $width = null, $length = null, $height = null) + { + $this->weight = $weight; + $this->width = $width; + $this->length = $length; + $this->height = $height; + } + + public function getVolume() + { + if (!is_null($this->length) + && !is_null($this->width) + && !is_null($this->height) + ) { + return $this->length * $this->width * $this->height; + } else { + return false; + } + } + + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata + ->addPropertyConstraint('weight', new Assert\NotBlank()); + } +} diff --git a/Model/PackageItem.php b/Model/PackageItem.php new file mode 100644 index 0000000..64dc505 --- /dev/null +++ b/Model/PackageItem.php @@ -0,0 +1,72 @@ +") + */ + public $properties; +} diff --git a/Model/Plate.php b/Model/Plate.php new file mode 100644 index 0000000..cb54045 --- /dev/null +++ b/Model/Plate.php @@ -0,0 +1,34 @@ +code = $code; + $this->label = $label; + } +} diff --git a/Model/RequestCalculate.php b/Model/RequestCalculate.php new file mode 100644 index 0000000..3e7e760 --- /dev/null +++ b/Model/RequestCalculate.php @@ -0,0 +1,117 @@ +") + */ + public $packages; + + /** + * Объявленная стоимость + * @var float + * + * @Serializer\Groups({"request", "calculate"}) + * @Serializer\SerializedName("declaredValue") + * @Serializer\Type("float") + */ + public $declaredValue; + + /** + * Наложенный платеж + * @var float + * + * @Serializer\Groups({"request", "calculate"}) + * @Serializer\SerializedName("cod") + * @Serializer\Type("float") + */ + public $cod; + + /** + * Плательщик за доставку + * @var string + * + * @Serializer\Groups({"request", "calculate"}) + * @Serializer\SerializedName("payerType") + * @Serializer\Type("string") + */ + public $payerType; + + /** + * Дата доставки + * @var \DateTime $deliveryDate + * + * @Serializer\Groups({"request", "calculate"}) + * @Serializer\SerializedName("deliveryDate") + * @Serializer\Type("DateTime<'Y-m-d'>") + */ + public $deliveryDate; + + /** + * Время доставки + * @var DeliveryTime $deliveryTime + * + * @Serializer\Groups({"request", "calculate"}) + * @Serializer\SerializedName("deliveryTime") + * @Serializer\Type("RetailCrm\DeliveryModuleBundle\Model\DeliveryTime") + */ + public $deliveryTime; + + /** + * Валюта + * @var string $currency + * + * @Serializer\Groups({"request", "calculate"}) + * @Serializer\SerializedName("currency") + * @Serializer\Type("string") + */ + public $currency; + + /** + * Дополнительные данные доставки + * @var array + * + * @Serializer\Groups({"request", "calculate"}) + * @Serializer\SerializedName("extraData") + * @Serializer\Type("array") + */ + public $extraData; +} diff --git a/Model/RequestDelete.php b/Model/RequestDelete.php new file mode 100644 index 0000000..69f8031 --- /dev/null +++ b/Model/RequestDelete.php @@ -0,0 +1,17 @@ +") + */ + public $packages; + + /** + * Данные доставки + * @var RetailCrm\DeliveryModuleBundle\Model\SaveDeliveryData + * + * @Serializer\Groups({"request"}) + * @Serializer\SerializedName("delivery") + * @Serializer\Type("RetailCrm\DeliveryModuleBundle\Model\SaveDeliveryData") + */ + public $delivery; + + /** + * Валюта + * @var string $currency + * + * @Serializer\Groups({"request", "calculate"}) + * @Serializer\SerializedName("currency") + * @Serializer\Type("string") + */ + public $currency; + + public function getFullDeclaredValue() + { + $result = 0; + foreach ($this->packages as $package) { + foreach ($package->items as $item) { + $result += $item->declaredValue * $item->quantity; + } + } + + return $result; + } + + public function getFullItemsCodValue() + { + $result = 0; + foreach ($this->packages as $package) { + foreach ($package->items as $item) { + $result += $item->cod * $item->quantity; + } + } + + return $result; + } +} diff --git a/Model/RequestShipmentDelete.php b/Model/RequestShipmentDelete.php new file mode 100644 index 0000000..95392bd --- /dev/null +++ b/Model/RequestShipmentDelete.php @@ -0,0 +1,28 @@ +") + */ + public $date; + + /** + * Время доставки ("custom" не ипользуется) + * @var RetailCrm\DeliveryModuleBundle\Model\DeliveryTime + * + * @Serializer\Groups({"get"}) + * @Serializer\SerializedName("time") + * @Serializer\Type("RetailCrm\DeliveryModuleBundle\Model\DeliveryTime") + */ + public $time; + + /** + * Адрес отгрузки + * @var string + * + * @Serializer\Groups({"get"}) + * @Serializer\SerializedName("address") + * @Serializer\Type("RetailCrm\DeliveryModuleBundle\Model\DeliveryAddress") + */ + public $address; + + /** + * Массив идентификаторов оформленных доставок в службе доставки + * @var array + * + * @Serializer\Groups({"get"}) + * @Serializer\SerializedName("orders") + * @Serializer\Type("array") + */ + public $orders; + + /** + * @var string + * + * @Serializer\Groups({"get"}) + * @Serializer\SerializedName("comment") + * @Serializer\Type("string") + */ + public $comment; + + /** + * Дополнительные данные отгрузки + * @var array + * + * @Serializer\Groups({"get"}) + * @Serializer\SerializedName("extraData") + * @Serializer\Type("array") + */ + public $extraData; +} diff --git a/Model/RequestStatusUpdateItem.php b/Model/RequestStatusUpdateItem.php new file mode 100644 index 0000000..350a018 --- /dev/null +++ b/Model/RequestStatusUpdateItem.php @@ -0,0 +1,53 @@ +") + */ + public $history; + + /** + * Массив дополнительных данных доставки + * @var array + * + * @Serializer\Groups({"request"}) + * @Serializer\SerializedName("extraData") + * @Serializer\Type("array") + */ + public $extraData; + + public function __construct() + { + $this->history = []; + } +} diff --git a/Model/ResponseAutocompleteItem.php b/Model/ResponseAutocompleteItem.php new file mode 100644 index 0000000..6aac639 --- /dev/null +++ b/Model/ResponseAutocompleteItem.php @@ -0,0 +1,42 @@ +value = $value; + $this->label = $label; + $this->description = $description; + } +} diff --git a/Model/ResponseAutocompleteSuccessful.php b/Model/ResponseAutocompleteSuccessful.php new file mode 100644 index 0000000..b8c3e17 --- /dev/null +++ b/Model/ResponseAutocompleteSuccessful.php @@ -0,0 +1,26 @@ +") + */ + public $result; +} diff --git a/Model/ResponseCalculate.php b/Model/ResponseCalculate.php new file mode 100644 index 0000000..c847adc --- /dev/null +++ b/Model/ResponseCalculate.php @@ -0,0 +1,126 @@ +") + */ + public $pickuppointList; + + public function __construct() + { + $this->extraData = []; + } +} diff --git a/Model/ResponseCalculateSuccessful.php b/Model/ResponseCalculateSuccessful.php new file mode 100644 index 0000000..d87206b --- /dev/null +++ b/Model/ResponseCalculateSuccessful.php @@ -0,0 +1,26 @@ +") + */ + public $result; +} diff --git a/Model/ResponseLoadDeliveryData.php b/Model/ResponseLoadDeliveryData.php new file mode 100644 index 0000000..ccca5f1 --- /dev/null +++ b/Model/ResponseLoadDeliveryData.php @@ -0,0 +1,138 @@ +") + */ + public $shipmentDate; + + /** + * Дата доставки + * @var string + * + * @Serializer\Groups({"response"}) + * @Serializer\SerializedName("deliveryDate") + * @Serializer\Type("DateTime<'Y-m-d'>") + */ + public $deliveryDate; + + /** + * Время доставки + * @var RetailCrm\DeliveryModuleBundle\Model\DeliveryTime + * + * @Serializer\Groups({"response"}) + * @Serializer\SerializedName("deliveryTime") + * @Serializer\Type("RetailCrm\DeliveryModuleBundle\Model\DeliveryTime") + */ + public $deliveryTime; + + /** + * Код тарифа + * @var string + * + * @Serializer\Groups({"response"}) + * @Serializer\SerializedName("tariff") + * @Serializer\Type("string") + */ + public $tariff; + + /** + * Наименование тарифа + * @var string + * + * @Serializer\Groups({"response"}) + * @Serializer\SerializedName("tariffName") + * @Serializer\Type("string") + */ + public $tariffName; + + /** + * Плательщик за доставку + * @var string + * + * @Serializer\Groups({"response"}) + * @Serializer\SerializedName("payerType") + * @Serializer\Type("string") + */ + public $payerType; + + /** + * Текущий статус достаквки + * @var StatusInfo + * + * @Serializer\Groups({"response"}) + * @Serializer\SerializedName("status") + * @Serializer\Type("RetailCrm\DeliveryModuleBundle\Model\StatusInfo") + */ + public $status; + + /** + * Дополнительные данные доставки + * @var string + * + * @Serializer\Groups({"response"}) + * @Serializer\SerializedName("extraData") + * @Serializer\Type("array") + */ + public $extraData; + + /** + * Адрес отгрузки + * @var DeliveryAddress + * + * @Serializer\Groups({"response"}) + * @Serializer\SerializedName("shipmentAddress") + * @Serializer\Type("RetailCrm\DeliveryModuleBundle\Model\DeliveryAddress") + */ + public $shipmentAddress; + + /** + * Адрес доставки + * @var DeliveryAddress + * + * @Serializer\Groups({"response"}) + * @Serializer\SerializedName("deliveryAddress") + * @Serializer\Type("RetailCrm\DeliveryModuleBundle\Model\DeliveryAddress") + */ + public $deliveryAddress; + + public $additionalData; + + public function __construct() + { + $this->extraData = []; + $this->additionalData = []; + } +} diff --git a/Model/ResponseResult.php b/Model/ResponseResult.php new file mode 100644 index 0000000..bb0f2c3 --- /dev/null +++ b/Model/ResponseResult.php @@ -0,0 +1,7 @@ +extraData = []; + $this->additionalData = []; + } +} diff --git a/Model/ResponseShipmentSave.php b/Model/ResponseShipmentSave.php new file mode 100644 index 0000000..337c0c8 --- /dev/null +++ b/Model/ResponseShipmentSave.php @@ -0,0 +1,36 @@ +") + */ + public $extraData; + + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata + ->addPropertyConstraint('shipmentId', new Assert\NotBlank()); + } +} diff --git a/Model/ResponseSuccessful.php b/Model/ResponseSuccessful.php new file mode 100644 index 0000000..9d86cbf --- /dev/null +++ b/Model/ResponseSuccessful.php @@ -0,0 +1,26 @@ +") + */ + public $shipmentDate; + + /** + * Дата доставки + * @var DateTime + * + * @Serializer\Groups({"get"}) + * @Serializer\SerializedName("deliveryDate") + * @Serializer\Type("DateTime<'Y-m-d'>") + */ + public $deliveryDate; + + /** + * Время доставки ("custom" не ипользуется) + * @var Intaro\CRMBundle\Entity\Model\DeliveryTime + * + * @Serializer\Groups({"get"}) + * @Serializer\SerializedName("deliveryTime") + * @Serializer\Type("RetailCrm\DeliveryModuleBundle\Model\DeliveryTime") + */ + public $deliveryTime; + + /** + * Дополнительные данные доставки + * @var array + * + * @Serializer\Groups({"get"}) + * @Serializer\SerializedName("extraData") + * @Serializer\Type("array") + */ + public $extraData; +} diff --git a/Model/ShipmentOrder.php b/Model/ShipmentOrder.php new file mode 100644 index 0000000..0ac8dbd --- /dev/null +++ b/Model/ShipmentOrder.php @@ -0,0 +1,29 @@ +") + */ + public $packages; +} diff --git a/Model/Status.php b/Model/Status.php new file mode 100644 index 0000000..9da23d9 --- /dev/null +++ b/Model/Status.php @@ -0,0 +1,45 @@ +code = $code; + $this->name = $name; + $this->isEditable = $isEditable; + } +} diff --git a/Model/StatusInfo.php b/Model/StatusInfo.php new file mode 100644 index 0000000..da2bc23 --- /dev/null +++ b/Model/StatusInfo.php @@ -0,0 +1,38 @@ +") + */ + public $updatedAt; + + /** + * Комментарий к статусу + * @var string + * + * @Serializer\Groups({"get", "response"}) + * @Serializer\SerializedName("comment") + * @Serializer\Type("string") + */ + public $comment; +} diff --git a/Model/Terminal.php b/Model/Terminal.php new file mode 100644 index 0000000..280a94a --- /dev/null +++ b/Model/Terminal.php @@ -0,0 +1,78 @@ +extraData[$fieldCode])) { + return null; + } else { + return $this->extraData[$fieldCode]; + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml new file mode 100644 index 0000000..62fff1e --- /dev/null +++ b/Resources/config/routing.yml @@ -0,0 +1,80 @@ +retailcrm_delivery_module_connect: + path: /{_locale}/connect + defaults: { _controller: :Admin:connect } + requirements: + _locale: en|ru + +retailcrm_delivery_module_connect_edit: + path: /{_locale}/connect/{clientId}/edit + defaults: { _controller: :Admin:connect } + requirements: + _locale: en|ru + +############ +# Admin +############ +retailcrm_delivery_module_admin_list: + path: /omega + defaults: { _controller: :Admin:list } + +retailcrm_delivery_module_admin_new: + path: /omega/new + defaults: { _controller: :Admin:new } + +retailcrm_delivery_module_admin_edit: + path: /omega/{connectionId}/edit + defaults: { _controller: :Admin:edit } + requirements: + connectionId: \d+ + +retailcrm_delivery_module_admin_update_configuration: + path: /omega/{connectionId}/update-configuration + defaults: { _controller: :Admin:updateConfiguration } + requirements: + connectionId: \d+ + +retailcrm_delivery_module_admin_parcel_list: + path: /omega/parcels + defaults: { _controller: :Admin:parcelList } + +retailcrm_delivery_module_admin_parcel_new: + path: /omega/parcels/new + defaults: { _controller: :Admin:parcelNew } + +retailcrm_delivery_module_admin_parcel_edit: + path: /omega/parcels/{parcelId}/edit + defaults: { _controller: :Admin:parcelEdit } + requirements: + parcelId: \d+ + + +############# +# Exchange +############ +retailcrm_delivery_module_exchange_base: + path: /api + defaults: { _controller: DeliveryModuleBundle/Controller/Api:index } + +retailcrm_delivery_module_exchange_activity: + path: /api/activity + defaults: { _controller: DeliveryModuleBundle/Controller/Api:activity } + +retailcrm_delivery_module_exchange_calculate: + path: /api/calculate + defaults: { _controller: DeliveryModuleBundle/Controller/Api:calculate } + +retailcrm_delivery_module_exchange_save: + path: /api/save + defaults: { _controller: DeliveryModuleBundle/Controller/Api:save } + +retailcrm_delivery_module_exchange_print: + path: /api/print + defaults: { _controller: DeliveryModuleBundle/Controller/Api:print } + +retailcrm_delivery_module_exchange_shipment_save: + path: /api/shipment-save + defaults: { _controller: DeliveryModuleBundle/Controller/Api:shipmentSave } + +retailcrm_delivery_module_exchange_shipment_delete: + path: /api/shipment-delete + defaults: { _controller: DeliveryModuleBundle/Controller/Api:shipmentDelete } \ No newline at end of file diff --git a/Resources/config/services.yml b/Resources/config/services.yml new file mode 100644 index 0000000..bd13572 --- /dev/null +++ b/Resources/config/services.yml @@ -0,0 +1,40 @@ + +services: + RetailCrm\DeliveryModuleBundle\Service\ModuleManager: + public: true + class: "%retailcrm.delivery_module.module_manager.class%" + arguments: + - "%retailcrm.delivery_module.module_configuration%" + - "@RetailCrm\DeliveryModuleBundle\Service\DeliveryOrderManager" + - "@jms_serializer" + - "@translator" + - "@router" + + RetailCrm\DeliveryModuleBundle\Service\DeliveryOrderManager: + class: "RetailCrm\DeliveryModuleBundle\Service\DeliveryOrderManager" + arguments: + - "%retailcrm.delivery_module.delivery_order.class%" + - "@doctrine.orm.entity_manager" + + RetailCrm\DeliveryModuleBundle\Command\StatusesCommand: + class: RetailCrm\DeliveryModuleBundle\Command\StatusesCommand + arguments: + - "@doctrine.orm.entity_manager" + - "RetailCrm\DeliveryModuleBundle\Service\ModuleManager" + tags: ['console.command'] + + RetailCrm\DeliveryModuleBundle\Command\UpdateModuleConfigurationCommand: + class: RetailCrm\DeliveryModuleBundle\Command\UpdateModuleConfigurationCommand + arguments: + - "@doctrine.orm.entity_manager" + - "RetailCrm\DeliveryModuleBundle\Service\ModuleManager" + tags: ['console.command'] + + RetailCrm\DeliveryModuleBundle\Controller\: + resource: '../../Controller' + public: true + tags: ['controller.service_arguments'] + + RetailCrm\DeliveryModuleBundle\EventListener\SerializeListener: + tags: + - { name: jms_serializer.event_subscriber } diff --git a/Resources/translations/messages.en.yml b/Resources/translations/messages.en.yml new file mode 100644 index 0000000..816c98e --- /dev/null +++ b/Resources/translations/messages.en.yml @@ -0,0 +1,67 @@ +header: + configureConnection: Configuration of connection with system + additionalSettings: Additional settings + adminParcelEdit: 'Edit tracking %trackId%' + adminParcelCreate: Create tracking + listConnection: Current connection + listTracking: Current tracking + serviceConnect: 'Service connection %delivery%' + adminConnectionEdit: 'Edit connection data: %uid%' + adminConnectionCreate: New connection + +button: + activate: Activate + save: Save + add: Add + listConnection: List of connections + listTracking: Parcel tracking + addTracking: Add tracking + updateConfiguration: Update the configuration + +label: + crmUrl: System address + crmKey: System API key + debug: Debug mode + isActive: Integration is active + isFreeze: Integration is freeze + language: Language + account_number: Account number + token: API token + isInProduction: Use production server + id: ID + connection: ID connection + orderId: ID order + trackId: ID tracking + isClosed: Tracking completed + connectionId: Connection ID + +select_value: + sender: Sender + receiver: Receiver + +error: + connect.failed: Data to connect to %delivery% or System API key is entered incorrectly, try again.

Re-enter data + unknown_country: Unknown country + unknown_shipping_country: Unknown shipping country + shipping_country_required: Shipping country must not be empty + shipper_postal_code_required: Shipper postal code required + delivery_postal_code_required: Delivery postal code required + manager_phone_required: Manager`s phone required + dhl: + ready_time_required: Ready time required + dury_payment_type_for_receiver: Duty Payment Type cant be sender for payer type receiver + receiver_account_number_required: Receiver account number required + +plate: + label: Label + +day_short: + monday: Mon + tuesday: Tue + wednesday: Wed + thursday: Thu + friday: Fri + saturday: Sat + sunday: Sun + +pagination.items.name: elements diff --git a/Resources/translations/messages.es.yml b/Resources/translations/messages.es.yml new file mode 100644 index 0000000..a66d5b5 --- /dev/null +++ b/Resources/translations/messages.es.yml @@ -0,0 +1,67 @@ +header: + configureConnection: Configuración de la conexión del sistema + additionalSettings: Configuración avanzada + adminParcelEdit: 'Editar seguimiento %trackId%' + adminParcelCreate: Crear seguimiento + listConnection: Conexiones actuales + listTracking: Seguimiento actual + serviceConnect: 'Conexión de Servicio %delivery%' + adminConnectionEdit: 'Editar datos del cliente: %uid%' + adminConnectionCreate: Nueva conexión + +button: + activate: Activar + save: Guardar + add: Añadir + listConnection: A la lista de conexiones + listTracking: Seguimiento de paquetes + addTracking: Añadir seguimiento + updateConfiguration: Actualizar configuración + +label: + crmUrl: Dirección del Sistema + crmKey: Clave API del sistema + debug: Modo de depuración + isActive: Conexión activa + isFreeze: Conexión congelada + language: Idioma + account_number: Número de cuenta + token: token API + isInProduction: Utilizar servidor normal + id: ID + connection: ID de conexión + orderId: ID de pedido + trackId: ID de seguimiento + isClosed: Seguimiento completado + connectionId: Id de conexión + +select_value: + sender: Remitente + receiver: Receptor + +error: + connect.failed: Datos para conectarse a %delivery% o la clave API del sistema son incorrectos, intente de nuevo.

Introducir datos de nuevo + unknown_country: País desconocido + unknown_shipping_country: Páis de envio desconocido + shipping_country_required: Debe especificar el país de envío + shipper_postal_code_required: Debe especificar el código Postal del remitente + delivery_postal_code_required: Debe especificar el código Postal del destinatario + manager_phone_required: Debe especificar el Teléfono del mánager + dhl: + ready_time_required: Debe especificar la fecha del envío + dury_payment_type_for_receiver: El remitente no puede pagar los cargos adicionales si el que paga es el destinatario + receiver_account_number_required: Debe especificar el número de cuenta del destinatario + +plate: + label: Etiqueta + +day_short: + monday: Lu + tuesday: Ma + wednesday: Mie + thursday: Ju + friday: Vi + saturday: Sa + sunday: Do + +pagination.items.name: elementos diff --git a/Resources/translations/messages.ru.yml b/Resources/translations/messages.ru.yml new file mode 100644 index 0000000..cfed3d8 --- /dev/null +++ b/Resources/translations/messages.ru.yml @@ -0,0 +1,67 @@ +header: + configureConnection: Настройка подключения к системе + additionalSettings: Дополнительные настройки + adminParcelEdit: 'Редактировать отслеживание %trackId%' + adminParcelCreate: Создать отслеживание + listConnection: Текущие подключения + listTracking: Текущие отслеживания + serviceConnect: 'Подключение сервиса %delivery%' + adminConnectionEdit: 'Редактировать данные клиента: %uid%' + adminConnectionCreate: Новое подключение + +button: + activate: Активировать + save: Сохранить + add: Добавить + listConnection: К списку подключений + listTracking: Отслеживание посылок + addTracking: Добавить отслеживание + updateConfiguration: Обновить конфигурацию + +label: + crmUrl: Адрес системы + crmKey: API ключ системы + debug: Режим отладки + isActive: Подключение активно + isFreeze: Подключение заморожено + language: Язык + account_number: Номер аккаунта + token: API токен + isInProduction: Использовать боевой сервер + id: ID + connection: ID подключения + orderId: ID заказа + trackId: ID отслеживания + isClosed: Отслеживание завершено + connectionId: Идентификатор подключения + +select_value: + sender: Отправитель + receiver: Получатель + +error: + connect.failed: Данные для подключения к %delivery% или API ключ системы введены неверно, попробуйте еще раз.

Ввести данные заново + unknown_country: Неизвестная страна + unknown_shipping_country: Неизвестная страна отправки + shipping_country_required: Необходимо указать страну отправки + shipper_postal_code_required: Необходимо указать почтовый индекс отправителя + delivery_postal_code_required: Необходимо указать почтовый индекс получателя + manager_phone_required: Необходимо указать телефон менеджера + dhl: + ready_time_required: Необходимо указать время отгрузки + dury_payment_type_for_receiver: Отправитель не может быть плательщиком за дополнительные сборы если тип плательщика получатель + receiver_account_number_required: Необходимо указать номер аккаунта получателя + +plate: + label: Наклейка + +day_short: + monday: Пн + tuesday: Вт + wednesday: Ср + thursday: Чт + friday: Пт + saturday: Сб + sunday: Вс + +pagination.items.name: элементов diff --git a/Resources/views/Connection/configure.html.twig b/Resources/views/Connection/configure.html.twig new file mode 100644 index 0000000..8d84911 --- /dev/null +++ b/Resources/views/Connection/configure.html.twig @@ -0,0 +1,68 @@ +{% form_theme form 'DeliveryCoreBundle:Form:configure.html.twig' %} + + + + + + + {% block title %}{% endblock %} + + + + + + +
+
+
+
+ {% block logo %}{% endblock %} +
+
+
+
+
+
+ {% block form %} +
+ {{ form_errors(form) }} +
+ +
+ {{ form_start(form) }} + + {% block form_delivery %} + {% endblock %} + +
+ {{ 'header.configureConnection'|trans }} + {{ form_widget(form.crmUrl, {'attr': {'value': account}}) }} + {{ form_errors(form.crmUrl) }} + + {{ form_widget(form.crmKey) }} + {{ form_errors(form.crmKey) }} + + {{ form_widget(form.language) }} + {{ form_errors(form.language) }} +
+ + {% block form_delivery_after %} + {% endblock %} + +
+ {{ form_rest(form) }} +
+ + + {{ form_end(form) }} + {% endblock %} + +
+
+ +
+ + + diff --git a/Resources/views/Connection/configure_error.html.twig b/Resources/views/Connection/configure_error.html.twig new file mode 100644 index 0000000..0440200 --- /dev/null +++ b/Resources/views/Connection/configure_error.html.twig @@ -0,0 +1,13 @@ +{% extends 'CoreAutomateBundle:Layout:connect.html.twig' %} + +{% block title %} + {{ 'header.serviceConnect'|trans({'%delivery%': title_delivery})|raw }} +{% endblock %} + +{% block logo %} + {{ title_delivery }} +{% endblock %} + +{% block form %} + {{ 'error.connect.failed'|trans({'%delivery%': title_delivery, '%href%': referer})|raw }} +{% endblock %} diff --git a/Resources/views/Connection/edit.html.twig b/Resources/views/Connection/edit.html.twig new file mode 100644 index 0000000..3b1889e --- /dev/null +++ b/Resources/views/Connection/edit.html.twig @@ -0,0 +1,60 @@ +{% extends 'CoreOmegaBundle:Layout:base.html.twig' %} +{% form_theme form 'DeliveryCoreBundle:Form:admin.html.twig' %} + +{% block content %} +
+

+ {% if connection is defined %} + {{ 'header.adminConnectionEdit'|trans({'%uid%': ''~connection.crmUrl~''})|raw }} + {% else %} + {{ 'header.adminConnectionCreate'|trans()|raw }} + {% endif %} +

+
+ +
+
+ {{ form_start(form) }} + {{ form_errors(form) }} + +
+ {{ form_row(form.crmUrl) }} + {{ form_row(form.crmKey) }} + + {{ form_row(form.isActive) }} + + {% if form.language is defined %} + {{ form_row(form.language) }} + {% endif %} + + {{ form_row(form.isFreeze) }} +
+ + {% block form_appendix %} + {% endblock %} + +
+ {{ form_row(form.debug) }} +
+ +
+
+ +
+ {% if is_granted('ROLE_DEVELOPER') %} + {% if connection is defined %} + + {% endif %} + {% endif %} +
+ + {{ form_end(form) }} +
+ +
+
+{% endblock %} diff --git a/Resources/views/Connection/list.html.twig b/Resources/views/Connection/list.html.twig new file mode 100644 index 0000000..dde22df --- /dev/null +++ b/Resources/views/Connection/list.html.twig @@ -0,0 +1,61 @@ +{% extends 'CoreOmegaBundle:Layout:base.html.twig' %} + +{% block content %} +
+

{{ 'header.listConnection'|trans()|raw }}

+
+ +
+
+ {% if is_granted('ROLE_DEVELOPER') %} + + {{ 'button.add'|trans()|raw }} + + {% endif %} + + {{ 'button.listTracking'|trans()|raw }} + +
+ + + + + + + + {% for client in pagination %} + + + + + + {% endfor %} +
{{ 'label.id'|trans()|raw }}{{ 'label.crmUrl'|trans()|raw }}{{ 'label.isActive'|trans()|raw }}
+ {{ client.clientId }} + + {% if client.crmUrl is not empty %} + + {{ client.crmUrl }} + + {% endif %} + + {% if client.isActive %} + + {% else %} + + {% endif %} +
+ +
+
+ + {{ pagination.getTotalItemCount }} {{ 'pagination.items.name'|trans()|raw }} + +
+
+ {{ knp_pagination_render(pagination) }} +
+
+
+
+{% endblock %} diff --git a/Resources/views/Form/admin.html.twig b/Resources/views/Form/admin.html.twig new file mode 100644 index 0000000..5e0b0f2 --- /dev/null +++ b/Resources/views/Form/admin.html.twig @@ -0,0 +1,18 @@ +{% extends "form_div_layout.html.twig" %} + +{% block form_row %} +{% spaceless %} +
+ {{ form_label(form, null, {'label_attr' : {'class': 'label-common'}}) }} + {{ form_errors(form) }} + + {% if not attr or not attr.class|default(null) %} + {% set attr = attr|default({})|merge({ + 'class': 'input-field', + 'style': 'max-width: 320px;' + }) %} + {% endif %} + {{ form_widget(form, { 'attr': attr }) }} +
+{% endspaceless %} +{% endblock form_row %} \ No newline at end of file diff --git a/Resources/views/Form/configure.html.twig b/Resources/views/Form/configure.html.twig new file mode 100644 index 0000000..60eb358 --- /dev/null +++ b/Resources/views/Form/configure.html.twig @@ -0,0 +1,13 @@ +{% extends "form_div_layout.html.twig" %} + +{% block form_errors %} + {% spaceless %} + {% if errors|length > 0 %} + {% for error in errors %} +
+ {{ error.message }} +
+ {% endfor %} + {% endif %} + {% endspaceless %} +{% endblock form_errors %} \ No newline at end of file diff --git a/Resources/views/Parcel/edit.html.twig b/Resources/views/Parcel/edit.html.twig new file mode 100644 index 0000000..00ef4cc --- /dev/null +++ b/Resources/views/Parcel/edit.html.twig @@ -0,0 +1,61 @@ +{% extends 'CoreOmegaBundle:Layout:base.html.twig' %} + +{% block content %} +
+

+ {% if parcel.id is not empty %} + {{ 'header.adminParcelEdit' |trans({'%trackId%': parcel.trackId})|raw }} + {% else %} + {{ 'header.adminParcelCreate' |trans()|raw }} + {% endif %} +

+
+ +
+
+ {{ form_start(form) }} + {{ form_errors(form) }} + +
+
+ {{ form_label(form.connection, null, {'label_attr' : {'class': 'label-common'}}) }} + {{ form_errors(form.connection) }} + {{ form_widget(form.connection, {'attr': {'class': 'input-field', 'style': 'width: 320px;'}}) }} +
+ +
+ {{ form_label(form.orderId, null, {'label_attr' : {'class': 'label-common'}}) }} + {{ form_errors(form.orderId) }} + {{ form_widget(form.orderId, {'attr': {'class': 'input-field', 'style': 'width: 320px;'}}) }} +
+
+ +
+
+ {{ form_label(form.trackId, null, {'label_attr' : {'class': 'label-common'}}) }} + {{ form_errors(form.trackId) }} + {{ form_widget(form.trackId, {'attr': {'class': 'input-field', 'style': 'width: 320px;'}}) }} +
+ +
+ {{ form_label(form.isClosed, null, {'label_attr' : {'class': 'label-common'}}) }} + {{ form_errors(form.isClosed) }} + {{ form_widget(form.isClosed) }} +
+
+ + {% block form_appendix %} + {% endblock %} + +
+
+ +
+
+ + {{ form_end(form) }} +
+ +
+
+{% endblock%} diff --git a/Resources/views/Parcel/list.html.twig b/Resources/views/Parcel/list.html.twig new file mode 100644 index 0000000..0eb062a --- /dev/null +++ b/Resources/views/Parcel/list.html.twig @@ -0,0 +1,60 @@ +{% extends 'CoreOmegaBundle:Layout:base.html.twig' %} + +{% block content %} +
+

{{ 'header.listConnection'|trans()|raw }}

+
+ +
+ + + + + + + + + {% for track in pagination %} + + + + + + + {% endfor %} +
{{ 'label.trackId'|trans()|raw }}{{ 'label.orderId'|trans()|raw }}{{ 'label.connection'|trans()|raw }}{{ 'label.isClosed'|trans()|raw }}
+ {{ track.trackId}} + + {{ track.orderId}} + + {{ track.clientId}} + + {% if track.isClosed %} + + {% else %} + + {% endif %} +
+ +
+
+ + {{ pagination.getTotalItemCount }} {{ 'pagination.items.name'|trans()|raw }} + +
+
+ {{ knp_pagination_render(pagination) }} +
+
+
+
+{% endblock%} diff --git a/Service/DeliveryOrderManager.php b/Service/DeliveryOrderManager.php new file mode 100644 index 0000000..f5053db --- /dev/null +++ b/Service/DeliveryOrderManager.php @@ -0,0 +1,50 @@ +class = $deliveryOrderClass; + $this->entityManager = $entityManager; + } + + public function getClass(): string + { + return $this->getRepository()->getClassName(); + } + + public function create(): DeliveryOrder + { + $class = $this->getClass(); + + return new $class(); + } + + public function findBy(array $criteria): array + { + return $this->getRepository()->findBy($criteria); + } + + public function findOneBy(array $criteria): ?DeliveryOrder + { + return $this->getRepository()->findOneBy($criteria); + } + + public function flush(): void + { + $this->entityManager->flush(); + } + + public function getRepository(): ObjectRepository + { + return $this->entityManager->getRepository($this->class); + } +} diff --git a/Service/ModuleManager.php b/Service/ModuleManager.php new file mode 100644 index 0000000..8721be6 --- /dev/null +++ b/Service/ModuleManager.php @@ -0,0 +1,348 @@ +integrationCode = $moduleConfig['integrationCode']; + $this->config = $moduleConfig; + $this->deliveryManager = $deliveryManager; + $this->jmsSerializer = $jmsSerializer; + $this->translator = $translator; + $this->router = $router; + $this->pinbaService = $pinbaService; + } + + public function getModuleCode(): string + { + if (null === $this->account) { + throw new \LogicException('Account is not selected'); + } + + return sprintf('%s-%s', $this->integrationCode, $this->account->getId()); + } + + public function setLogger(?LoggerInterface $logger): self + { + $this->logger = $logger; + + return $this; + } + + public function getAccount(): ?Account + { + return $this->account; + } + + public function setAccount(Account $account): self + { + $this->account = $account; + + if ($this->account && $this->account->getLanguage() && $this->translator) { + $this->translator->setLocale($this->account->getLanguage()); + } + + $this->createRetailCrmClient(); + + return $this; + } + + public function updateModuleConfiguration(): bool + { + if (null === $this->account) { + throw new \LogicException('Account is not selected'); + } + + $integrationModule = $this->buildIntegrationModule(); + $integrationModule = $this->jmsSerializer + ->serialize($integrationModule, 'json', SerializationContext::create()->setGroups(['get', 'request'])); + + $response = $this->pinbaService->timerHandler( + [ + 'api' => 'retailCrm', + 'method' => 'integrationModulesEdit', + ], + static function () use ($integrationModule) { + return $this->retailCrmClient->request->integrationModulesEdit( + json_decode($integrationModule, true) + ); + } + ); + + if ($result['success'] ?? false) { + return true; + } else { + return false; + } + } + + protected function buildIntegrationModule(): IntegrationModule + { + $integrationModule = new IntegrationModule(); + + $integrationModule->code = $this->getModuleCode(); + $integrationModule->integrationCode = $this->integrationCode; + $integrationModule->active = $this->account->isActive(); + $integrationModule->name = $this->config['locales'][$this->translator->getLocale()]['name']; + $integrationModule->logo = $this->config['locales'][$this->translator->getLocale()]['logo']; + $integrationModule->clientId = $this->account->getId(); + $integrationModule->availableCountries = $this->config['countries']; + $integrationModule->actions = [ + 'activity' => 'activity', + ]; + + $integrationModule->baseUrl = $this->router->generate( + 'retailcrm_delivery_module_exchange_base', + [], + UrlGeneratorInterface::ABSOLUTE_URL + ); + $integrationModule->accountUrl = $this->router->generate( + 'retailcrm_delivery_module_connect', + ['_locale' => $this->connection->getLanguage()], + UrlGeneratorInterface::ABSOLUTE_URL + ); + + $integrationModule->integrations['delivery'] = $this->doBuildDeliveryConfiguration(); + + return $integrationModule; + } + + abstract protected function doBuildConfiguration(): Configuration; + + public function calculateDelivery(RequestCalculate $data): ResponseCalculate + { + throw new \LogicException('Method should be implemented'); + } + + public function saveDelivery(RequestSave $data, DeliveryOrder $delivery = null): ResponseSave + { + throw new \LogicException('Method should be implemented'); + } + + public function deleteDelivery(RequestDelete $request, DeliveryOrder $delivery): bool + { + throw new \LogicException('Method should be implemented'); + } + + public function saveShipment(RequestShipmentSave $data): ResponseShipmentSave + { + throw new \LogicException('Method should be implemented'); + } + + public function deleteShipment(RequestShipmentDelete $request): bool + { + throw new \LogicException('Method should be implemented'); + } + + public function printDocument(RequestPrint $request) + { + $deliveries = $this->deliveryManager->findBy([ + 'account' => $this->account, + 'externalId' => $request->deliveryIds, + ]); + + if (empty($deliveries)) { + throw new Exception\ApiException('Deliveries not found.'); + } + + return $this->doPrint($request->type, $deliveries); + } + + protected function doPrint(string $documentType, array $deliveries): array + { + throw new \LogicException('Method should be implemented'); + } + + public function updateStatuses(): int + { + if (null === $this->account) { + throw new \LogicException('Account is not selected'); + } + + $deliveryQuery = $this->deliveryManager->createQueryBuilder('delivery') + ->select('delivery') + ->andWhere('delivery.account = :account') + ->andWhere('delivery.id >= :lastId') + ->andWhere('delivery.ended = FALSE') + ->orderBy('delivery.id ASC') + ->createQuery() + ->setMaxResults(static::STATUS_UPDATE_LIMIT) + ->setAccount($this->account) + ; + + $count = 0; + $lastId = 0; + while (true) { + $deliveryQuery->setParameter('lastId', $lastId); + $deliveries = $deliveryQuery->getResult(); + if (empty($deliveries)) { + break; + } + + foreach ($deliveries as $delivery) { + if ($delivery->getId() > $lastId) { + $lastId = $delivery->getId(); + } + } + + $deliveriesHistory = $this->doUpdateStatuses($deliveries); + if (!empty($deliveriesHistory)) { + $this->updateRetailCrmOrderStatuses($deliveriesHistory); + } + $count += count($deliveriesHistory); + $this->deliveryManager->flush(); + } + + return $count; + } + + /** + * Получение актуальных статусов доставки от службы доставки + * + * @param \RetailCrm\DeliveryModuleBundle\Entity\Parcel[] $parces + * + * @return \RetailCrm\DeliveryModuleBundle\Model\RequestStatusUpdateItem[] + */ + protected function doUpdateStatuses(array $deliveries): array + { + throw new \LogicException('Method should be implemented'); + } + + /** + * Обновление статусов в CRM + * + * @param \RetailCrm\DeliveryModuleBundle\Model\RequestStatusUpdateItem[] $deliveriesHistory + * + * @throws \Exception + */ + protected function updateRetailCrmOrderStatuses(array $deliveriesHistory): void + { + if (count($deliveriesHistory) > 100) { + $parts = array_chunk($deliveriesHistory, 100); + } else { + $parts = [$deliveriesHistory]; + } + + foreach ($parts as $part) { + $request = $this->jmsSerializer + ->serialize($part, 'json', SerializationContext::create()->setGroups(['get', 'request'])); + + $response = $this->pinbaService->timerHandler( + [ + 'api' => 'retailCrm', + 'method' => 'deliveryTracking', + ], + static function () use ($request) { + return $this->retailCrmClient->request->deliveryTracking( + $this->getModuleCode(), + json_decode($request, true) + ); + } + ); + } + } + + private function createRetailCrmClient(): void + { + if (null === $this->account) { + throw new \LogicException('Account is not selected'); + } + + if (empty($this->account->getCrmUrl())) { + throw new \LogicException('Crm url is empty'); + } + + if (empty($this->account->getCrmApiKey())) { + throw new \LogicException('Crm apiKey is empty'); + } + + $this->retailCrmClient = new ApiClient( + $this->account->getCrmUrl(), + $this->account->getCrmApiKey(), + ApiClient::V5 + ); + if ($this->logger) { + $this->retailCrmClient->setLogger($this->logger); + } + } +} diff --git a/Service/PinbaService.php b/Service/PinbaService.php new file mode 100644 index 0000000..bbe289a --- /dev/null +++ b/Service/PinbaService.php @@ -0,0 +1,25 @@ +2.2,<2.4" + }, + "require-dev": { + "alcaeus/mongo-php-adapter": "^1.1", + "doctrine/coding-standard": "^6.0", + "mongodb/mongodb": "^1.1", + "phpunit/phpunit": "^7.0", + "predis/predis": "~1.0" + }, + "suggest": { + "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", + "homepage": "https://www.doctrine-project.org/projects/cache.html", + "keywords": [ + "abstraction", + "apcu", + "cache", + "caching", + "couchdb", + "memcached", + "php", + "redis", + "xcache" + ], + "time": "2019-11-29T15:36:20+00:00" + }, + { + "name": "doctrine/collections", + "version": "1.6.4", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7", + "reference": "6b1e4b2b66f6d6e49983cebfe23a21b7ccc5b0d7", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan-shim": "^0.9.2", + "phpunit/phpunit": "^7.0", + "vimeo/psalm": "^3.2.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", + "homepage": "https://www.doctrine-project.org/projects/collections.html", + "keywords": [ + "array", + "collections", + "iterators", + "php" + ], + "time": "2019-11-13T13:07:11+00:00" + }, + { + "name": "doctrine/common", + "version": "v2.11.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/common.git", + "reference": "b8ca1dcf6b0dc8a2af7a09baac8d0c48345df4ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/common/zipball/b8ca1dcf6b0dc8a2af7a09baac8d0c48345df4ff", + "reference": "b8ca1dcf6b0dc8a2af7a09baac8d0c48345df4ff", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.0", + "doctrine/cache": "^1.0", + "doctrine/collections": "^1.0", + "doctrine/event-manager": "^1.0", + "doctrine/inflector": "^1.0", + "doctrine/lexer": "^1.0", + "doctrine/persistence": "^1.1", + "doctrine/reflection": "^1.0", + "php": "^7.1" + }, + "require-dev": { + "doctrine/coding-standard": "^1.0", + "phpstan/phpstan": "^0.11", + "phpstan/phpstan-phpunit": "^0.11", + "phpunit/phpunit": "^7.0", + "squizlabs/php_codesniffer": "^3.0", + "symfony/phpunit-bridge": "^4.0.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.11.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, persistence interfaces, proxies, event system and much more.", + "homepage": "https://www.doctrine-project.org/projects/common.html", + "keywords": [ + "common", + "doctrine", + "php" + ], + "time": "2019-09-10T10:10:14+00:00" + }, + { + "name": "doctrine/dbal", + "version": "v2.10.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/dbal.git", + "reference": "0c9a646775ef549eb0a213a4f9bd4381d9b4d934" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/0c9a646775ef549eb0a213a4f9bd4381d9b4d934", + "reference": "0c9a646775ef549eb0a213a4f9bd4381d9b4d934", + "shasum": "" + }, + "require": { + "doctrine/cache": "^1.0", + "doctrine/event-manager": "^1.0", + "ext-pdo": "*", + "php": "^7.2" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "jetbrains/phpstorm-stubs": "^2019.1", + "phpstan/phpstan": "^0.11.3", + "phpunit/phpunit": "^8.4.1", + "symfony/console": "^2.0.5|^3.0|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For helpful console commands such as SQL execution and import of files." + }, + "bin": [ + "bin/doctrine-dbal" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.10.x-dev", + "dev-develop": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\DBAL\\": "lib/Doctrine/DBAL" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.", + "homepage": "https://www.doctrine-project.org/projects/dbal.html", + "keywords": [ + "abstraction", + "database", + "db2", + "dbal", + "mariadb", + "mssql", + "mysql", + "oci8", + "oracle", + "pdo", + "pgsql", + "postgresql", + "queryobject", + "sasql", + "sql", + "sqlanywhere", + "sqlite", + "sqlserver", + "sqlsrv" + ], + "time": "2019-11-03T16:50:43+00:00" + }, + { + "name": "doctrine/event-manager", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/event-manager.git", + "reference": "629572819973f13486371cb611386eb17851e85c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/629572819973f13486371cb611386eb17851e85c", + "reference": "629572819973f13486371cb611386eb17851e85c", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "conflict": { + "doctrine/common": "<2.9@dev" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.", + "homepage": "https://www.doctrine-project.org/projects/event-manager.html", + "keywords": [ + "event", + "event dispatcher", + "event manager", + "event system", + "events" + ], + "time": "2019-11-10T09:48:07+00:00" + }, + { + "name": "doctrine/inflector", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "ec3a55242203ffa6a4b27c58176da97ff0a7aec1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/ec3a55242203ffa6a4b27c58176da97ff0a7aec1", + "reference": "ec3a55242203ffa6a4b27c58176da97ff0a7aec1", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^6.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Common String Manipulations with regard to casing and singular/plural rules.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string" + ], + "time": "2019-10-30T19:59:35+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.13", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-shim": "^0.11", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2019-10-21T16:45:58+00:00" + }, + { + "name": "doctrine/lexer", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", + "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", + "shasum": "" + }, + "require": { + "php": "^7.2" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan": "^0.11.8", + "phpunit/phpunit": "^8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "time": "2019-10-30T14:39:59+00:00" + }, + { + "name": "doctrine/orm", + "version": "v2.7.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/orm.git", + "reference": "4d763ca4c925f647b248b9fa01b5f47aa3685d62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/orm/zipball/4d763ca4c925f647b248b9fa01b5f47aa3685d62", + "reference": "4d763ca4c925f647b248b9fa01b5f47aa3685d62", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.8", + "doctrine/cache": "^1.9.1", + "doctrine/collections": "^1.5", + "doctrine/common": "^2.11", + "doctrine/dbal": "^2.9.3", + "doctrine/event-manager": "^1.1", + "doctrine/instantiator": "^1.3", + "doctrine/persistence": "^1.2", + "ext-pdo": "*", + "php": "^7.1", + "symfony/console": "^3.0|^4.0|^5.0" + }, + "require-dev": { + "doctrine/coding-standard": "^5.0", + "phpunit/phpunit": "^7.5", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" + }, + "bin": [ + "bin/doctrine" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\ORM\\": "lib/Doctrine/ORM" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Object-Relational-Mapper for PHP", + "homepage": "https://www.doctrine-project.org/projects/orm.html", + "keywords": [ + "database", + "orm" + ], + "time": "2019-11-19T08:38:05+00:00" + }, + { + "name": "doctrine/persistence", + "version": "1.3.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/persistence.git", + "reference": "99b196bbd4715a94fa100fac664a351ffa46d6a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/99b196bbd4715a94fa100fac664a351ffa46d6a5", + "reference": "99b196bbd4715a94fa100fac664a351ffa46d6a5", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.0", + "doctrine/cache": "^1.0", + "doctrine/collections": "^1.0", + "doctrine/event-manager": "^1.0", + "doctrine/reflection": "^1.0", + "php": "^7.1" + }, + "conflict": { + "doctrine/common": "<2.10@dev" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan": "^0.11", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common", + "Doctrine\\Persistence\\": "lib/Doctrine/Persistence" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "The Doctrine Persistence project is a set of shared interfaces and functionality that the different Doctrine object mappers share.", + "homepage": "https://doctrine-project.org/projects/persistence.html", + "keywords": [ + "mapper", + "object", + "odm", + "orm", + "persistence" + ], + "time": "2019-12-13T10:43:02+00:00" + }, + { + "name": "doctrine/reflection", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/reflection.git", + "reference": "02538d3f95e88eb397a5f86274deb2c6175c2ab6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/reflection/zipball/02538d3f95e88eb397a5f86274deb2c6175c2ab6", + "reference": "02538d3f95e88eb397a5f86274deb2c6175c2ab6", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.0", + "ext-tokenizer": "*", + "php": "^7.1" + }, + "require-dev": { + "doctrine/coding-standard": "^4.0", + "doctrine/common": "^2.8", + "phpstan/phpstan": "^0.9.2", + "phpstan/phpstan-phpunit": "^0.9.4", + "phpunit/phpunit": "^7.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Doctrine Reflection component", + "homepage": "https://www.doctrine-project.org/projects/reflection.html", + "keywords": [ + "reflection" + ], + "time": "2018-06-14T14:45:07+00:00" + }, + { + "name": "hoa/compiler", + "version": "3.17.08.08", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Compiler.git", + "reference": "aa09caf0bf28adae6654ca6ee415ee2f522672de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Compiler/zipball/aa09caf0bf28adae6654ca6ee415ee2f522672de", + "reference": "aa09caf0bf28adae6654ca6ee415ee2f522672de", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0", + "hoa/file": "~1.0", + "hoa/iterator": "~2.0", + "hoa/math": "~1.0", + "hoa/protocol": "~1.0", + "hoa/regex": "~1.0", + "hoa/visitor": "~2.0" + }, + "require-dev": { + "hoa/json": "~2.0", + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Compiler\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Compiler library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "algebraic", + "ast", + "compiler", + "context-free", + "coverage", + "exhaustive", + "grammar", + "isotropic", + "language", + "lexer", + "library", + "ll1", + "llk", + "parser", + "pp", + "random", + "regular", + "rule", + "sampler", + "syntax", + "token", + "trace", + "uniform" + ], + "time": "2017-08-08T07:44:07+00:00" + }, + { + "name": "hoa/consistency", + "version": "1.17.05.02", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Consistency.git", + "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Consistency/zipball/fd7d0adc82410507f332516faf655b6ed22e4c2f", + "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f", + "shasum": "" + }, + "require": { + "hoa/exception": "~1.0", + "php": ">=5.5.0" + }, + "require-dev": { + "hoa/stream": "~1.0", + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Consistency\\": "." + }, + "files": [ + "Prelude.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Consistency library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "autoloader", + "callable", + "consistency", + "entity", + "flex", + "keyword", + "library" + ], + "time": "2017-05-02T12:18:12+00:00" + }, + { + "name": "hoa/event", + "version": "1.17.01.13", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Event.git", + "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Event/zipball/6c0060dced212ffa3af0e34bb46624f990b29c54", + "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Event\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Event library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "event", + "library", + "listener", + "observer" + ], + "time": "2017-01-13T15:30:50+00:00" + }, + { + "name": "hoa/exception", + "version": "1.17.01.16", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Exception.git", + "reference": "091727d46420a3d7468ef0595651488bfc3a458f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Exception/zipball/091727d46420a3d7468ef0595651488bfc3a458f", + "reference": "091727d46420a3d7468ef0595651488bfc3a458f", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/event": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Exception\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Exception library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "exception", + "library" + ], + "time": "2017-01-16T07:53:27+00:00" + }, + { + "name": "hoa/file", + "version": "1.17.07.11", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/File.git", + "reference": "35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/File/zipball/35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca", + "reference": "35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/event": "~1.0", + "hoa/exception": "~1.0", + "hoa/iterator": "~2.0", + "hoa/stream": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\File\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\File library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "Socket", + "directory", + "file", + "finder", + "library", + "link", + "temporary" + ], + "time": "2017-07-11T07:42:15+00:00" + }, + { + "name": "hoa/iterator", + "version": "2.17.01.10", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Iterator.git", + "reference": "d1120ba09cb4ccd049c86d10058ab94af245f0cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Iterator/zipball/d1120ba09cb4ccd049c86d10058ab94af245f0cc", + "reference": "d1120ba09cb4ccd049c86d10058ab94af245f0cc", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Iterator\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Iterator library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "iterator", + "library" + ], + "time": "2017-01-10T10:34:47+00:00" + }, + { + "name": "hoa/math", + "version": "1.17.05.16", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Math.git", + "reference": "7150785d30f5d565704912116a462e9f5bc83a0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Math/zipball/7150785d30f5d565704912116a462e9f5bc83a0c", + "reference": "7150785d30f5d565704912116a462e9f5bc83a0c", + "shasum": "" + }, + "require": { + "hoa/compiler": "~3.0", + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0", + "hoa/iterator": "~2.0", + "hoa/protocol": "~1.0", + "hoa/zformat": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Math\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Math library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "arrangement", + "combination", + "combinatorics", + "counting", + "library", + "math", + "permutation", + "sampler", + "set" + ], + "time": "2017-05-16T08:02:17+00:00" + }, + { + "name": "hoa/protocol", + "version": "1.17.01.14", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Protocol.git", + "reference": "5c2cf972151c45f373230da170ea015deecf19e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Protocol/zipball/5c2cf972151c45f373230da170ea015deecf19e2", + "reference": "5c2cf972151c45f373230da170ea015deecf19e2", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Protocol\\": "." + }, + "files": [ + "Wrapper.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Protocol library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "library", + "protocol", + "resource", + "stream", + "wrapper" + ], + "time": "2017-01-14T12:26:10+00:00" + }, + { + "name": "hoa/regex", + "version": "1.17.01.13", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Regex.git", + "reference": "7e263a61b6fb45c1d03d8e5ef77668518abd5bec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Regex/zipball/7e263a61b6fb45c1d03d8e5ef77668518abd5bec", + "reference": "7e263a61b6fb45c1d03d8e5ef77668518abd5bec", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0", + "hoa/math": "~1.0", + "hoa/protocol": "~1.0", + "hoa/ustring": "~4.0", + "hoa/visitor": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Regex\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Regex library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "compiler", + "library", + "regex" + ], + "time": "2017-01-13T16:10:24+00:00" + }, + { + "name": "hoa/stream", + "version": "1.17.02.21", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Stream.git", + "reference": "3293cfffca2de10525df51436adf88a559151d82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Stream/zipball/3293cfffca2de10525df51436adf88a559151d82", + "reference": "3293cfffca2de10525df51436adf88a559151d82", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/event": "~1.0", + "hoa/exception": "~1.0", + "hoa/protocol": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Stream\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Stream library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "Context", + "bucket", + "composite", + "filter", + "in", + "library", + "out", + "protocol", + "stream", + "wrapper" + ], + "time": "2017-02-21T16:01:06+00:00" + }, + { + "name": "hoa/ustring", + "version": "4.17.01.16", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Ustring.git", + "reference": "e6326e2739178799b1fe3fdd92029f9517fa17a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Ustring/zipball/e6326e2739178799b1fe3fdd92029f9517fa17a0", + "reference": "e6326e2739178799b1fe3fdd92029f9517fa17a0", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "suggest": { + "ext-iconv": "ext/iconv must be present (or a third implementation) to use Hoa\\Ustring::transcode().", + "ext-intl": "To get a better Hoa\\Ustring::toAscii() and Hoa\\Ustring::compareTo()." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Ustring\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Ustring library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "library", + "search", + "string", + "unicode" + ], + "time": "2017-01-16T07:08:25+00:00" + }, + { + "name": "hoa/visitor", + "version": "2.17.01.16", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Visitor.git", + "reference": "c18fe1cbac98ae449e0d56e87469103ba08f224a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Visitor/zipball/c18fe1cbac98ae449e0d56e87469103ba08f224a", + "reference": "c18fe1cbac98ae449e0d56e87469103ba08f224a", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Visitor\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Visitor library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "library", + "structure", + "visit", + "visitor" + ], + "time": "2017-01-16T07:02:03+00:00" + }, + { + "name": "hoa/zformat", + "version": "1.17.01.10", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Zformat.git", + "reference": "522c381a2a075d4b9dbb42eb4592dd09520e4ac2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Zformat/zipball/522c381a2a075d4b9dbb42eb4592dd09520e4ac2", + "reference": "522c381a2a075d4b9dbb42eb4592dd09520e4ac2", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Zformat\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Zformat library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "library", + "parameter", + "zformat" + ], + "time": "2017-01-10T10:39:54+00:00" + }, + { + "name": "jms/metadata", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/metadata.git", + "reference": "8d8958103485c2cbdd9a9684c3869312ebdaf73a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/8d8958103485c2cbdd9a9684c3869312ebdaf73a", + "reference": "8d8958103485c2cbdd9a9684c3869312ebdaf73a", + "shasum": "" + }, + "require": { + "php": "^7.2" + }, + "require-dev": { + "doctrine/cache": "^1.0", + "doctrine/coding-standard": "^4.0", + "phpunit/phpunit": "^7.0", + "symfony/cache": "^3.1|^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Metadata\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "Class/method/property metadata management in PHP", + "keywords": [ + "annotations", + "metadata", + "xml", + "yaml" + ], + "time": "2019-09-17T15:30:40+00:00" + }, + { + "name": "jms/serializer", + "version": "3.4.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/serializer.git", + "reference": "e2d3c49d9322a08ee32221a5623c898160dada79" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/e2d3c49d9322a08ee32221a5623c898160dada79", + "reference": "e2d3c49d9322a08ee32221a5623c898160dada79", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.0", + "doctrine/instantiator": "^1.0.3", + "hoa/compiler": "^3.17.08.08", + "jms/metadata": "^2.0", + "php": "^7.2" + }, + "conflict": { + "hoa/consistency": "<1.17.05.02", + "hoa/core": "*", + "hoa/iterator": "<2.16.03.15" + }, + "require-dev": { + "doctrine/coding-standard": "^5.0", + "doctrine/orm": "~2.1", + "doctrine/phpcr-odm": "^1.3|^2.0", + "ext-pdo_sqlite": "*", + "jackalope/jackalope-doctrine-dbal": "^1.1.5", + "ocramius/proxy-manager": "^1.0|^2.0", + "phpunit/phpunit": "^7.5||^8.0", + "psr/container": "^1.0", + "symfony/dependency-injection": "^3.0|^4.0|^5.0", + "symfony/expression-language": "^3.0|^4.0|^5.0", + "symfony/filesystem": "^3.0|^4.0|^5.0", + "symfony/form": "^3.0|^4.0|^5.0", + "symfony/translation": "^3.0|^4.0|^5.0", + "symfony/validator": "^3.1.9|^4.0|^5.0", + "symfony/yaml": "^3.3|^4.0|^5.0", + "twig/twig": "~1.34|~2.4" + }, + "suggest": { + "doctrine/cache": "Required if you like to use cache functionality.", + "doctrine/collections": "Required if you like to use doctrine collection types as ArrayCollection.", + "symfony/yaml": "Required if you'd like to use the YAML metadata format." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "JMS\\Serializer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.", + "homepage": "http://jmsyst.com/libs/serializer", + "keywords": [ + "deserialization", + "jaxb", + "json", + "serialization", + "xml" + ], + "time": "2019-12-14T20:49:23+00:00" + }, + { + "name": "jms/serializer-bundle", + "version": "3.5.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/JMSSerializerBundle.git", + "reference": "5793ec59b2243365a625c0fd78415732097c11e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/JMSSerializerBundle/zipball/5793ec59b2243365a625c0fd78415732097c11e8", + "reference": "5793ec59b2243365a625c0fd78415732097c11e8", + "shasum": "" + }, + "require": { + "jms/serializer": "^2.3|^3.0", + "php": "^7.2", + "symfony/dependency-injection": "^3.3 || ^4.0 || ^5.0", + "symfony/framework-bundle": "^3.0 || ^4.0 || ^5.0" + }, + "require-dev": { + "doctrine/orm": "^2.4", + "phpunit/phpunit": "^6.0", + "symfony/expression-language": "^3.0 || ^4.0 || ^5.0", + "symfony/finder": "^3.0 || ^4.0 || ^5.0", + "symfony/form": "^3.0 || ^4.0 || ^5.0", + "symfony/stopwatch": "^3.0 || ^4.0 || ^5.0", + "symfony/twig-bundle": "*", + "symfony/validator": "^3.0 || ^4.0 || ^5.0", + "symfony/yaml": "^3.0 || ^4.0 || ^5.0" + }, + "suggest": { + "jms/di-extra-bundle": "Required to get lazy loading (de)serialization visitors, ^1.3", + "symfony/finder": "Required for cache warmup, supported versions ^3.0|^4.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "JMS\\SerializerBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "Allows you to easily serialize, and deserialize data of any complexity", + "homepage": "http://jmsyst.com/bundles/JMSSerializerBundle", + "keywords": [ + "deserialization", + "json", + "serialization", + "xml" + ], + "time": "2019-11-29T13:03:07+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.99", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "shasum": "" + }, + "require": { + "php": "^7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "time": "2018-07-02T15:55:56+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/log", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2019-11-01T11:05:21+00:00" + }, + { + "name": "ramsey/uuid", + "version": "3.9.2", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "7779489a47d443f845271badbdcedfe4df8e06fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/7779489a47d443f845271badbdcedfe4df8e06fb", + "reference": "7779489a47d443f845271badbdcedfe4df8e06fb", + "shasum": "" + }, + "require": { + "ext-json": "*", + "paragonie/random_compat": "^1 | ^2 | 9.99.99", + "php": "^5.4 | ^7 | ^8", + "symfony/polyfill-ctype": "^1.8" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "codeception/aspect-mock": "^1 | ^2", + "doctrine/annotations": "^1.2", + "goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1", + "jakub-onderka/php-parallel-lint": "^1", + "mockery/mockery": "^0.9.11 | ^1", + "moontoast/math": "^1.1", + "paragonie/random-lib": "^2", + "php-mock/php-mock-phpunit": "^0.3 | ^1.1", + "phpunit/phpunit": "^4.8 | ^5.4 | ^6.5", + "squizlabs/php_codesniffer": "^3.5" + }, + "suggest": { + "ext-ctype": "Provides support for PHP Ctype functions", + "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", + "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator", + "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", + "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\Uuid\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + }, + { + "name": "Marijn Huizendveld", + "email": "marijn.huizendveld@gmail.com" + }, + { + "name": "Thibaud Fabre", + "email": "thibaud@aztech.io" + } + ], + "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", + "homepage": "https://github.com/ramsey/uuid", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "time": "2019-12-17T08:18:51+00:00" + }, + { + "name": "ramsey/uuid-doctrine", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid-doctrine.git", + "reference": "2a56db8e68bff487508244f5a2008075279d0255" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid-doctrine/zipball/2a56db8e68bff487508244f5a2008075279d0255", + "reference": "2a56db8e68bff487508244f5a2008075279d0255", + "shasum": "" + }, + "require": { + "doctrine/orm": "^2.5", + "php": "^5.4 || ^7.0", + "ramsey/uuid": "^3.0" + }, + "require-dev": { + "jakub-onderka/php-parallel-lint": "^1.0", + "mockery/mockery": "^0.9 || ^1.1", + "php-coveralls/php-coveralls": "^1.1 || ^2.1", + "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5", + "squizlabs/php_codesniffer": "^3.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ramsey\\Uuid\\Doctrine\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marijn Huizendveld", + "email": "marijn.huizendveld@gmail.com" + }, + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "http://benramsey.com" + } + ], + "description": "Allow the use of a ramsey/uuid UUID as Doctrine field type.", + "homepage": "https://github.com/ramsey/uuid-doctrine", + "keywords": [ + "doctrine", + "guid", + "identifier", + "uuid" + ], + "time": "2018-08-11T21:01:22+00:00" + }, + { + "name": "retailcrm/api-client-php", + "version": "dev-add-logger", + "source": { + "type": "git", + "url": "https://github.com/raulleo/api-client-php.git", + "reference": "55c444e038c9741dee739f9b6c0acbe8f8247bd6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/raulleo/api-client-php/zipball/55c444e038c9741dee739f9b6c0acbe8f8247bd6", + "reference": "55c444e038c9741dee739f9b6c0acbe8f8247bd6", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "php": ">=5.4.0", + "psr/log": "^1.1" + }, + "require-dev": { + "apigen/apigen": "4.*", + "phpunit/phpunit": "4.*", + "squizlabs/php_codesniffer": "3.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-0": { + "RetailCrm\\": "lib/" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "retailCRM", + "email": "support@retailcrm.ru" + } + ], + "description": "PHP client for retailCRM API", + "homepage": "http://www.retailcrm.ru/", + "keywords": [ + "API", + "REST", + "retailCRM" + ], + "support": { + "email": "support@retailcrm.ru", + "source": "https://github.com/raulleo/api-client-php/tree/add-logger" + }, + "time": "2019-08-29T15:00:10+00:00" + }, + { + "name": "symfony/cache", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "6e8d978878ae5de705ec9fabbb6011cc18776bc9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/6e8d978878ae5de705ec9fabbb6011cc18776bc9", + "reference": "6e8d978878ae5de705ec9fabbb6011cc18776bc9", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "psr/cache": "~1.0", + "psr/log": "~1.0", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/service-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0" + }, + "conflict": { + "doctrine/dbal": "<2.5", + "symfony/dependency-injection": "<4.4", + "symfony/http-kernel": "<4.4", + "symfony/var-dumper": "<4.4" + }, + "provide": { + "psr/cache-implementation": "1.0", + "psr/simple-cache-implementation": "1.0", + "symfony/cache-implementation": "1.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "~1.6", + "doctrine/dbal": "~2.5", + "predis/predis": "~1.1", + "psr/simple-cache": "^1.0", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Cache component with PSR-6, PSR-16, and tags", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "time": "2019-12-12T13:03:32+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "23ed8bfc1a4115feca942cb5f1aacdf3dcdf3c16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/23ed8bfc1a4115feca942cb5f1aacdf3dcdf3c16", + "reference": "23ed8bfc1a4115feca942cb5f1aacdf3dcdf3c16", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "psr/cache": "^1.0" + }, + "suggest": { + "symfony/cache-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-11-18T17:27:11+00:00" + }, + { + "name": "symfony/config", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "7f930484966350906185ba0a604728f7898b7ba0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/7f930484966350906185ba0a604728f7898b7ba0", + "reference": "7f930484966350906185ba0a604728f7898b7ba0", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/filesystem": "^4.4|^5.0", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<4.4" + }, + "require-dev": { + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^4.4|^5.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Config Component", + "homepage": "https://symfony.com", + "time": "2019-12-18T13:50:31+00:00" + }, + { + "name": "symfony/console", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "fe6e3cd889ca64172d7a742a2eb058541404ef47" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/fe6e3cd889ca64172d7a742a2eb058541404ef47", + "reference": "fe6e3cd889ca64172d7a742a2eb058541404ef47", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/dependency-injection": "<4.4", + "symfony/event-dispatcher": "<4.4", + "symfony/lock": "<4.4", + "symfony/process": "<4.4" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2019-12-17T13:20:22+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "f9dbfbf487d08f60b1c83220edcd16559d1e40a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f9dbfbf487d08f60b1c83220edcd16559d1e40a2", + "reference": "f9dbfbf487d08f60b1c83220edcd16559d1e40a2", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "psr/container": "^1.0", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/config": "<5.0", + "symfony/finder": "<4.4", + "symfony/proxy-manager-bridge": "<4.4", + "symfony/yaml": "<4.4" + }, + "provide": { + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0" + }, + "require-dev": { + "symfony/config": "^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/yaml": "^4.4|^5.0" + }, + "suggest": { + "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", + "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DependencyInjection Component", + "homepage": "https://symfony.com", + "time": "2019-12-19T16:01:11+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "460863313bd3212d7c38e1b40602cbcfeeeea4a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/460863313bd3212d7c38e1b40602cbcfeeeea4a5", + "reference": "460863313bd3212d7c38e1b40602cbcfeeeea4a5", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "psr/log": "^1.0", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony ErrorHandler Component", + "homepage": "https://symfony.com", + "time": "2019-12-16T14:48:47+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "7b738a51645e10f864cc25c24d232fb03f37b475" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7b738a51645e10f864cc25c24d232fb03f37b475", + "reference": "7b738a51645e10f864cc25c24d232fb03f37b475", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/event-dispatcher-contracts": "^2" + }, + "conflict": { + "symfony/dependency-injection": "<4.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^4.4|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2019-11-18T17:27:11+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "af23c2584d4577d54661c434446fb8fbed6025dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/af23c2584d4577d54661c434446fb8fbed6025dd", + "reference": "af23c2584d4577d54661c434446fb8fbed6025dd", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "psr/event-dispatcher": "^1" + }, + "suggest": { + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-11-18T17:27:11+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "1d71f670bc5a07b9ccc97dc44f932177a322d4e6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/1d71f670bc5a07b9ccc97dc44f932177a322d4e6", + "reference": "1d71f670bc5a07b9ccc97dc44f932177a322d4e6", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2019-11-26T23:25:11+00:00" + }, + { + "name": "symfony/finder", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "17874dd8ab9a19422028ad56172fb294287a701b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/17874dd8ab9a19422028ad56172fb294287a701b", + "reference": "17874dd8ab9a19422028ad56172fb294287a701b", + "shasum": "" + }, + "require": { + "php": "^7.2.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2019-11-18T17:27:11+00:00" + }, + { + "name": "symfony/framework-bundle", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "36e51776b231d8e224da4ce4c60079540acd1c55" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/36e51776b231d8e224da4ce4c60079540acd1c55", + "reference": "36e51776b231d8e224da4ce4c60079540acd1c55", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": "^7.2.5", + "symfony/cache": "^4.4|^5.0", + "symfony/config": "^5.0", + "symfony/dependency-injection": "^5.0.1", + "symfony/error-handler": "^4.4.1|^5.0.1", + "symfony/filesystem": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/http-kernel": "^5.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/routing": "^5.0" + }, + "conflict": { + "doctrine/persistence": "<1.3", + "phpdocumentor/reflection-docblock": "<3.0", + "phpdocumentor/type-resolver": "<0.2.1", + "phpunit/phpunit": "<5.4.3", + "symfony/asset": "<4.4", + "symfony/browser-kit": "<4.4", + "symfony/console": "<4.4", + "symfony/dom-crawler": "<4.4", + "symfony/dotenv": "<4.4", + "symfony/form": "<4.4", + "symfony/http-client": "<4.4", + "symfony/lock": "<4.4", + "symfony/mailer": "<4.4", + "symfony/messenger": "<4.4", + "symfony/mime": "<4.4", + "symfony/property-info": "<4.4", + "symfony/serializer": "<4.4", + "symfony/stopwatch": "<4.4", + "symfony/translation": "<5.0", + "symfony/twig-bridge": "<4.4", + "symfony/twig-bundle": "<4.4", + "symfony/validator": "<4.4", + "symfony/web-profiler-bundle": "<4.4", + "symfony/workflow": "<4.4" + }, + "require-dev": { + "doctrine/annotations": "~1.7", + "doctrine/cache": "~1.0", + "paragonie/sodium_compat": "^1.8", + "phpdocumentor/reflection-docblock": "^3.0|^4.0", + "symfony/asset": "^4.4|^5.0", + "symfony/browser-kit": "^4.4|^5.0", + "symfony/console": "^4.4|^5.0", + "symfony/css-selector": "^4.4|^5.0", + "symfony/dom-crawler": "^4.4|^5.0", + "symfony/dotenv": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/form": "^4.4|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/mailer": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/process": "^4.4|^5.0", + "symfony/property-info": "^4.4|^5.0", + "symfony/security-csrf": "^4.4|^5.0", + "symfony/security-http": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/stopwatch": "^4.4|^5.0", + "symfony/string": "~5.0.0", + "symfony/translation": "^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/validator": "^4.4|^5.0", + "symfony/web-link": "^4.4|^5.0", + "symfony/workflow": "^4.4|^5.0", + "symfony/yaml": "^4.4|^5.0", + "twig/twig": "^2.10|^3.0" + }, + "suggest": { + "ext-apcu": "For best performance of the system caches", + "symfony/console": "For using the console commands", + "symfony/form": "For using forms", + "symfony/property-info": "For using the property_info service", + "symfony/serializer": "For using the serializer service", + "symfony/validator": "For using validation", + "symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering", + "symfony/yaml": "For using the debug:config and lint:yaml commands" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\FrameworkBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony FrameworkBundle", + "homepage": "https://symfony.com", + "time": "2019-12-17T10:33:13+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "5dd7f6be6e62d86ba6f3154cf40e78936367978b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5dd7f6be6e62d86ba6f3154cf40e78936367978b", + "reference": "5dd7f6be6e62d86ba6f3154cf40e78936367978b", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/mime": "^4.4|^5.0", + "symfony/polyfill-mbstring": "~1.1" + }, + "require-dev": { + "predis/predis": "~1.0", + "symfony/expression-language": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony HttpFoundation Component", + "homepage": "https://symfony.com", + "time": "2019-12-19T16:01:11+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "00ce30602f3f690e66a63c327743d7b26c723b2e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/00ce30602f3f690e66a63c327743d7b26c723b2e", + "reference": "00ce30602f3f690e66a63c327743d7b26c723b2e", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "psr/log": "~1.0", + "symfony/error-handler": "^4.4|^5.0", + "symfony/event-dispatcher": "^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9" + }, + "conflict": { + "symfony/browser-kit": "<4.4", + "symfony/cache": "<5.0", + "symfony/config": "<5.0", + "symfony/dependency-injection": "<4.4", + "symfony/doctrine-bridge": "<5.0", + "symfony/form": "<5.0", + "symfony/http-client": "<5.0", + "symfony/mailer": "<5.0", + "symfony/messenger": "<5.0", + "symfony/translation": "<5.0", + "symfony/twig-bridge": "<5.0", + "symfony/validator": "<5.0", + "twig/twig": "<2.4" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/cache": "~1.0", + "symfony/browser-kit": "^4.4|^5.0", + "symfony/config": "^5.0", + "symfony/console": "^4.4|^5.0", + "symfony/css-selector": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/dom-crawler": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "symfony/routing": "^4.4|^5.0", + "symfony/stopwatch": "^4.4|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^2.4|^3.0" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony HttpKernel Component", + "homepage": "https://symfony.com", + "time": "2019-12-19T18:35:03+00:00" + }, + { + "name": "symfony/lock", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/lock.git", + "reference": "7ccaee23cc5b8884c9700eef4ccee03f85ff7821" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/lock/zipball/7ccaee23cc5b8884c9700eef4ccee03f85ff7821", + "reference": "7ccaee23cc5b8884c9700eef4ccee03f85ff7821", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "psr/log": "~1.0" + }, + "conflict": { + "doctrine/dbal": "<2.5" + }, + "require-dev": { + "doctrine/dbal": "~2.5", + "mongodb/mongodb": "~1.1", + "predis/predis": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Lock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jérémy Derussé", + "email": "jeremy@derusse.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Lock Component", + "homepage": "https://symfony.com", + "keywords": [ + "cas", + "flock", + "locking", + "mutex", + "redlock", + "semaphore" + ], + "time": "2019-12-03T16:35:18+00:00" + }, + { + "name": "symfony/mime", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "0e6a4ced216e49d457eddcefb61132173a876d79" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/0e6a4ced216e49d457eddcefb61132173a876d79", + "reference": "0e6a4ced216e49d457eddcefb61132173a876d79", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10", + "symfony/dependency-injection": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A library to manipulate MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "time": "2019-11-30T14:12:50+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.13.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", + "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.13-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2019-11-27T13:56:44+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.13.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "6f9c239e61e1b0c9229a28ff89a812dc449c3d46" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/6f9c239e61e1b0c9229a28ff89a812dc449c3d46", + "reference": "6f9c239e61e1b0c9229a28ff89a812dc449c3d46", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/polyfill-mbstring": "^1.3", + "symfony/polyfill-php72": "^1.9" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.13-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "time": "2019-11-27T13:56:44+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.13.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f", + "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.13-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2019-11-27T14:18:11+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.13.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "66fea50f6cb37a35eea048d75a7d99a45b586038" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/66fea50f6cb37a35eea048d75a7d99a45b586038", + "reference": "66fea50f6cb37a35eea048d75a7d99a45b586038", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.13-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2019-11-27T13:56:44+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.13.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "4b0e2222c55a25b4541305a053013d5647d3a25f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/4b0e2222c55a25b4541305a053013d5647d3a25f", + "reference": "4b0e2222c55a25b4541305a053013d5647d3a25f", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.13-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2019-11-27T16:25:15+00:00" + }, + { + "name": "symfony/routing", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "120c5fa4f4ef5466cbb510ece8126e0007285301" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/120c5fa4f4ef5466cbb510ece8126e0007285301", + "reference": "120c5fa4f4ef5466cbb510ece8126e0007285301", + "shasum": "" + }, + "require": { + "php": "^7.2.5" + }, + "conflict": { + "symfony/config": "<5.0", + "symfony/dependency-injection": "<4.4", + "symfony/yaml": "<4.4" + }, + "require-dev": { + "doctrine/annotations": "~1.2", + "psr/log": "~1.0", + "symfony/config": "^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/yaml": "^4.4|^5.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Routing Component", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "time": "2019-12-12T13:03:32+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "144c5e51266b281231e947b51223ba14acf1a749" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749", + "reference": "144c5e51266b281231e947b51223ba14acf1a749", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-11-18T17:27:11+00:00" + }, + { + "name": "symfony/translation", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "3ae6fad7a3dc2d99a023f9360184628fc44acbb3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/3ae6fad7a3dc2d99a023f9360184628fc44acbb3", + "reference": "3ae6fad7a3dc2d99a023f9360184628fc44acbb3", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2" + }, + "conflict": { + "symfony/config": "<4.4", + "symfony/dependency-injection": "<5.0", + "symfony/http-kernel": "<5.0", + "symfony/twig-bundle": "<5.0", + "symfony/yaml": "<4.4" + }, + "provide": { + "symfony/translation-implementation": "2.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^4.4|^5.0", + "symfony/console": "^4.4|^5.0", + "symfony/dependency-injection": "^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/http-kernel": "^5.0", + "symfony/intl": "^4.4|^5.0", + "symfony/service-contracts": "^1.1.2|^2", + "symfony/yaml": "^4.4|^5.0" + }, + "suggest": { + "psr/log-implementation": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Translation Component", + "homepage": "https://symfony.com", + "time": "2019-12-12T13:03:32+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "8cc682ac458d75557203b2f2f14b0b92e1c744ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/8cc682ac458d75557203b2f2f14b0b92e1c744ed", + "reference": "8cc682ac458d75557203b2f2f14b0b92e1c744ed", + "shasum": "" + }, + "require": { + "php": "^7.2.5" + }, + "suggest": { + "symfony/translation-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-11-18T17:27:11+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "d7bc61d5d335fa9b1b91e14bb16861e8ca50f53a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/d7bc61d5d335fa9b1b91e14bb16861e8ca50f53a", + "reference": "d7bc61d5d335fa9b1b91e14bb16861e8ca50f53a", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "phpunit/phpunit": "<5.4.3", + "symfony/console": "<4.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^2.4|^3.0" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony mechanism for exploring and dumping PHP variables", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "time": "2019-12-18T13:50:31+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "1b9653e68d5b701bf6d9c91bdd3660078c9f4f28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/1b9653e68d5b701bf6d9c91bdd3660078c9f4f28", + "reference": "1b9653e68d5b701bf6d9c91bdd3660078c9f4f28", + "shasum": "" + }, + "require": { + "php": "^7.2.5" + }, + "require-dev": { + "symfony/var-dumper": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A blend of var_export() + serialize() to turn any serializable data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" + ], + "time": "2019-12-01T08:48:26+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "retailcrm/api-client-php": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": "^7.3" + }, + "platform-dev": [] +} diff --git a/docker-compose-test.yml b/docker-compose-test.yml new file mode 100644 index 0000000..7a2bf2a --- /dev/null +++ b/docker-compose-test.yml @@ -0,0 +1,28 @@ +version: '2.1' +services: + automate_app: + image: "gwinn/php:7.1" + working_dir: /automate + user: ${UID:-1000}:${GID:-1000} + volumes: + - ./:/automate + links: + - "automate_db:automate_db" + - "automate_cache:automate_cache" + - "automate_queue:automate_queue" + automate_db: + image: "postgres:9.5" + ports: + - ${POSTGRES_ADDRESS:-127.0.0.1:5432}:5432 + environment: + - POSTGRES_PASSWORD=automate + - POSTGRES_USER=automate + - POSTGRES_DB=automate + automate_cache: + image: "redis:alpine" + ports: + - "6379:6379" + automate_queue: + image: "schickling/beanstalkd:latest" + ports: + - "11300:11300" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..57478ac --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,46 @@ +version: '2.1' +services: + automate_app: + image: "gwinn/php:7.1" + ports: + - "80:8080" + working_dir: /automate + user: ${UID:-1000}:${GID:-1000} + volumes: + - ./:/automate + depends_on: + - automate_db + - automate_db_test + - automate_cache + - automate_queue + links: + - "automate_db:automate_db" + - "automate_db_test:automate_db_test" + - "automate_cache:automate_cache" + - "automate_queue:automate_queue" + command: make run + automate_db: + image: "postgres:9.5" + ports: + - ${POSTGRES_ADDRESS:-127.0.0.1:5432}:5432 + environment: + - POSTGRES_PASSWORD=automate + - POSTGRES_USER=automate + - POSTGRES_DB=automate + automate_db_test: + image: "postgres:9.5" + ports: + - ${POSTGRES_ADDRESS:-127.0.0.1:5434}:5434 + environment: + - PGPORT=5434 + - POSTGRES_PASSWORD=automate + - POSTGRES_USER=automate + - POSTGRES_DB=automate + automate_cache: + image: "redis:alpine" + ports: + - "6379:6379" + automate_queue: + image: "schickling/beanstalkd:latest" + ports: + - "11300:11300" diff --git a/tests/Controller/AbstractExchangeControllerTest.php b/tests/Controller/AbstractExchangeControllerTest.php new file mode 100644 index 0000000..9940498 --- /dev/null +++ b/tests/Controller/AbstractExchangeControllerTest.php @@ -0,0 +1,102 @@ +getContainer(); + + $req = $this->createMock(Request::class); + $req->$type = new ParameterBag([ + 'clientId' => 'clientId', + $dataKey => $data + ]); + $req->expects($this->any()) + ->method('isMethod') + ->with('post') + ->willReturn($type == 'request'); + + $reqStack = $this->createMock(RequestStack::class); + $reqStack->expects($this->any()) + ->method('getCurrentRequest') + ->willReturn($req); + + $res = $this->getExchangeControllerMock($reqStack)->{$method.'Action'}($req); + $content = json_decode($res->getContent(), true); + + $assertions($res, $content); + } + + /** + * @return \PHPUnit\Framework\MockObject\MockObject + */ + protected function getExchangeControllerMock($reqStack) + { + $container = self::$kernel->getContainer(); + $serviceMock = $this->getServiceMock(); + + $exchangeControllerClassName = $this->getExchangeControllerClassName(); + $exchangeControllerMock = $this->getMockBuilder($exchangeControllerClassName) + ->setMethods(['getDeliveryApi']) + ->setConstructorArgs([ + $container->get('doctrine.orm.entity_manager'), + $container->get('jms_serializer'), + $reqStack, + ]) + ->getMock(); + + $exchangeControllerMock->expects($this->any()) + ->method('getDeliveryApi') + ->willReturn($serviceMock); + + $exchangeControllerMock->setContainer($container); + + return $exchangeControllerMock; + } +}