From 9618ce7a7dd3e6bfd73978a73c6c8f9fe99b76c3 Mon Sep 17 00:00:00 2001 From: aurelienCastellarnau Date: Fri, 22 Mar 2019 15:03:04 +0100 Subject: [PATCH 01/13] [FEATURE#128384] feat(sprinter_service_provider): Migration vers Symfony4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Mise en place de la DI - Réécriture du service pour coller à la disparition d'app et l'arrivée du container - Ajout d'un dumping de configuration (prepend) - Ajout des configurations pour sprinter et pour le producer rabbitMQ de sprinter - Missing tests --- LICENSE.md | 2 +- README.md | 58 +++++- composer.json | 73 +++++--- config/packages/old_sound_rabbit_mq.yaml | 9 + config/packages/sprinter.yaml | 4 + config/services.yaml | 25 +++ src/DependencyInjection/Configuration.php | 53 ++++++ src/DependencyInjection/SprinterExtension.php | 98 ++++++++++ src/SPrinter.php | 46 ----- src/SPrinterServiceProvider.php | 38 ---- src/Services/Sprinter.php | 176 ++++++++++++++++++ src/SprinterBundle.php | 14 ++ 12 files changed, 476 insertions(+), 120 deletions(-) create mode 100644 config/packages/old_sound_rabbit_mq.yaml create mode 100644 config/packages/sprinter.yaml create mode 100644 config/services.yaml create mode 100644 src/DependencyInjection/Configuration.php create mode 100644 src/DependencyInjection/SprinterExtension.php delete mode 100644 src/SPrinter.php delete mode 100644 src/SPrinterServiceProvider.php create mode 100644 src/Services/Sprinter.php create mode 100644 src/SprinterBundle.php diff --git a/LICENSE.md b/LICENSE.md index 0f1474c..f87fc44 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 ETNA SARL +Copyright (c) 2019 ETNA SARL Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 06a41da..421ce65 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,9 @@ sprinter-service-provider -========================= +Dependency Status Scrutinizer Code Quality -[![Dependency Status](https://www.versioneye.com/user/projects/53dde6d38e78abc422000010/badge.svg)](https://www.versioneye.com/user/projects/53dde6d38e78abc422000010) -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/etna-alternance/composer-sprinter-service-provider/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/etna-alternance/composer-sprinter-service-provider/?branch=master) +## Installation +Modifier composer.json : -Installation ------------- - -Modifier `composer.json` : - -``` { // ... "require": { @@ -18,8 +12,52 @@ Modifier `composer.json` : "repositories": [ { "type": "composer", - "url": "http://blu-composer.herokuapp.com" + "url": "https://blu-composer.herokuapp.com" } ] } +## Configuration +### Environnement + +Dans le fichier d'env : + +Une variable RABBITMQ_URL qui contient l'adresse du serveur rabbitMQ +Une variable RABBITMQ_VHOST qui contient le type d'environnement souhaité ```production```||```development```||```/test-behat``` + ``` +RABBITMQ_URL=amqp://development:ieJoh8sa@rabbitmq.etna.local:5672 +RABBITMQ_VHOST=development +``` + +### Sprinter et RabbitMQ + +La description de la default routing_key est située dans SprinterServiceProvider/config/packages/sprinter.yaml + +La description du producer rabbitMQ est située dans SprinterServiceProvider/config/packages/old_sound_rabbit_mq.yaml + +Lors de l'injection de la dépendance, la configuration rabbitMQ est ajoutée (prepend) à la configuration du parent. + +Si le parent redéfini la default routing_key ou le producer SPrinter, il écrase la configuration définie au niveau SprinterServiceProvider + +*****Exemple de sprinter.yaml:***** + +``` +default: + routing_key: sprinter.lefran_f +``` + +*****Exemple de old_sound_rabbit_mq.yaml:***** + +``` +connections: + default: + url: '%env(RABBITMQ_URL)%' + vhost: '%env(RABBITMQ_VHOST)%' +producers: + # use 'old_sound_rabbit_mq.sprinter_producer' service to send data. + SPrinter: + connection: default + exchange_options: { name: 'SPrinter', type: direct, passive: false, durable: true, auto_delete: false } +``` + +L'ordre d'appel des bundles n'a pas d'importance. diff --git a/composer.json b/composer.json index ee36167..253073d 100644 --- a/composer.json +++ b/composer.json @@ -1,37 +1,60 @@ { - "name": "etna/sprinter-service-provider", - "description": "SPrinter Service Provider", - "keywords": ["sprinter", "rabbitmq", "silex"], - "license": "proprietary", - "authors": [ - { - "name": "ETNA", - "email": "dev@etna-alternance.net", - "homepage": "http://etna-alternance.net" - } - ], + "type": "symfony-bundle", + "license": "BLU", "require": { - "php": ">=5.5", - "silex/silex": "1.x", - "etna/rabbitmq-service-provider": "0.x" + "php": "^7.1.3", + "ext-ctype": "*", + "ext-iconv": "*", + "php-amqplib/rabbitmq-bundle": "^1.14", + "symfony/console": "4.2.*", + "symfony/dotenv": "4.2.*", + "symfony/flex": "^1.1", + "symfony/framework-bundle": "4.2.*", + "symfony/yaml": "4.2.*" }, "config": { - "bin-dir": "bin" + "preferred-install": { + "*": "dist" + }, + "sort-packages": true }, "autoload": { "psr-4": { - "ETNA\\Silex\\Provider\\SPrinter\\": "src" + "ETNA\\Sprinter\\": "src/" } }, - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" + "autoload-dev": { + "psr-4": { + "ETNA\\Sprinter\\Tests\\": "tests/" } }, - "repositories": [ - { - "type": "composer", - "url": "http://blu-composer.herokuapp.com/" - } - ] + "replace": { + "paragonie/random_compat": "2.*", + "symfony/polyfill-ctype": "*", + "symfony/polyfill-iconv": "*", + "symfony/polyfill-php71": "*", + "symfony/polyfill-php70": "*", + "symfony/polyfill-php56": "*" + }, + "scripts": { + "auto-scripts": { + "cache:clear": "symfony-cmd", + "assets:install %PUBLIC_DIR%": "symfony-cmd" + }, + "post-install-cmd": [ + "@auto-scripts" + ], + "post-update-cmd": [ + "@auto-scripts" + ] + }, + "conflict": { + "symfony/symfony": "*" + }, + "extra": { + "symfony": { + "allow-contrib": false, + "require": "4.2.*" + } + } } diff --git a/config/packages/old_sound_rabbit_mq.yaml b/config/packages/old_sound_rabbit_mq.yaml new file mode 100644 index 0000000..7448b5d --- /dev/null +++ b/config/packages/old_sound_rabbit_mq.yaml @@ -0,0 +1,9 @@ +connections: + default: + url: '%env(RABBITMQ_URL)%' + vhost: '%env(RABBITMQ_VHOST)%' +producers: + # use 'old_sound_rabbit_mq.sprinter_producer' service to send data. + SPrinter: + connection: default + exchange_options: { name: 'SPrinter', type: direct, passive: false, durable: true, auto_delete: false } diff --git a/config/packages/sprinter.yaml b/config/packages/sprinter.yaml new file mode 100644 index 0000000..066bc07 --- /dev/null +++ b/config/packages/sprinter.yaml @@ -0,0 +1,4 @@ +default: + routing_key: sprinter.lefran_f +# On a pas forcément besoin d'un fichier sprinter.yaml +# dans le bundle parent... diff --git a/config/services.yaml b/config/services.yaml new file mode 100644 index 0000000..cdb0889 --- /dev/null +++ b/config/services.yaml @@ -0,0 +1,25 @@ +# This file is the entry point to configure your own services. +# Files in the packages/ subdirectory configure your dependencies. + +# Put parameters here that don't need to change on each machine where the app is deployed +# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration +services: + # default configuration for services in *this* file + _defaults: + autowire: true # Automatically injects dependencies in your services. + autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. + + # makes classes in src/ available to be used as services + # this creates a service per class whose id is the fully-qualified class name + ETNA\Sprinter\: + resource: '../src/*' + exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}' + + sprinter.service: + class: 'ETNA\Sprinter\Services\Sprinter' + autowire: true + + ETNA\Sprinter\Services\Sprinter: '@sprinter.service' + + # add more service definitions when explicit configuration is needed + # please note that last definitions always *replace* previous ones diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php new file mode 100644 index 0000000..27a2dcf --- /dev/null +++ b/src/DependencyInjection/Configuration.php @@ -0,0 +1,53 @@ + + */ + +declare(strict_types=1); + +namespace ETNA\Sprinter\DependencyInjection; + +use Symfony\Component\Config\Definition\Builder\TreeBuilder; +use Symfony\Component\Config\Definition\ConfigurationInterface; + +/** + * Classe décrivant la configuration du SprinterBundle. + * + * Exemple de configuration yaml : + * + *
+ *    sprinter:
+ *        default:
+ *            routing_key: lefran_f
+ * 
+ * + */ +class Configuration implements ConfigurationInterface +{ + /** + * Configure la structure de la configuration du SprinterBundle. + * + * @return TreeBuilder Contient la config + */ + public function getConfigTreeBuilder() + { + $tree_builder = new TreeBuilder(); + $root_node = $tree_builder->root('sprinter'); + + $root_node + ->children() + ->arrayNode('default') + ->children() + ->scalarNode('routing_key') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->end() + ->end() + ->end(); + + return $tree_builder; + } +} diff --git a/src/DependencyInjection/SprinterExtension.php b/src/DependencyInjection/SprinterExtension.php new file mode 100644 index 0000000..46d4504 --- /dev/null +++ b/src/DependencyInjection/SprinterExtension.php @@ -0,0 +1,98 @@ + + */ + +declare(strict_types=1); + +namespace ETNA\Sprinter\DependencyInjection; + +use Symfony\Component\HttpKernel\DependencyInjection\Extension; +use Symfony\Component\Config\FileLocator; +use Symfony\Component\Yaml\Yaml; +use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; + +/** + * On définit cette classe pour personnaliser le processus de parsing de la configuration de notre bundle. + * + * Entre autres on ajoute la configuration dans les paramêtres du container Symfony + * Ici, on va aussi dumper les fichiers de conf .yaml du bundle dans le bundle parent + * Grâce à l'interface PrependExtensionInterface, on va pouvoir intervenir sur les + * conf .yaml d'extensions loadées depuis l'extérieur. + */ +class SprinterExtension extends Extension implements PrependExtensionInterface +{ + /** + * Implémentation de l'interface PrependExtensionInterface + * Cette fonction permet d'intervenir sur les fichiers de configuration + * du dossier config/packages/*.yaml du bundle parent + * + * @param ContainerBuilder $container Le container du bundle parent + */ + public function prepend(ContainerBuilder $container) + { + // récupérer le dossier de configs de la lib + $configPath = __DIR__.'/../../config/packages/'; + $sprinterYml = "sprinter.yaml"; + $rabbitMqYml = "old_sound_rabbit_mq.yaml"; + // on parse les configurations + $sprinterConf = Yaml::parse(file_get_contents($configPath.$sprinterYml)); + $rabbitMqConf = Yaml::parse(file_get_contents($configPath.$rabbitMqYml)); + // on récupère les bundles + $bundles = $container->getParameter('kernel.bundles'); + // on vérifie que le bundle rabbitMq est bien intégré au projet + // sinon on renvoi une exception indiquant comment intégré rmq + // ce cas de figure devrait être géré par composer + if (!isset($bundles["OldSoundRabbitMqBundle"])) + throw new \Exception("SprinterBundle require RabbitMQ: try composer require php-amqplib/rabbitmq-bundle", 500); + // on récupère les extensions et on intervient sur les deux extensions concernées ici + foreach ($container->getExtensions() as $name => $extension) { + switch ($name) { + // sur l'extension sprinter, on définit une default routin_key d'office (cf: SprinterServiceProvider/config/packages) + // on va pouvoir exécuter le processConfiguration sur Sprinter + // puisqu'on est dans la classe extension du bundle Sprinter + case 'sprinter': + $container->prependExtensionConfig($name, $sprinterConf); + $sprinterConf = $container->getExtensionConfig($name); + break; + // pour rabbitmq, on ne peut pas exécuter le processConfiguration + // cela ne nous empêche pas d'intervenir sur la configuration .yaml + // Si le fichier old_sound_rabbit_mq.yaml du bundle parent + // défini un producer SPrinter, celui défini ici sera écrasé. + case 'old_sound_rabbit_mq': + $container->prependExtensionConfig($name, $rabbitMqConf); + break; + default: + break; + } + } + $config = $this->processConfiguration(new Configuration(), $sprinterConf); + } + + /** + * Cette fonction est appelée par symfony et permet + * le chargement de la configuration du bundle + * dans les paramètres du container. + * La config provient du bundle appelant localisé dans le fichier config/packages/sprinter.yaml + * mais qui a été modifiée dans le processus de prepend. + * + * Ensuite on load la config du/des services dans le dossier Resources/config. + * + * @param array $configs Les éventuels paramètres + * @param ContainerBuilder $container Le container de la configuration + */ + public function load(array $configs, ContainerBuilder $container): void + { + $config = $this->processConfiguration(new Configuration(), $configs); + $container->setParameter("sprinter.default.routing_key", $config["default"]["routing_key"]); + $loader = new YamlFileLoader( + $container, + new FileLocator(__DIR__.'/../../config') + ); + $loader->load('services.yaml'); + } +} diff --git a/src/SPrinter.php b/src/SPrinter.php deleted file mode 100644 index aa97dfa..0000000 --- a/src/SPrinter.php +++ /dev/null @@ -1,46 +0,0 @@ -exchange = $exchange; - $this->routing_key = $options["default.routing_key"]; - } - - public function getDefaultRoutingKey() - { - return $this->routing_key; - } - - public function sendPrint($template, $data, $print_flag, $routing_key = null, $opt = null) - { - $queue_opt = [ - "passive" => false, - "durable" => true, - "exclusive" => false, - "auto_delete" => false, - ]; - $params = [ - "template" => $template, - "data" => $data, - "printflag" => $print_flag - ]; - if ($opt) { - $params = array_merge($params, $opt); - } - - $routing_key = $routing_key ?: $this->routing_key; - - // crée la queue au besoin - $queue = new Queue($routing_key, $this->exchange, $this->exchange->getChannel(), $queue_opt); - - $this->exchange->send($params, $routing_key); - } -} diff --git a/src/SPrinterServiceProvider.php b/src/SPrinterServiceProvider.php deleted file mode 100644 index 366d3f2..0000000 --- a/src/SPrinterServiceProvider.php +++ /dev/null @@ -1,38 +0,0 @@ - $routing_key, - ]; - } - - $app["sprinter"] = $app->share( - function (Application $app) { - return new SPrinter($app["amqp.exchanges"]["SPrinter"], $app["sprinter.options"]); - } - ); - } -} diff --git a/src/Services/Sprinter.php b/src/Services/Sprinter.php new file mode 100644 index 0000000..26ba9d2 --- /dev/null +++ b/src/Services/Sprinter.php @@ -0,0 +1,176 @@ + + */ + +declare(strict_types=1); + +namespace ETNA\Sprinter\Services; + +use Symfony\Component\DependencyInjection\ContainerInterface; +/** + * La classe Sprinter est le service déclaré dans config/service.yaml + * Cette classe accède au container du projet et stocke le producer rabbitMQ et la routing_key + */ +class Sprinter +{ + /** @var ContainerInterface Conteneur de l'application symfony ou sont référencés les paramètres */ + private $container; + + /** @var Producer décrit un producer rabbitMQ, un producer permet de publier sur une queue **/ + private $producer; + + /** @var string décrit le nom du channel par défaut **/ + private $routing_key; + + /** + * Constructeur du service. + * + * @param ContainerInterface $container Le container de l'application symfony + */ + public function __construct(ContainerInterface $container) + { + $this->container = $container; + $this->producer = $container->get('old_sound_rabbit_mq.SPrinter_producer'); + $this->routing_key = $container->getParameter("sprinter.default.routing_key"); + } + + /** + * Getter sur routing_key + * + * @return string + */ + public function getDefaultRoutingKey() + { + return $this->routing_key; + } + + /** + * sendPrint est la fonction principale du service. + * Elle compose un groupe de paramètres nécessaires à une impression + * sur Sprinter et publie ces paramètres sur le producer Sprinter de rabbitMQ + * + * @param string $template_title le nom du fichier template + * @param string $template le contenu du template extrait avec file_get_content + * @param boolean $print_flag paramètre permettant de déterminer si l'on souhaite une impression papier + * @param string $routing_key la routing_key sur laquelle la publication doit avoir lieu + * @param array $sprinter_data l'entité servant à la composition des tokens + * @param array $sprinter_opt les options de l'impression + * + * @return string + */ + public function sendPrint( + $template_title, + $template, + // true | false + $print_flag, + $routing_key = null, + // student or contract, entities + array $sprinter_data, + // exemple: ['printFlag' => $paper] + array $sprinter_opt = [] + ) { + if (!is_array($sprinter_data) || empty($sprinter_data)) { + throw new \Exception("Bad data provided for printing", 400); + } + $template_b64 = base64_encode($template); + $csv = $this->arrayToCsv($sprinter_data, $sprinter_opt["csv_rows"]); + $csv_base64 = base64_encode($csv); + $template = [ + "Name" => $template_title, + "Content" => $template_b64, + ]; + $data = [ + "Name" => "data.csv", + "Content" => $csv_base64, + ]; + $queue_opt = [ + "passive" => false, + "durable" => true, + "exclusive" => false, + "auto_delete" => false, + ]; + $params = [ + "template" => $template, + "data" => $data, + "printflag" => $print_flag + ]; + if ($queue_opt) { + $params = array_merge($params, $queue_opt); + } + $routing_key = $routing_key ?: $this->routing_key; + $this->producer->publish(json_encode($params), $routing_key); + + return $routing_key; + } + + /** + * Cette fonction appartient à la lib etna/CSVUtils + * Elle est donc destinée à bouger quand la lib sera migrée. + * + * Prends un tableau PHP et en génère un csv + * + * @param array $array Array a transformer + * @param int|null &$csv_rows Nombre de rows générées + * + * @return string + */ + private function arrayToCsv(array $array, int &$csv_rows = null) + { + if (true === empty($array)) { + $csv_rows = 0; + return ""; + } + $headers = array_keys($array[0]); + $tokens = array_values($array); + $csv = self::sputcsv($headers, ';', '"', "\n"); + foreach ($tokens as $value) { + if (!empty(array_diff(array_keys($value), $headers))) { + throw new \Exception("Bad csv", 400); + } + $clean_array = str_replace("\n", " ", array_values($value)); + $csv .= self::sputcsv($clean_array, ';', '"', "\n"); + } + $csv = substr_replace($csv, "", -1); + $csv_rows = count($tokens); + + return $csv; + } + + /** + * Cette fonction appartient à la lib etna/CSVUtils + * Elle est donc destinée à bouger quand la lib sera migrée. + * + * Vu que sputcsv n'existe pas dans php :'( + * fonction qui retourne une string csv a partir de l'array fourni + * + * @param array $row Le tableau contenant les données à csvifier + * @param string $delimiter Le caractère délimitant les champs csv + * @param string $enclosure Le caractère à utiliser pour echapper + * @param string $eol Le caractère d'EndOfFile + * + * @return false|string + */ + private function sputcsv(array $row, $delimiter = ',', $enclosure = '"', $eol = "\n") + { + static $file_pointer = false; + + if (false === $file_pointer) { + $file_pointer = fopen('php://temp', 'r+'); + } else { + rewind($file_pointer); + } + if (false === fputcsv($file_pointer, $row, $delimiter, $enclosure)) { + return false; + } + rewind($file_pointer); + $csv = fgets($file_pointer); + if (PHP_EOL !== $eol) { + $csv = substr($csv, 0, (0 - strlen(PHP_EOL))) . $eol; + } + + return $csv; + } +} diff --git a/src/SprinterBundle.php b/src/SprinterBundle.php new file mode 100644 index 0000000..2a0e155 --- /dev/null +++ b/src/SprinterBundle.php @@ -0,0 +1,14 @@ + + */ + +declare(strict_types=1); + +namespace ETNA\Sprinter; + +use Symfony\Component\HttpKernel\Bundle\Bundle; + +class SprinterBundle extends Bundle {} From ccce2518c6ffd7c691591278298de746c64d8361 Mon Sep 17 00:00:00 2001 From: aurelienCastellarnau Date: Fri, 22 Mar 2019 17:55:33 +0100 Subject: [PATCH 02/13] [FEATURE#128384] feat(tests): configuration - Ajout de la TestApp - Ajout de la configuration des tests - Missing features --- .coveralls.yml | 2 + .drone.yml | 20 + .env.test | 4 + .gitignore | 27 ++ .php_cs.dist | 55 +++ .scrutinizer.yml | 8 +- TestApp/app/Kernel.php | 61 +++ TestApp/config/bundles.php | 7 + TestApp/config/packages/framework.yaml | 7 + TestApp/config/routes/annotations.yaml | 3 + TestApp/config/services.yaml | 21 + behat.yml.dist | 12 + build.xml | 66 ++++ composer.json | 80 ++-- config/bootstrap.php | 21 + config/bundles.php | 6 + config/packages/cache.yaml | 19 + config/packages/dev/routing.yaml | 3 + config/packages/framework.yaml | 17 + config/packages/routing.yaml | 4 + config/packages/test/framework.yaml | 4 + config/packages/test/routing.yaml | 3 + config/packages/translation.yaml | 6 + config/routes.yaml | 3 + config/routes/annotations.yaml | 3 + config/services.yaml | 3 + features/bootstrap/bootstrap.php | 4 + features/demo.feature | 12 + phpcs.xml.dist | 19 + phpdoc.xml | 24 ++ phpmd.xml | 52 +++ phpunit.xml.dist | 27 ++ public/index.php | 27 ++ src/Controller/.gitignore | 0 src/Kernel.php | 48 +++ symfony.lock | 508 +++++++++++++++++++++++++ tests/.gitignore | 0 translations/.gitignore | 0 38 files changed, 1148 insertions(+), 38 deletions(-) create mode 100644 .coveralls.yml create mode 100644 .drone.yml create mode 100644 .env.test create mode 100644 .php_cs.dist create mode 100644 TestApp/app/Kernel.php create mode 100755 TestApp/config/bundles.php create mode 100755 TestApp/config/packages/framework.yaml create mode 100755 TestApp/config/routes/annotations.yaml create mode 100755 TestApp/config/services.yaml create mode 100644 behat.yml.dist create mode 100644 build.xml create mode 100644 config/bootstrap.php create mode 100644 config/bundles.php create mode 100644 config/packages/cache.yaml create mode 100644 config/packages/dev/routing.yaml create mode 100644 config/packages/framework.yaml create mode 100644 config/packages/routing.yaml create mode 100644 config/packages/test/framework.yaml create mode 100644 config/packages/test/routing.yaml create mode 100644 config/packages/translation.yaml create mode 100644 config/routes.yaml create mode 100644 config/routes/annotations.yaml create mode 100644 features/bootstrap/bootstrap.php create mode 100644 features/demo.feature create mode 100644 phpcs.xml.dist create mode 100644 phpdoc.xml create mode 100644 phpmd.xml create mode 100644 phpunit.xml.dist create mode 100644 public/index.php create mode 100644 src/Controller/.gitignore create mode 100644 src/Kernel.php create mode 100644 symfony.lock create mode 100644 tests/.gitignore create mode 100644 translations/.gitignore diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 0000000..644bd93 --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1,2 @@ +coverage_clover: tmp/behat/coverage.clover.xml +json_path: tmp/behat/coveralls-upload.json diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..ae0776c --- /dev/null +++ b/.drone.yml @@ -0,0 +1,20 @@ +image: etna/drone-php7:php71 +env: + - APP_ENV=test + - COVERALLS_REPO_TOKEN=$$COVERALLS_TOKEN + - COVERALLS_SERVICE_NAME=drone.io +script: + - composer global require phpdocumentor/phpdocumentor --no-interaction --prefer-dist --no-progress + - composer install --dev --no-interaction --prefer-dist --no-progress --no-scripts + - composer phing + - composer coveralls +services: + - rabbitmq +notify: + slack: + webhook_url: $$SLACK_WEBHOOK_URL + username: drone + channel: $$SLACK_CHANNEL + on_started: true + on_failure: true + on_success: true diff --git a/.env.test b/.env.test new file mode 100644 index 0000000..414430e --- /dev/null +++ b/.env.test @@ -0,0 +1,4 @@ +# define your env variables for the test env here +KERNEL_CLASS='App\Kernel' +APP_SECRET='s$cretf0rt3st' +SYMFONY_DEPRECATIONS_HELPER=999999 diff --git a/.gitignore b/.gitignore index 435c464..58ece3c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,30 @@ bin/ tmp/ vendor/ composer.lock + +###> symfony/framework-bundle ### +/.env.local +/.env.local.php +/.env.*.local +/public/bundles/ +/var/ +/vendor/ +###< symfony/framework-bundle ### + +###> behat/symfony2-extension ### +behat.yml +###< behat/symfony2-extension ### + +###> phpunit/phpunit ### +/phpunit.xml +###< phpunit/phpunit ### + +###> squizlabs/php_codesniffer ### +/.phpcs-cache +/phpcs.xml +###< squizlabs/php_codesniffer ### + +###> friendsofphp/php-cs-fixer ### +/.php_cs +/.php_cs.cache +###< friendsofphp/php-cs-fixer ### diff --git a/.php_cs.dist b/.php_cs.dist new file mode 100644 index 0000000..ae4abec --- /dev/null +++ b/.php_cs.dist @@ -0,0 +1,55 @@ +in(__DIR__ . "/src") +; + +return PhpCsFixer\Config::create() + ->setRules([ + "@PSR1" => true, + "@PSR2" => true, + "@Symfony" => true, + "@Symfony:risky" => true, + "@DoctrineAnnotation" => true, + "@PHP56Migration" => true, + "@PHP56Migration:risky" => true, + "@PHP70Migration" => true, + "@PHP70Migration:risky" => true, + "@PHP71Migration" => true, + "@PHP71Migration:risky" => true, + "binary_operator_spaces" => [ + "align_double_arrow" => true, + "align_equals" => true + ], + "concat_space" => true, + "strict_comparison" => true, + "combine_consecutive_issets" => true, + "combine_consecutive_unsets" => true, + "comment_to_phpdoc" => true, + "compact_nullable_typehint" => true, + "explicit_indirect_variable" => true, + "explicit_string_variable" => true, + "header_comment" => [ + "commentType" => "PHPDoc", + "header" => "PHP version 7.1\n@author BLU ", + "location" => "after_open", + "separate" => "bottom" + ], + "linebreak_after_opening_tag" => true, + "no_useless_else" => true, + "no_useless_return" => true, + "ordered_imports" => true, + "phpdoc_order" => true, + "psr0" => true, + "return_assignment" => true, + "visibility_required" => [ + "elements" => ['property', 'method'] + ], + "concat_space" => [ + "spacing" => "one" + ] + ]) + ->setFinder($finder) + ->setRiskyAllowed(true) + ->setUsingCache(false) +; diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 3f5a905..e82d469 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -2,7 +2,13 @@ tools: php_sim: true php_pdepend: true php_analyzer: true - + external_code_coverage: + timeout: 2000 +filter: + paths: + - src/ + dependency_paths: + - vendor/ checks: php: code_rating: true diff --git a/TestApp/app/Kernel.php b/TestApp/app/Kernel.php new file mode 100644 index 0000000..6c4b098 --- /dev/null +++ b/TestApp/app/Kernel.php @@ -0,0 +1,61 @@ +getProjectDir().'/tmp/cache/'.$this->environment; + } + + public function getLogDir() + { + return $this->getProjectDir().'/tmp/log'; + } + + public function registerBundles() + { + $contents = require $this->getProjectDir().'/TestApp/config/bundles.php'; + foreach ($contents as $class => $envs) { + if (isset($envs['all']) || isset($envs[$this->environment])) { + yield new $class(); + } + } + } + + protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader) + { + $container->addResource(new FileResource($this->getProjectDir().'/TestApp/config/bundles.php')); + // Feel free to remove the "container.autowiring.strict_mode" parameter + // if you are using symfony/dependency-injection 4.0+ as it's the default behavior + $container->setParameter('container.autowiring.strict_mode', true); + $container->setParameter('container.dumper.inline_class_loader', true); + $confDir = $this->getProjectDir().'/TestApp/config'; + + $loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/{packages}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob'); + } + + protected function configureRoutes(RouteCollectionBuilder $routes) + { + $confDir = $this->getProjectDir().'/TestApp/config'; + + $routes->import($confDir.'/{routes}/*'.self::CONFIG_EXTS, '/', 'glob'); + $routes->import($confDir.'/{routes}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, '/', 'glob'); + $routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob'); + } +} diff --git a/TestApp/config/bundles.php b/TestApp/config/bundles.php new file mode 100755 index 0000000..484300a --- /dev/null +++ b/TestApp/config/bundles.php @@ -0,0 +1,7 @@ + ['all' => true], + ETNA\Sprinter\SprinterBundle::class => ['all' => true], + Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], +]; diff --git a/TestApp/config/packages/framework.yaml b/TestApp/config/packages/framework.yaml new file mode 100755 index 0000000..dbfe6bc --- /dev/null +++ b/TestApp/config/packages/framework.yaml @@ -0,0 +1,7 @@ +framework: + secret: 'toto' + + php_errors: + log: true + + test: true diff --git a/TestApp/config/routes/annotations.yaml b/TestApp/config/routes/annotations.yaml new file mode 100755 index 0000000..1ecdd36 --- /dev/null +++ b/TestApp/config/routes/annotations.yaml @@ -0,0 +1,3 @@ +controllers: + resource: ../../app/Controller/ + type: annotation diff --git a/TestApp/config/services.yaml b/TestApp/config/services.yaml new file mode 100755 index 0000000..0efde31 --- /dev/null +++ b/TestApp/config/services.yaml @@ -0,0 +1,21 @@ +# Put parameters here that don't need to change on each machine where the app is deployed +# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration +parameters: + application_name: 'test_app' + version: 2.0.0 + +services: + # default configuration for services in *this* file + _defaults: + autowire: true # Automatically injects dependencies in your services. + autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. + public: false # Allows optimizing the container by removing unused services; this also means + # fetching services directly from the container via $container->get() won't work. + # The best practice is to be explicit about your dependencies anyway. + + # makes classes in src/ available to be used as services + # this creates a service per class whose id is the fully-qualified class name + TestApp\: + resource: '../app/*' + exclude: '../app/{Entity,Migrations,Tests,Utils,Kernel.php}' + diff --git a/behat.yml.dist b/behat.yml.dist new file mode 100644 index 0000000..b4de76f --- /dev/null +++ b/behat.yml.dist @@ -0,0 +1,12 @@ +default: + suites: + default: + contexts: + - FeatureContext: + kernel: '@kernel' + + extensions: + Behat\Symfony2Extension: + kernel: + bootstrap: features/bootstrap/bootstrap.php + class: App\Kernel diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..f189221 --- /dev/null +++ b/build.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/composer.json b/composer.json index 253073d..6fbd0ed 100644 --- a/composer.json +++ b/composer.json @@ -1,22 +1,23 @@ { + "name": "etna/sprinter-service-provider", + "description": "Sprinter Service Provider", "type": "symfony-bundle", - "license": "BLU", + "keywords": ["sprinter", "silex"], + "license": "proprietary", + "authors": [ + { + "name": "ETNA", + "email": "dev@etna-alternance.net", + "homepage": "http://etna-alternance.net" + } + ], "require": { "php": "^7.1.3", - "ext-ctype": "*", - "ext-iconv": "*", + "symfony/framework-bundle": "4.2.*", "php-amqplib/rabbitmq-bundle": "^1.14", + "symfony/yaml": "4.2.*", "symfony/console": "4.2.*", - "symfony/dotenv": "4.2.*", - "symfony/flex": "^1.1", - "symfony/framework-bundle": "4.2.*", - "symfony/yaml": "4.2.*" - }, - "config": { - "preferred-install": { - "*": "dist" - }, - "sort-packages": true + "symfony/flex": "^1.1" }, "autoload": { "psr-4": { @@ -25,36 +26,41 @@ }, "autoload-dev": { "psr-4": { - "ETNA\\Sprinter\\Tests\\": "tests/" + "TestApp\\": "TestApp/app/" } }, - "replace": { - "paragonie/random_compat": "2.*", - "symfony/polyfill-ctype": "*", - "symfony/polyfill-iconv": "*", - "symfony/polyfill-php71": "*", - "symfony/polyfill-php70": "*", - "symfony/polyfill-php56": "*" - }, + "repositories": [ + { + "type": "composer", + "url": "https://blu-composer.herokuapp.com" + } + ], "scripts": { + "test": "behat", + "behat": "behat", + "phing": "phing", + "coveralls": "php-coveralls", "auto-scripts": { "cache:clear": "symfony-cmd", "assets:install %PUBLIC_DIR%": "symfony-cmd" - }, - "post-install-cmd": [ - "@auto-scripts" - ], - "post-update-cmd": [ - "@auto-scripts" - ] - }, - "conflict": { - "symfony/symfony": "*" - }, - "extra": { - "symfony": { - "allow-contrib": false, - "require": "4.2.*" } + }, + "require-dev": { + "behat/behat": "^3.4", + "behat/symfony2-extension": "^2.1", + "etna/composer-behat-utils": "^3.0.0-alpha.1", + "phpunit/php-code-coverage": "^6.0", + "phpunit/phpcov": "^5.0", + "phploc/phploc": "^4.0", + "squizlabs/php_codesniffer": "^3.3", + "friendsofphp/php-cs-fixer": "^2.12", + "sebastian/phpcpd": "^4.0", + "phpmd/phpmd": "^2.6", + "phing/phing": "^2.16", + "php-coveralls/php-coveralls": "^2.1", + "scrutinizer/ocular": "^1.5", + "phpstan/phpstan": "^0.11.0", + "povils/phpmnd": "^2.0", + "phpmetrics/phpmetrics": "^2.4" } } diff --git a/config/bootstrap.php b/config/bootstrap.php new file mode 100644 index 0000000..f6afb40 --- /dev/null +++ b/config/bootstrap.php @@ -0,0 +1,21 @@ +=1.2) +if (is_array($env = @include dirname(__DIR__).'/.env.local.php')) { + $_SERVER += $env; + $_ENV += $env; +} elseif (!class_exists(Dotenv::class)) { + throw new RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.'); +} else { + // load all the .env files + (new Dotenv())->loadEnv(dirname(__DIR__).'/.env'); +} + +$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev'; +$_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV']; +$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0'; diff --git a/config/bundles.php b/config/bundles.php new file mode 100644 index 0000000..0ec5220 --- /dev/null +++ b/config/bundles.php @@ -0,0 +1,6 @@ + ['all' => true], + OldSound\RabbitMqBundle\OldSoundRabbitMqBundle::class => ['all' => true], +]; diff --git a/config/packages/cache.yaml b/config/packages/cache.yaml new file mode 100644 index 0000000..93e620e --- /dev/null +++ b/config/packages/cache.yaml @@ -0,0 +1,19 @@ +framework: + cache: + # Put the unique name of your app here: the prefix seed + # is used to compute stable namespaces for cache keys. + #prefix_seed: your_vendor_name/app_name + + # The app cache caches to the filesystem by default. + # Other options include: + + # Redis + #app: cache.adapter.redis + #default_redis_provider: redis://localhost + + # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) + #app: cache.adapter.apcu + + # Namespaced pools use the above "app" backend by default + #pools: + #my.dedicated.cache: ~ diff --git a/config/packages/dev/routing.yaml b/config/packages/dev/routing.yaml new file mode 100644 index 0000000..4116679 --- /dev/null +++ b/config/packages/dev/routing.yaml @@ -0,0 +1,3 @@ +framework: + router: + strict_requirements: true diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml new file mode 100644 index 0000000..d3f884c --- /dev/null +++ b/config/packages/framework.yaml @@ -0,0 +1,17 @@ +framework: + secret: '%env(APP_SECRET)%' + #default_locale: en + #csrf_protection: true + #http_method_override: true + + # Enables session support. Note that the session will ONLY be started if you read or write from it. + # Remove or comment this section to explicitly disable session support. + session: + handler_id: ~ + cookie_secure: auto + cookie_samesite: lax + + #esi: true + #fragments: true + php_errors: + log: true diff --git a/config/packages/routing.yaml b/config/packages/routing.yaml new file mode 100644 index 0000000..a15c4ec --- /dev/null +++ b/config/packages/routing.yaml @@ -0,0 +1,4 @@ +framework: + router: + strict_requirements: ~ + utf8: true diff --git a/config/packages/test/framework.yaml b/config/packages/test/framework.yaml new file mode 100644 index 0000000..d051c84 --- /dev/null +++ b/config/packages/test/framework.yaml @@ -0,0 +1,4 @@ +framework: + test: true + session: + storage_id: session.storage.mock_file diff --git a/config/packages/test/routing.yaml b/config/packages/test/routing.yaml new file mode 100644 index 0000000..4116679 --- /dev/null +++ b/config/packages/test/routing.yaml @@ -0,0 +1,3 @@ +framework: + router: + strict_requirements: true diff --git a/config/packages/translation.yaml b/config/packages/translation.yaml new file mode 100644 index 0000000..e6b1cd6 --- /dev/null +++ b/config/packages/translation.yaml @@ -0,0 +1,6 @@ +framework: + default_locale: '%locale%' + translator: + default_path: '%kernel.project_dir%/translations' + fallbacks: + - '%locale%' diff --git a/config/routes.yaml b/config/routes.yaml new file mode 100644 index 0000000..c3283aa --- /dev/null +++ b/config/routes.yaml @@ -0,0 +1,3 @@ +#index: +# path: / +# controller: App\Controller\DefaultController::index diff --git a/config/routes/annotations.yaml b/config/routes/annotations.yaml new file mode 100644 index 0000000..d49a502 --- /dev/null +++ b/config/routes/annotations.yaml @@ -0,0 +1,3 @@ +controllers: + resource: ../../src/Controller/ + type: annotation diff --git a/config/services.yaml b/config/services.yaml index cdb0889..96977f9 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -1,3 +1,6 @@ +parameters: + locale: 'en' + # This file is the entry point to configure your own services. # Files in the packages/ subdirectory configure your dependencies. diff --git a/features/bootstrap/bootstrap.php b/features/bootstrap/bootstrap.php new file mode 100644 index 0000000..0f3ad18 --- /dev/null +++ b/features/bootstrap/bootstrap.php @@ -0,0 +1,4 @@ + + + + + + + + + + + + bin/ + config/ + public/ + src/ + tests/ + + diff --git a/phpdoc.xml b/phpdoc.xml new file mode 100644 index 0000000..a7d8f4e --- /dev/null +++ b/phpdoc.xml @@ -0,0 +1,24 @@ + + + etna/sprinter-service-provider + + doc/build + + + doc + + + warn + + {APP_ROOT}/data/log/{DATE}.log + {APP_ROOT}/data/log/{DATE}.errors.log + + + +