├── example ├── src │ ├── Controller │ │ ├── .gitignore │ │ └── DefaultController.php │ ├── Entity │ │ ├── .gitignore │ │ ├── Test1.php │ │ ├── DictWords.php │ │ ├── States.php │ │ └── States2.php │ ├── Repository │ │ ├── .gitignore │ │ └── DictWordsRepository.php │ ├── Kernel.php │ └── DataSeeds │ │ ├── TestSeed.php │ │ ├── DictWordsSeed.php │ │ ├── CsvSeed.php │ │ ├── USStatesSeed.php │ │ └── USStatesSeed2.php ├── config │ ├── packages │ │ ├── test │ │ │ ├── twig.yaml │ │ │ ├── framework.yaml │ │ │ └── web_profiler.yaml │ │ ├── routing.yaml │ │ ├── prod │ │ │ ├── routing.yaml │ │ │ └── doctrine.yaml │ │ ├── sensio_framework_extra.yaml │ │ ├── dev │ │ │ ├── web_profiler.yaml │ │ │ └── debug.yaml │ │ ├── twig.yaml │ │ ├── debug.yaml │ │ ├── web_profiler.yaml │ │ ├── framework.yaml │ │ ├── doctrine.yaml │ │ └── cache.yaml │ ├── routes.yaml │ ├── routes │ │ ├── dev │ │ │ ├── framework.yaml │ │ │ └── web_profiler.yaml │ │ ├── framework.yaml │ │ ├── annotations.yaml │ │ └── web_profiler.yaml │ ├── preload.php │ ├── bundles.php │ ├── bootstrap.php │ └── services.yaml ├── public │ └── index.php ├── .gitignore ├── templates │ ├── base.html.twig │ └── default │ │ └── index.html.twig ├── .env └── composer.json ├── tests ├── bootstrap.php ├── App │ ├── config.yml │ └── AppKernel.php ├── fixtures │ ├── FailSeed.php │ ├── GlobSeedA.php │ ├── GlobSeedB.php │ ├── TownSeed.php │ ├── StreetSeed.php │ ├── CountrySeed.php │ └── PostcodeSeed.php └── SeedCommandTest.php ├── .gitignore ├── src ├── Command │ ├── Seed.php │ ├── LoadSeedsCommand.php │ └── UnloadSeedsCommand.php ├── Core │ ├── ManualSeedCommand.php │ ├── SeedRegistry.php │ └── SeedCoreCommand.php ├── Exception │ └── InvalidSeedNameException.php ├── Model │ └── SeedItem.php ├── Interfaces │ └── SeedInterface.php ├── Resources │ └── config │ │ └── services.yml ├── EvotodiSeedBundle.php └── DependencyInjection │ ├── EvotodiSeedExtension.php │ └── Compiler │ └── SeedPass.php ├── phpunit.xml.dist ├── LICENSE ├── composer.json ├── .travis.yml └── README.md /example/src/Controller/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/src/Entity/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/src/Repository/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/config/packages/test/twig.yaml: -------------------------------------------------------------------------------- 1 | twig: 2 | strict_variables: true 3 | -------------------------------------------------------------------------------- /example/config/packages/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | utf8: true 4 | -------------------------------------------------------------------------------- /example/config/packages/prod/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | strict_requirements: null 4 | -------------------------------------------------------------------------------- /example/config/routes.yaml: -------------------------------------------------------------------------------- 1 | #index: 2 | # path: / 3 | # controller: App\Controller\DefaultController::index 4 | -------------------------------------------------------------------------------- /example/config/packages/sensio_framework_extra.yaml: -------------------------------------------------------------------------------- 1 | sensio_framework_extra: 2 | router: 3 | annotations: false 4 | -------------------------------------------------------------------------------- /example/config/packages/test/framework.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | test: true 3 | session: 4 | storage_id: session.storage.mock_file 5 | -------------------------------------------------------------------------------- /example/config/routes/dev/framework.yaml: -------------------------------------------------------------------------------- 1 | _errors: 2 | resource: '@FrameworkBundle/Resources/config/routing/errors.xml' 3 | prefix: /_error 4 | -------------------------------------------------------------------------------- /example/config/routes/framework.yaml: -------------------------------------------------------------------------------- 1 | when@dev: 2 | _errors: 3 | resource: '@FrameworkBundle/Resources/config/routing/errors.xml' 4 | prefix: /_error 5 | -------------------------------------------------------------------------------- /example/config/packages/test/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler: 2 | toolbar: false 3 | intercept_redirects: false 4 | 5 | framework: 6 | profiler: { collect: false } 7 | -------------------------------------------------------------------------------- /example/config/packages/dev/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler: 2 | toolbar: true 3 | intercept_redirects: false 4 | 5 | framework: 6 | profiler: { only_exceptions: false } 7 | -------------------------------------------------------------------------------- /example/config/routes/annotations.yaml: -------------------------------------------------------------------------------- 1 | controllers: 2 | resource: ../../src/Controller/ 3 | type: annotation 4 | 5 | kernel: 6 | resource: ../../src/Kernel.php 7 | type: annotation 8 | -------------------------------------------------------------------------------- /example/config/packages/twig.yaml: -------------------------------------------------------------------------------- 1 | twig: 2 | default_path: '%kernel.project_dir%/templates' 3 | debug: '%kernel.debug%' 4 | strict_variables: '%kernel.debug%' 5 | exception_controller: null 6 | -------------------------------------------------------------------------------- /example/config/preload.php: -------------------------------------------------------------------------------- 1 | symfony/framework-bundle ### 2 | /.env.local 3 | /.env.local.php 4 | /.env.*.local 5 | /config/secrets/prod/prod.decrypt.private.php 6 | /public/bundles/ 7 | /var/ 8 | /vendor/ 9 | ###< symfony/framework-bundle ### 10 | 11 | ###> symfony/web-server-bundle ### 12 | /.web-server-pid 13 | ###< symfony/web-server-bundle ### 14 | -------------------------------------------------------------------------------- /example/templates/base.html.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block title %}Welcome!{% endblock %} 6 | {% block stylesheets %}{% endblock %} 7 | 8 | 9 | {% block body %}{% endblock %} 10 | {% block javascripts %}{% endblock %} 11 | 12 | 13 | -------------------------------------------------------------------------------- /example/config/packages/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | when@dev: 2 | web_profiler: 3 | toolbar: true 4 | intercept_redirects: false 5 | 6 | framework: 7 | profiler: { only_exceptions: false } 8 | 9 | when@test: 10 | web_profiler: 11 | toolbar: false 12 | intercept_redirects: false 13 | 14 | framework: 15 | profiler: { collect: false } 16 | -------------------------------------------------------------------------------- /src/Core/ManualSeedCommand.php: -------------------------------------------------------------------------------- 1 | method = null; 12 | 13 | $this 14 | ->addArgument('method', InputArgument::REQUIRED, 'load/unload seed') 15 | ; 16 | $this->baseConfigure(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Command/LoadSeedsCommand.php: -------------------------------------------------------------------------------- 1 | method = 'load'; 17 | parent::configure(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Command/UnloadSeedsCommand.php: -------------------------------------------------------------------------------- 1 | method = 'unload'; 17 | parent::configure(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Exception/InvalidSeedNameException.php: -------------------------------------------------------------------------------- 1 | name = $name; 15 | $this->classRef = $classRef; 16 | $this->order = $order; 17 | $this->manual = $manual; 18 | } 19 | 20 | public function getClassName(): string 21 | { 22 | return get_class($this->classRef); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/fixtures/FailSeed.php: -------------------------------------------------------------------------------- 1 | ['all' => true], 5 | Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], 6 | Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true], 7 | Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], 8 | Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true], 9 | Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], 10 | Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], 11 | Evotodi\SeedBundle\EvotodiSeedBundle::class => ['all' => true], 12 | ]; 13 | -------------------------------------------------------------------------------- /tests/fixtures/GlobSeedA.php: -------------------------------------------------------------------------------- 1 | writeln('Load foo:bar'); 19 | return 0; 20 | } 21 | 22 | public function unload(InputInterface $input, OutputInterface $output): int 23 | { 24 | $output->writeln('Unload foo:bar'); 25 | return 0; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/fixtures/GlobSeedB.php: -------------------------------------------------------------------------------- 1 | writeln('Load foo:baz'); 19 | return 0; 20 | } 21 | 22 | public function unload(InputInterface $input, OutputInterface $output): int 23 | { 24 | $output->writeln('Unload foo:baz'); 25 | return 0; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Interfaces/SeedInterface.php: -------------------------------------------------------------------------------- 1 | writeln('Load town'); 24 | return 0; 25 | } 26 | 27 | public function unload(InputInterface $input, OutputInterface $output): int 28 | { 29 | $output->writeln('Unload town'); 30 | return 0; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/fixtures/StreetSeed.php: -------------------------------------------------------------------------------- 1 | writeln('Load street'); 24 | return 0; 25 | } 26 | 27 | public function unload(InputInterface $input, OutputInterface $output): int 28 | { 29 | $output->writeln('Unload street'); 30 | return 0; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/fixtures/CountrySeed.php: -------------------------------------------------------------------------------- 1 | writeln('Load country'); 24 | return 0; 25 | } 26 | 27 | public function unload(InputInterface $input, OutputInterface $output): int 28 | { 29 | $output->writeln('Unload country'); 30 | return 0; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/fixtures/PostcodeSeed.php: -------------------------------------------------------------------------------- 1 | writeln('Load postcode'); 24 | return 0; 25 | } 26 | 27 | public function unload(InputInterface $input, OutputInterface $output): int 28 | { 29 | $output->writeln('Unload postcode'); 30 | return 0; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /example/src/Entity/Test1.php: -------------------------------------------------------------------------------- 1 | id; 28 | } 29 | 30 | public function setId( int $id): self 31 | { 32 | $this->id = $id; 33 | return $this; 34 | } 35 | 36 | public function getTest1(): string 37 | { 38 | return $this->test1; 39 | } 40 | 41 | public function setTest1(string $test1): self 42 | { 43 | $this->test1 = $test1; 44 | return $this; 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/EvotodiSeedBundle.php: -------------------------------------------------------------------------------- 1 | extension){ 16 | $this->extension = new EvotodiSeedExtension(); 17 | } 18 | 19 | return $this->extension; 20 | } 21 | 22 | public function build(ContainerBuilder $container): void 23 | { 24 | $this->container = $container; 25 | 26 | parent::build($container); 27 | $container->addCompilerPass(new SeedPass()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /example/src/DataSeeds/TestSeed.php: -------------------------------------------------------------------------------- 1 | disableDoctrineLogging(); 19 | $test = new Test1(); 20 | $test->setTest1('asdf'); 21 | 22 | $this->getManager()->persist($test); 23 | $this->getManager()->flush(); 24 | return 0; 25 | } 26 | 27 | public function unload(InputInterface $input, OutputInterface $output): int 28 | { 29 | $this->getManager()->getConnection()->executeQuery('DELETE FROM test1'); 30 | return 0; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /example/templates/default/index.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | {% block title %}Hello DefaultController!{% endblock %} 4 | 5 | {% block body %} 6 | 10 | 11 |
12 |

Hello {{ controller_name }}! ✅

13 | 14 | This friendly message is coming from: 15 | 19 |
20 | {% endblock %} 21 | -------------------------------------------------------------------------------- /src/DependencyInjection/EvotodiSeedExtension.php: -------------------------------------------------------------------------------- 1 | registerForAutoconfiguration(SeedInterface::class)->addTag('seed.seed'); 21 | 22 | $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 23 | $loader->load('services.yml'); 24 | } 25 | 26 | public function getAlias(): string 27 | { 28 | return 'evo_seed'; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /example/src/Entity/DictWords.php: -------------------------------------------------------------------------------- 1 | id; 35 | } 36 | 37 | public function setId(int $id): self 38 | { 39 | $this->id = $id; 40 | return $this; 41 | } 42 | 43 | public function getWord(): string 44 | { 45 | return $this->word; 46 | } 47 | 48 | public function setWord(string $word): self 49 | { 50 | $this->word = $word; 51 | return $this; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /example/src/Controller/DefaultController.php: -------------------------------------------------------------------------------- 1 | getParameter('kernel.logs_dir').'/dev.log', 0); 18 | // $reader->getParser()->registerPattern('test', '/\[(?P.*)\] (?P\w+).(?P\w+): (?P.*)(?P.*)(?P.*)/'); 19 | // $reader->setPattern('test'); 20 | // foreach ($reader as $log) { 21 | // echo sprintf("::: %s %s %s
", $log['date']->format('Y-m-d h:i:s'), $log['level'], $log['message']); 22 | // } 23 | // dd($reader); 24 | return $this->render('default/index.html.twig', [ 25 | 'controller_name' => 'DefaultController', 26 | ]); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ./src 6 | 7 | 8 | ./Resources 9 | ./Tests 10 | ./vendor 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ./tests 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /example/src/Entity/States.php: -------------------------------------------------------------------------------- 1 | abv; 35 | } 36 | 37 | public function setAbv(string $abv): self 38 | { 39 | $this->abv = $abv; 40 | return $this; 41 | } 42 | 43 | public function getName(): string 44 | { 45 | return $this->name; 46 | } 47 | 48 | public function setName(string $name): self 49 | { 50 | $this->name = $name; 51 | return $this; 52 | } 53 | 54 | public function __toString() 55 | { 56 | return $this->getAbv(); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /example/src/Entity/States2.php: -------------------------------------------------------------------------------- 1 | abv; 35 | } 36 | 37 | public function setAbv(string $abv): self 38 | { 39 | $this->abv = $abv; 40 | return $this; 41 | } 42 | 43 | public function getName(): string 44 | { 45 | return $this->name; 46 | } 47 | 48 | public function setName(string $name): self 49 | { 50 | $this->name = $name; 51 | return $this; 52 | } 53 | 54 | public function __toString() 55 | { 56 | return $this->getAbv(); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /tests/App/AppKernel.php: -------------------------------------------------------------------------------- 1 | load(__DIR__.'/config.yml'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2020-present Justin Davis and other contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /example/src/Repository/DictWordsRepository.php: -------------------------------------------------------------------------------- 1 | getEntityManager(); 25 | return $em->createQuery( 26 | "SELECT word FROM AppBundle:DictWords AS d ORDER BY RAND() LIMIT 0,3; " 27 | )->getResult(); 28 | } 29 | 30 | public function findRandWordsNew($count): array 31 | { 32 | $em = $this->getEntityManager(); 33 | $words = $em->getRepository(DictWords::class)->findAll(); 34 | shuffle($words); 35 | return array_slice($words, 0 , $count); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "evotodi/seed-bundle", 3 | "description": "Seeder for symfony 6/7", 4 | "type": "symfony-bundle", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "evotodi", 9 | "email": "evotodi@gmail.com" 10 | }, 11 | { 12 | "name": "Soyuka", 13 | "email": "soyuka@gmail.com" 14 | } 15 | ], 16 | "require": { 17 | "php": "^8", 18 | "symfony/framework-bundle": "^6.0|^7.0", 19 | "symfony/console": "^6.0|^7.0", 20 | "symfony/finder": "^6.0|^7.0", 21 | "doctrine/doctrine-bundle": "^2.0", 22 | "doctrine/orm": "^2.0|^3.0", 23 | "symfony/yaml": "^6.0|^7.0", 24 | "symfony/doctrine-bridge": "^6.0|^7.0", 25 | "webmozart/glob": "^4.5" 26 | }, 27 | "require-dev": { 28 | "symfony/config": "^6.0|^7.0", 29 | "symfony/dependency-injection": "^6.0|^7.0", 30 | "symfony/phpunit-bridge": "^6.0|^7.0" 31 | 32 | }, 33 | "autoload": { 34 | "psr-4": { 35 | "Evotodi\\SeedBundle\\": "src/" 36 | } 37 | }, 38 | "autoload-dev": { 39 | "psr-4": { 40 | "Evotodi\\SeedBundle\\Tests\\": "tests/" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /example/config/bootstrap.php: -------------------------------------------------------------------------------- 1 | =1.2) 9 | if (is_array($env = @include dirname(__DIR__).'/.env.local.php') && (!isset($env['APP_ENV']) || ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? $env['APP_ENV']) === $env['APP_ENV'])) { 10 | foreach ($env as $k => $v) { 11 | $_ENV[$k] = $_ENV[$k] ?? (isset($_SERVER[$k]) && 0 !== strpos($k, 'HTTP_') ? $_SERVER[$k] : $v); 12 | } 13 | } elseif (!class_exists(Dotenv::class)) { 14 | throw new RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.'); 15 | } else { 16 | // load all the .env files 17 | (new Dotenv())->loadEnv(dirname(__DIR__).'/.env'); 18 | } 19 | 20 | $_SERVER += $_ENV; 21 | $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev'; 22 | $_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV']; 23 | $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0'; 24 | -------------------------------------------------------------------------------- /example/config/services.yaml: -------------------------------------------------------------------------------- 1 | # This file is the entry point to configure your own services. 2 | # Files in the packages/ subdirectory configure your dependencies. 3 | 4 | # Put parameters here that don't need to change on each machine where the app is deployed 5 | # https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration 6 | parameters: 7 | 8 | services: 9 | # default configuration for services in *this* file 10 | _defaults: 11 | autowire: true # Automatically injects dependencies in your services. 12 | autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. 13 | 14 | # makes classes in src/ available to be used as services 15 | # this creates a service per class whose id is the fully-qualified class name 16 | App\: 17 | resource: '../src/*' 18 | exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}' 19 | 20 | # controllers are imported separately to make sure services can be injected 21 | # as action arguments even if you don't extend any base controller class 22 | App\Controller\: 23 | resource: '../src/Controller' 24 | tags: ['controller.service_arguments'] 25 | 26 | # add more service definitions when explicit configuration is needed 27 | # please note that last definitions always *replace* previous ones 28 | 29 | # App\DataSeeds\TestSeed: 30 | # arguments: ['@doctrine.orm.entity_manager', '@service_container'] 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | os: linux 3 | cache: 4 | directories: 5 | - $HOME/.composer/cache/files 6 | - $HOME/symfony-bridge/.phpunit 7 | 8 | env: 9 | global: 10 | - PHPUNIT_FLAGS="-v" 11 | - SYMFONY_PHPUNIT_DIR="$HOME/symfony-bridge/.phpunit" 12 | 13 | jobs: 14 | fast_finish: true 15 | include: 16 | # Minimum supported dependencies with the latest and oldest PHP version 17 | - php: 8.0 18 | env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" 19 | 20 | # Latest commit to master 21 | - php: 8.0 22 | env: STABILITY="dev" 23 | 24 | allow_failures: 25 | # Dev-master is allowed to fail. 26 | - env: STABILITY="dev" 27 | 28 | before_install: 29 | - if [[ $COVERAGE != true ]]; then phpenv config-rm xdebug.ini || true; fi 30 | - if ! [ -z "$STABILITY" ]; then composer config minimum-stability ${STABILITY}; fi; 31 | - if ! [ -v "$DEPENDENCIES" ]; then composer require --no-update ${DEPENDENCIES}; fi; 32 | 33 | install: 34 | # To be removed when this issue will be resolved: https://github.com/composer/composer/issues/5355 35 | - if [[ "$COMPOSER_FLAGS" == *"--prefer-lowest"* ]]; then 36 | composer update --prefer-dist --no-interaction --prefer-stable --quiet; 37 | else 38 | composer update --prefer-dist --no-interaction --quiet; 39 | fi 40 | - ./vendor/bin/simple-phpunit install 41 | 42 | script: 43 | - composer validate --strict --no-check-lock 44 | # simple-phpunit is the PHPUnit wrapper provided by the PHPUnit Bridge component and 45 | # it helps with testing legacy code and deprecations (composer require symfony/phpunit-bridge) 46 | - ./vendor/bin/simple-phpunit $PHPUNIT_FLAGS 47 | -------------------------------------------------------------------------------- /example/.env: -------------------------------------------------------------------------------- 1 | # In all environments, the following files are loaded if they exist, 2 | # the latter taking precedence over the former: 3 | # 4 | # * .env contains default values for the environment variables needed by the app 5 | # * .env.local uncommitted file with local overrides 6 | # * .env.$APP_ENV committed environment-specific defaults 7 | # * .env.$APP_ENV.local uncommitted environment-specific overrides 8 | # 9 | # Real environment variables win over .env files. 10 | # 11 | # DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES. 12 | # 13 | # Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2). 14 | # https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration 15 | 16 | ###> symfony/framework-bundle ### 17 | APP_ENV=dev 18 | APP_SECRET=my_secret 19 | #TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 20 | #TRUSTED_HOSTS='^(localhost|example\.com)$' 21 | ###< symfony/framework-bundle ### 22 | 23 | ###> doctrine/doctrine-bundle ### 24 | # Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url 25 | # For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db" 26 | # For a PostgreSQL database, use: "postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=11&charset=utf8" 27 | # IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml 28 | #DATABASE_URL=mysql://apollo:apollo@server-mysql:3306/seedtest 29 | DATABASE_URL=sqlite:///var/test.db 30 | ###< doctrine/doctrine-bundle ### 31 | -------------------------------------------------------------------------------- /example/src/DataSeeds/DictWordsSeed.php: -------------------------------------------------------------------------------- 1 | disableDoctrineLogging(); 29 | 30 | //Access doctrine through $this->doctrine 31 | $dictWordsRepository = $this->getManager()->getRepository(DictWords::class); 32 | 33 | 34 | foreach ($this->getWords() as $word) { 35 | 36 | if($dictWordsRepository->findOneBy(array('word' => $word))) { 37 | continue; 38 | } 39 | 40 | $em = new DictWords(); 41 | 42 | $em->setWord($word); 43 | 44 | //Doctrine manager is also available 45 | $this->getManager()->persist($em); 46 | 47 | $this->getManager()->flush(); 48 | } 49 | 50 | $this->getManager()->clear(); 51 | return 0; 52 | } 53 | 54 | public function unload(InputInterface $input, OutputInterface $output): int 55 | { 56 | $className = $this->getManager()->getClassMetadata(DictWords::class )->getName(); 57 | $this->getManager()->createQuery('DELETE FROM '.$className)->execute(); 58 | return 0; 59 | } 60 | 61 | public function getWords(): bool|array 62 | { 63 | $words = file(__DIR__.'/../Resources/dictWords.txt'); 64 | shuffle($words); 65 | return array_slice($words, 0, 1000); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /example/src/DataSeeds/CsvSeed.php: -------------------------------------------------------------------------------- 1 | parameterBag = $parameterBag; 21 | $this->filesystem = $filesystem; 22 | } 23 | 24 | public static function seedName(): string 25 | { 26 | return 'csv'; 27 | } 28 | 29 | /** 30 | * @throws Exception 31 | */ 32 | public function load(InputInterface $input, OutputInterface $output): int 33 | { 34 | $csvColumns = ['id', 'name', 'data']; 35 | $csvData = []; 36 | for($i = 0; $i < 10; $i++){ 37 | $csvData[] = [$i, 'MyName'.$i, random_int(0, 1000)]; 38 | } 39 | 40 | $this->filesystem->mkdir($this->parameterBag->get('kernel.project_dir').'/var'); 41 | 42 | $file = fopen($this->parameterBag->get('kernel.project_dir').'/var/test.csv', 'w'); 43 | 44 | fputcsv($file, $csvColumns); 45 | foreach ($csvData as $datum){ 46 | fputcsv($file, $datum); 47 | } 48 | 49 | fclose($file); 50 | 51 | return 0; 52 | } 53 | 54 | public function unload(InputInterface $input, OutputInterface $output): int 55 | { 56 | $this->filesystem->remove($this->parameterBag->get('kernel.project_dir').'/var/test.csv'); 57 | return 0; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /example/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "project", 3 | "license": "proprietary", 4 | "require": { 5 | "php": ">=8.0", 6 | "ext-ctype": "*", 7 | "ext-iconv": "*", 8 | "evotodi/seed-bundle": "dev-master", 9 | "sensio/framework-extra-bundle": "^6.0|^7.0", 10 | "symfony/asset": "^6.0|^7.0", 11 | "symfony/console": "^6.0|^7.0", 12 | "symfony/dotenv": "^6.0|^7.0", 13 | "symfony/flex": "^1.0", 14 | "symfony/framework-bundle": "^6.0|^7.0", 15 | "symfony/property-access": "^6.0|^7.0", 16 | "symfony/yaml": "^6.0|^7.0", 17 | "doctrine/doctrine-bundle": "^2.0", 18 | "doctrine/orm": "^2.8" 19 | }, 20 | "require-dev": { 21 | "symfony/debug-bundle": "^6.0|^7.0", 22 | "symfony/maker-bundle": "^1.0", 23 | "symfony/stopwatch": "^6.0|^7.0", 24 | "symfony/var-dumper": "^6.0|^7.0", 25 | "symfony/web-profiler-bundle": "^6.0|^7.0" 26 | }, 27 | "config": { 28 | "preferred-install": { 29 | "*": "dist" 30 | }, 31 | "sort-packages": true, 32 | "allow-plugins": { 33 | "symfony/flex": true 34 | } 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "App\\": "src/" 39 | } 40 | }, 41 | "autoload-dev": { 42 | "psr-4": { 43 | } 44 | }, 45 | "replace": { 46 | "paragonie/random_compat": "2.*", 47 | "symfony/polyfill-ctype": "*", 48 | "symfony/polyfill-iconv": "*", 49 | "symfony/polyfill-php71": "*", 50 | "symfony/polyfill-php70": "*", 51 | "symfony/polyfill-php56": "*" 52 | }, 53 | "scripts": { 54 | "auto-scripts": { 55 | "cache:clear": "symfony-cmd", 56 | "assets:install %PUBLIC_DIR%": "symfony-cmd" 57 | }, 58 | "post-install-cmd": [ 59 | "@auto-scripts" 60 | ], 61 | "post-update-cmd": [ 62 | "@auto-scripts" 63 | ] 64 | }, 65 | "conflict": { 66 | "symfony/symfony": "*" 67 | }, 68 | "extra": { 69 | "symfony": { 70 | "allow-contrib": true, 71 | "require": "^6.0|^7.0", 72 | "docker": false 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/DependencyInjection/Compiler/SeedPass.php: -------------------------------------------------------------------------------- 1 | has('seed.registry')) { 21 | return; 22 | } 23 | 24 | $definition = $container->findDefinition('seed.registry'); 25 | $taggedServices = $container->findTaggedServiceIds('seed.seed'); 26 | 27 | foreach ($taggedServices as $id => $tags){ 28 | $seedItem = $container->findDefinition($id); 29 | if(!$seedItem->getClass() instanceof SeedCoreCommand) { 30 | $seedItem->addMethodCall('setManager', [new Reference('doctrine')]); 31 | $seedItem->addMethodCall('setRegistry', [new Reference('seed.registry')]); 32 | } 33 | try { 34 | $rc = new ReflectionClass($id); 35 | if($rc->hasMethod('seedName')){ 36 | $seedName = $rc->getMethod('seedName')->invoke(null); 37 | if(in_array($seedName, ['load', 'unload', SeedCoreCommand::CORE_SEED_NAME])){ 38 | throw new InvalidSeedNameException(InvalidSeedNameException::MESSAGE . $id); 39 | } 40 | $seedOrder = $rc->getMethod('getOrder')->invoke(null); 41 | 42 | $definition->addMethodCall('addSeed', [$seedName, new Reference($id), $seedOrder]); 43 | } 44 | } catch (ReflectionException) { 45 | } 46 | 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Core/SeedRegistry.php: -------------------------------------------------------------------------------- 1 | 'string', 'class' => 'object', 'order' => 'int', 'path' => 'string'])] 11 | private array $seeds = []; 12 | 13 | /** @noinspection PhpUnused */ 14 | public function addSeed(string $seedName, object $seedClass, int $seedOrder): void 15 | { 16 | $this->seeds[strtolower($seedName)] = [ 17 | 'name' => strtolower($seedName), 18 | 'class' => $seedClass, 19 | 'order' => $seedOrder, 20 | 'path' => "/". str_replace(':', "/", strtolower($seedName)), 21 | ]; 22 | } 23 | 24 | #[ArrayShape(['name' => ['name' => 'string', 'class' => 'object', 'order' => 'int', 'path' => 'string']])] 25 | public function all(): array 26 | { 27 | return $this->seeds; 28 | } 29 | 30 | #[ArrayShape(['name' => 'string', 'class' => 'object', 'order' => 'int', 'path' => 'string'])] 31 | public function get(string $seedName): ?array 32 | { 33 | if(key_exists(strtolower($seedName), $this->seeds)){ 34 | return $this->seeds[strtolower($seedName)]; 35 | } 36 | return null; 37 | } 38 | 39 | public function has(string $seedName): bool 40 | { 41 | if(key_exists(strtolower($seedName), $this->seeds)){ 42 | return true; 43 | } 44 | return false; 45 | } 46 | 47 | #[ArrayShape(['name' => 'string'])] 48 | public function keys(): array 49 | { 50 | return array_keys($this->seeds); 51 | } 52 | 53 | #[ArrayShape(['name' => 'string'])] 54 | public function glob(string $glob): array 55 | { 56 | $paths = array_column($this->seeds, 'path'); 57 | 58 | $globPath = strtolower($glob); 59 | if(!str_starts_with($glob, '/')){ 60 | $globPath = '/' . $glob; 61 | } 62 | $globPath = str_replace(':', '/', $globPath); 63 | 64 | $matches = Glob::filter($paths, $globPath); 65 | 66 | $ret = []; 67 | foreach ($matches as $val){ 68 | $seed = $this->get(ltrim(str_replace('/', ":", $val), ':')); 69 | if($seed){ 70 | $ret[] = $seed['name']; 71 | } 72 | } 73 | if(empty($ret)){ 74 | $ret[] = strtolower($glob); 75 | } 76 | return $ret; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /example/src/DataSeeds/USStatesSeed.php: -------------------------------------------------------------------------------- 1 | disableDoctrineLogging(); 34 | 35 | //Access doctrine through $this->doctrine 36 | $statesRepository = $this->getManager()->getRepository(States::class); 37 | 38 | 39 | foreach ($this->getStates() as $abv => $name) { 40 | 41 | if($statesRepository->findOneBy(array('abv' => $abv))) { 42 | continue; 43 | } 44 | 45 | $em = new States(); 46 | 47 | $em->setAbv($abv); 48 | $em->setName($name); 49 | 50 | //Doctrine manager is also available 51 | $this->getManager()->persist($em); 52 | 53 | $this->getManager()->flush(); 54 | } 55 | 56 | $this->getManager()->clear(); 57 | return 0; 58 | } 59 | 60 | public function unload(InputInterface $input, OutputInterface $output): int 61 | { 62 | $className = $this->getManager()->getClassMetadata(States::class)->getName(); 63 | $this->getManager()->createQuery('DELETE FROM '.$className)->execute(); 64 | return 0; 65 | } 66 | 67 | public function getStates(): array 68 | { 69 | return array ( 70 | 'AL'=>'Alabama', 71 | 'AK'=>'Alaska', 72 | 'AZ'=>'Arizona', 73 | 'AR'=>'Arkansas', 74 | 'CA'=>'California', 75 | 'CO'=>'Colorado', 76 | 'CT'=>'Connecticut', 77 | 'DE'=>'Delaware', 78 | 'DC'=>'District of Columbia', 79 | 'FL'=>'Florida', 80 | 'GA'=>'Georgia', 81 | 'HI'=>'Hawaii', 82 | 'ID'=>'Idaho', 83 | 'IL'=>'Illinois', 84 | 'IN'=>'Indiana', 85 | 'IA'=>'Iowa', 86 | 'KS'=>'Kansas', 87 | 'KY'=>'Kentucky', 88 | 'LA'=>'Louisiana', 89 | 'ME'=>'Maine', 90 | 'MD'=>'Maryland', 91 | 'MA'=>'Massachusetts', 92 | 'MI'=>'Michigan', 93 | 'MN'=>'Minnesota', 94 | 'MS'=>'Mississippi', 95 | 'MO'=>'Missouri', 96 | 'MT'=>'Montana', 97 | 'NE'=>'Nebraska', 98 | 'NV'=>'Nevada', 99 | 'NH'=>'New Hampshire', 100 | 'NJ'=>'New Jersey', 101 | 'NM'=>'New Mexico', 102 | 'NY'=>'New York', 103 | 'NC'=>'North Carolina', 104 | 'ND'=>'North Dakota', 105 | 'OH'=>'Ohio', 106 | 'OK'=>'Oklahoma', 107 | 'OR'=>'Oregon', 108 | 'PA'=>'Pennsylvania', 109 | 'RI'=>'Rhode Island', 110 | 'SC'=>'South Carolina', 111 | 'SD'=>'South Dakota', 112 | 'TN'=>'Tennessee', 113 | 'TX'=>'Texas', 114 | 'UT'=>'Utah', 115 | 'VT'=>'Vermont', 116 | 'VA'=>'Virginia', 117 | 'WA'=>'Washington', 118 | 'WV'=>'West Virginia', 119 | 'WI'=>'Wisconsin', 120 | 'WY'=>'Wyoming', 121 | ); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /example/src/DataSeeds/USStatesSeed2.php: -------------------------------------------------------------------------------- 1 | disableDoctrineLogging(); 34 | 35 | //Access doctrine through $this->doctrine 36 | $statesRepository = $this->getManager()->getRepository(States::class); 37 | 38 | 39 | foreach ($this->getStates() as $abv => $name) { 40 | 41 | if($statesRepository->findOneBy(array('abv' => $abv))) { 42 | continue; 43 | } 44 | 45 | $em = new States(); 46 | 47 | $em->setAbv($abv); 48 | $em->setName($name); 49 | 50 | //Doctrine manager is also available 51 | $this->getManager()->persist($em); 52 | 53 | $this->getManager()->flush(); 54 | } 55 | 56 | $this->getManager()->clear(); 57 | return 0; 58 | } 59 | 60 | public function unload(InputInterface $input, OutputInterface $output): int 61 | { 62 | $className = $this->getManager()->getClassMetadata(States::class)->getName(); 63 | $this->getManager()->createQuery('DELETE FROM '.$className)->execute(); 64 | return 0; 65 | } 66 | 67 | public function getStates(): array 68 | { 69 | return array ( 70 | 'AL'=>'Alabama', 71 | 'AK'=>'Alaska', 72 | 'AZ'=>'Arizona', 73 | 'AR'=>'Arkansas', 74 | 'CA'=>'California', 75 | 'CO'=>'Colorado', 76 | 'CT'=>'Connecticut', 77 | 'DE'=>'Delaware', 78 | 'DC'=>'District of Columbia', 79 | 'FL'=>'Florida', 80 | 'GA'=>'Georgia', 81 | 'HI'=>'Hawaii', 82 | 'ID'=>'Idaho', 83 | 'IL'=>'Illinois', 84 | 'IN'=>'Indiana', 85 | 'IA'=>'Iowa', 86 | 'KS'=>'Kansas', 87 | 'KY'=>'Kentucky', 88 | 'LA'=>'Louisiana', 89 | 'ME'=>'Maine', 90 | 'MD'=>'Maryland', 91 | 'MA'=>'Massachusetts', 92 | 'MI'=>'Michigan', 93 | 'MN'=>'Minnesota', 94 | 'MS'=>'Mississippi', 95 | 'MO'=>'Missouri', 96 | 'MT'=>'Montana', 97 | 'NE'=>'Nebraska', 98 | 'NV'=>'Nevada', 99 | 'NH'=>'New Hampshire', 100 | 'NJ'=>'New Jersey', 101 | 'NM'=>'New Mexico', 102 | 'NY'=>'New York', 103 | 'NC'=>'North Carolina', 104 | 'ND'=>'North Dakota', 105 | 'OH'=>'Ohio', 106 | 'OK'=>'Oklahoma', 107 | 'OR'=>'Oregon', 108 | 'PA'=>'Pennsylvania', 109 | 'RI'=>'Rhode Island', 110 | 'SC'=>'South Carolina', 111 | 'SD'=>'South Dakota', 112 | 'TN'=>'Tennessee', 113 | 'TX'=>'Texas', 114 | 'UT'=>'Utah', 115 | 'VT'=>'Vermont', 116 | 'VA'=>'Virginia', 117 | 'WA'=>'Washington', 118 | 'WV'=>'West Virginia', 119 | 'WI'=>'Wisconsin', 120 | 'WY'=>'Wyoming', 121 | ); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Symfony](https://img.shields.io/badge/symfony-%23000000.svg?style=for-the-badge&logo=symfony&logoColor=white) 2 | ![PhpStorm](https://img.shields.io/badge/phpstorm-143?style=for-the-badge&logo=phpstorm&logoColor=black&color=black&labelColor=darkorchid) 3 | 4 | 5 | ![](https://img.shields.io/badge/v6.0-Breaking%20Change-red) 6 | 7 | # Symfony/Doctrine Seed Bundle 8 | Used to load/unload seed data from a doctrine database or anything that needs seeded. 9 | 10 | Example would be to load a table with a list of states and abbreviations, or populate the users table with initial admin user(s). 11 | Unlike the [DoctrineFixturesBundle](https://github.com/doctrine/DoctrineFixturesBundle) which is mainly for development this bundle is for seeding a database before the initial push to production. 12 | 13 | ## Installation 14 | Install the package with: 15 | ```console 16 | composer require evotodi/seed-bundle 17 | ``` 18 | 19 | 20 | (Optional) Load seeds as services `config/services.yaml` 21 | In Symfony default services.yaml classes in src/ are loaded as services, so creating a folder src/DataSeeds/ will load the seeds as services. 22 | ```yaml 23 | services: 24 | Evotodi\SeedBundle\DataSeeds\: 25 | resource: '../DataSeeds/*' 26 | ``` 27 | 28 | ## Building a seed to populate a database 29 | The `Seed` class is a `Command` and : 30 | 31 | - Must extend `Evotodi\SeedBundle\Command\Seed` 32 | - Must return the seed name from the static `seedName` method 33 | - Seed naming must follow the colon seperated naming convention for symfony console commands. 34 | 35 | 36 | ```php 37 | disableDoctrineLogging(); 82 | 83 | $users = [ 84 | [ 85 | 'email' => 'admin@admin.com', 86 | 'password' => 'password123', 87 | 'roles' => ['ROLE_ADMIN'], 88 | ], 89 | 90 | 91 | ]; 92 | 93 | foreach ($users as $user){ 94 | $userRepo = new User(); 95 | $userRepo->setEmail($user['email']); 96 | $userRepo->setRoles($user['roles']); 97 | $userRepo->setPassword($this->passwordEncoder->encodePassword($userRepo, $user['password'])); 98 | $this->manager->persist($userRepo); 99 | } 100 | $this->manager->flush(); 101 | $this->manager->clear(); 102 | 103 | /** 104 | * Must return an exit code. 105 | * A value other than 0 or Command::SUCCESS is considered a failed seed load/unload. 106 | */ 107 | return 0; 108 | } 109 | 110 | /** 111 | * The unload method is called when unloading a seed 112 | */ 113 | public function unload(InputInterface $input, OutputInterface $output): int 114 | { 115 | //Clear the table 116 | $this->manager->getConnection()->exec('DELETE FROM user'); 117 | 118 | /** 119 | * Must return an exit code. 120 | * A value other than 0 or Command::SUCCESS is considered a failed seed load/unload. 121 | */ 122 | return 0; 123 | } 124 | } 125 | ``` 126 | 127 | ## Seed commands 128 | The SeedBundle gives you two default commands and one for each seed you made. 129 | With the previous example, I'd have: 130 | 131 | ``` 132 | bin/console seed:load 133 | bin/console seed:unload 134 | bin/console seed:user 135 | ``` 136 | *Note: If your seeds do not show up in the command list under seed: then clear the cache* 137 | 138 | ## Global seed commands 139 | The global `seed:load` and `seed:unload` allow you to run multiple seeds in one command. 140 | The rest of this section will only show `seed:load` as it works the same as `seed:unload`. 141 | 142 | * `seed:load` will load all seeds in ascending order. 143 | * `seed:load user` will load only the user seed (see the example above). 144 | * Multiple seed like `seed:load user country town` will only load those seeds. 145 | * `seed:load --skip country` will load all seed except country. Multiple skips are allowed. 146 | * `seed:load --debug` with the debug flag will print what will be loaded and in what order. 147 | * `seed:load --break` will exit the seed load if a seed fails. 148 | * `seed:load --from country` will start with the county seed and load from there skipping lesser order values and possibly skipping same order values as country. 149 | See [Global seed ordering](#global-seed-ordering) for more details. 150 | 151 | ## Global seed name matching 152 | Seed names are matched using [webmozarts/glob](https://github.com/webmozarts/glob) filtering by turning the seed names into path like strings. 153 | An example would be if you had the following seeds: 154 | - prod:users:us 155 | - prod:users:eu 156 | - prod:users:it 157 | - prod:prices 158 | - prod:products 159 | - dev:users 160 | - dev:prices 161 | - dev:products 162 | 163 | And wanted to only load the users in the 'prod' group then call `seed:load prod/users/*` 164 | Or to load the whole 'prod' group then call `seed:load prod/**/*` 165 | Or load the 'dev' prices and products along with the 'prod' users then call `seed:load dev:prices dev:products prod:users:*` 166 | 167 | *Note: colons and forward slashed are interchangeable because all colons are replaced with forward slashes for filtering.* 168 | 169 | Please see the readme of [webmozarts/glob](https://github.com/webmozarts/glob) for more information on glob patterns. 170 | 171 | ## Global seed ordering 172 | Every seed has a `getOrder` method that is used to sort them. The default value is `0`. 173 | Seeds are loaded/unloaded in ascending order. 174 | 175 | #### Caution: Seeds with the same order value are loaded semi-randomly. This is especially a concern when using the --from option. 176 | #### Example issue of ordering and --from 177 | Seeds: 178 | * seed-a order 0 179 | * seed-b order 1 180 | * seed-c order 1 181 | * seed-d order 1 182 | * seed-e order 2 183 | 184 | Calling `seed:load --from seed-c` will start loading with seed-c but since seed-b and seed-d have the same order one or both may or may not be loaded depending on what order they were loaded into the registry. 185 | It is suggested to use the `--debug` flag to verify the order of loading or sequentially order your seeds. 186 | 187 | ## Manual seed commands 188 | Calling `seed:user load` (from example above) will load only the user seed. Conversely, calling `seed:user unload` will unload it. 189 | 190 | ## Example project 191 | In the example folder is a project that can be used to experiment with the Seed bundle. 192 | It shows how to seed a database or flat file. 193 | 194 | ## Thanks 195 | Thanks to soyuka/SeedBundle 196 | 197 | ## Contributions 198 | Contributions are very welcome! 199 | 200 | Please create detailed issues and PRs. 201 | 202 | ## Licence 203 | 204 | This package is free software distributed under the terms of the [MIT license](LICENSE). 205 | 206 | ## Updates 207 | * 2024-01-16 208 | * Fix depreciations for PHP 8.4 209 | * 2022-05-10 ![](https://img.shields.io/badge/v6.0-Breaking%20Change-red) 210 | * Breaking changes to previous versions as this is mostly a re-write of the bundle. 211 | * Seeds no longer need to have a name ending in seed 212 | * Setting the seed name is no longer supported in the configure method. Use the static method seedName to return the seed name. 213 | * The configuration file has been dropped 214 | * Php 8+ is required 215 | * Symfony 6+ is required 216 | * 2021-12-06 217 | * Updated dependencies to allow for symfony 5.3 and 5.4 218 | * 2020-06-03 219 | * Updated dependencies to allow for Symfony 4.4.* and 5.0.* and 5.1.* 220 | * 2020-04-23 221 | * Updated dependencies to allow for Symfony 4.4.* and 5.0.* 222 | * Added a required return exit code to load and unload functions 223 | * Updated tests to reflect required return code 224 | -------------------------------------------------------------------------------- /src/Core/SeedCoreCommand.php: -------------------------------------------------------------------------------- 1 | manager = $manager; 31 | } 32 | 33 | /** @noinspection PhpUnused */ 34 | public function setRegistry(SeedRegistry $registry): void 35 | { 36 | $this->registry = $registry; 37 | } 38 | 39 | public static function seedName(): string 40 | { 41 | return self::CORE_SEED_NAME; 42 | } 43 | 44 | /** @noinspection PhpUnused */ 45 | public static function getOrder(): int 46 | { 47 | return 0; 48 | } 49 | 50 | private function getSeedName(): string 51 | { 52 | return preg_replace('/^seed:/', '', $this->getName()); 53 | } 54 | 55 | public function getManager(?string $name = null): ObjectManager 56 | { 57 | return $this->manager->getManager($name); 58 | } 59 | 60 | protected function baseConfigure(): void 61 | { 62 | $this 63 | ->setName(sprintf('seed:%s', $this->seedName())) 64 | ->addOption('skip', '-s', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Seed(s) to skip') 65 | ->addOption('break', '-b', InputOption::VALUE_NONE, 'Stop on failed seed') 66 | ->addOption('debug', '-d', InputOption::VALUE_NONE, 'Debug seed ordering without making changes') 67 | ->addOption('from', '-f', InputOption::VALUE_REQUIRED, 'Start from seed. Unavailable for glob matching') 68 | ; 69 | } 70 | 71 | protected function configure(): void 72 | { 73 | $this 74 | ->addArgument('seeds', InputArgument::IS_ARRAY, 'seed(s)') 75 | ; 76 | $this->baseConfigure(); 77 | } 78 | 79 | protected function execute(InputInterface $input, OutputInterface $output): int 80 | { 81 | $io = new SymfonyStyle($input, $output); 82 | $debug = $input->getOption('debug'); 83 | 84 | $seedArgs = []; 85 | if($input->hasArgument('seeds')){ 86 | /** Add seeds from args to seedLoadNames */ 87 | $seedArgs = $input->getArgument('seeds'); 88 | if(empty($seedArgs)){ 89 | $seedArgs = $this->registry->keys(); 90 | } 91 | }else{ 92 | /** Else add single command seed to seedLoadNames */ 93 | $seedArgs[] = $this->getSeedName(); 94 | } 95 | 96 | if($input->hasArgument('method')){ 97 | $this->method = $input->getArgument('method'); 98 | $this->manual = true; 99 | } 100 | 101 | if (!in_array($this->method, ['load', 'unload'])) { 102 | throw new InvalidArgumentException('Method should be one of: load, unload'); 103 | } 104 | 105 | /** Check if seed from is valid */ 106 | $from = $input->getOption('from'); 107 | if($from) { 108 | $from = strtolower($from); 109 | if (!$this->registry->has($from)) { 110 | throw new InvalidArgumentException(sprintf("Invalid from seed %s! Valid seeds are '%s'", $from, join(", '", $this->registry->keys()))); 111 | } 112 | $io->text(sprintf('Starting at seed %s', get_class($this->registry->get($from)['class']))); 113 | } 114 | 115 | /** Check if seed skips is valid */ 116 | $skips = $input->getOption('skip'); 117 | if(!empty($skips)){ 118 | foreach ($skips as $sKey => $skip){ 119 | $skips[$sKey] = strtolower($skip); 120 | if (!$this->registry->has(strtolower($skip))) { 121 | throw new InvalidArgumentException(sprintf("Invalid skip seed %s! Valid seeds are '%s'", $skip, join(", '", $this->registry->keys()))); 122 | } 123 | } 124 | } 125 | 126 | /** Gather all seeds to process */ 127 | $seedsToProcess = []; 128 | foreach ($seedArgs as $seedArg) { 129 | foreach ($this->registry->glob($seedArg) as $seedName){ 130 | $seedsToProcess[] = $seedName; 131 | } 132 | } 133 | $seedsToProcess = array_unique($seedsToProcess); 134 | 135 | /** Check if seed names are valid and create SeedItems */ 136 | $seedItems = []; 137 | foreach ($seedsToProcess as $seedName) { 138 | if (!$this->registry->has($seedName)) { 139 | throw new InvalidArgumentException(sprintf("Invalid seed '%s'! Valid seeds are '%s'", $seedName, join(", '", $this->registry->keys()))); 140 | } 141 | $regItem = $this->registry->get($seedName); 142 | $seedItems[] = new SeedItem($regItem['name'], $regItem['class'], $regItem['order'], $this->manual); 143 | } 144 | 145 | /** Sort the seeds in order */ 146 | usort($seedItems, function ($a, $b) { 147 | return $a->order <=> $b->order; 148 | }); 149 | 150 | /** Check for seeds to process */ 151 | if(count($seedItems) == 0){ 152 | $io->warning("No seeds found"); 153 | return Command::FAILURE; 154 | } 155 | 156 | $processStartTime = microtime(true); 157 | $failedSeeds = []; 158 | $skippedSeeds = []; 159 | $startFrom = true; 160 | 161 | if($debug){ 162 | $io->warning("Debugging seed order. No changes will be made."); 163 | } 164 | foreach ($seedItems as $seedItem){ 165 | $retCode = 0; 166 | if($startFrom and $from){ 167 | if($seedItem->name != $from){ 168 | $io->text(sprintf('Skipping by from %s order %s', $seedItem->getClassName(), $seedItem->order)); 169 | $skippedSeeds[] = $seedItem->getClassName(); 170 | continue; 171 | }else{ 172 | $startFrom = false; 173 | } 174 | } 175 | 176 | if(in_array($seedItem->name, $skips)){ 177 | $io->text(sprintf('Skipping by skip %s order %s', $seedItem->getClassName(), $seedItem->order)); 178 | $skippedSeeds[] = $seedItem->getClassName(); 179 | continue; 180 | } 181 | 182 | $seedStartTime = microtime(true); 183 | 184 | switch ($this->method) { 185 | case 'load': 186 | if($debug){ 187 | $io->text(sprintf('Debug loading %s with order %s', $seedItem->getClassName(), $seedItem->order)); 188 | }else { 189 | $io->text(sprintf('Starting load %s order %s...', $seedItem->getClassName(), $seedItem->order)); 190 | if ($seedItem->manual) { 191 | /** @noinspection PhpUnhandledExceptionInspection */ 192 | $retCode = $this->load($input, $output); 193 | } else { 194 | $cls = $seedItem->classRef; 195 | $retCode = $cls->load($input, $output); 196 | 197 | } 198 | } 199 | break; 200 | case 'unload': 201 | if($debug){ 202 | $io->text(sprintf('Debug unloading %s with order %s', $seedItem->getClassName(), $seedItem->order)); 203 | }else { 204 | $io->text(sprintf('Starting unload %s order %s...', $seedItem->getClassName(), $seedItem->order)); 205 | if ($seedItem->manual) { 206 | /** @noinspection PhpUnhandledExceptionInspection */ 207 | $retCode = $this->unload($input, $output); 208 | } else { 209 | $cls = $seedItem->classRef; 210 | $retCode = $cls->unload($input, $output); 211 | } 212 | } 213 | break; 214 | } 215 | 216 | $seedTime = microtime(true) - $seedStartTime; 217 | 218 | if($retCode > 0){ 219 | $io->text(sprintf('Failed processing seed %s return code was %s (%.2f seconds)', $seedItem->getClassName(), $retCode, $seedTime)); 220 | $failedSeeds[] = $seedItem->getClassName(); 221 | }else{ 222 | if(!$debug) { 223 | $io->text(sprintf('Seed done %s (%.2f seconds)', $seedItem->getClassName(), $seedTime)); 224 | } 225 | } 226 | if($input->getOption('break')){ 227 | $io->text("Stopped on failed seed"); 228 | return Command::FAILURE; 229 | } 230 | } 231 | 232 | $processTime = microtime(true) - $processStartTime; 233 | if(!$debug) { 234 | $completeMessage = sprintf('Loading seed(s) completed (%.2f seconds)', $processTime); 235 | if(empty($failedSeeds) and empty($skippedSeeds)) { 236 | $io->success($completeMessage); 237 | }else{ 238 | if(!empty($failedSeeds)){ 239 | $completeMessage .= sprintf("\nFailed Seeds: %s", join(', ', array_unique($failedSeeds))); 240 | } 241 | if(!empty($skippedSeeds)){ 242 | $completeMessage .= sprintf("\nSkipped Seeds: %s", join(', ', array_unique($skippedSeeds))); 243 | } 244 | $io->warning($completeMessage); 245 | } 246 | } 247 | 248 | return Command::SUCCESS; 249 | } 250 | 251 | /** 252 | * @noinspection PhpUnhandledExceptionInspection 253 | * @noinspection PhpUnusedParameterInspection 254 | */ 255 | public function load(InputInterface $input, OutputInterface $output): int 256 | { 257 | throw new Exception("Core seed load should not be called"); 258 | } 259 | 260 | /** 261 | * @noinspection PhpUnhandledExceptionInspection 262 | * @noinspection PhpUnusedParameterInspection 263 | */ 264 | public function unload(InputInterface $input, OutputInterface $output): int 265 | { 266 | 267 | throw new Exception("Core seed unload should not be called"); 268 | } 269 | 270 | /** 271 | * disableDoctrineLogging 272 | * Shortcut to disable doctrine logging, useful when loading big seeds to 273 | * avoid memory leaks. 274 | * @noinspection PhpUnused 275 | */ 276 | protected function disableDoctrineLogging(): void 277 | { 278 | $config = $this->manager->getConnection()->getConfiguration(); 279 | if (method_exists($config,'setSQLLogger')) { 280 | $config->setSQLLogger(null); 281 | } else { 282 | $config->setMiddlewares(array_filter( 283 | $config->getMiddlewares(), 284 | fn($middleware) => !($middleware instanceof Middleware) 285 | )); 286 | } 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /tests/SeedCommandTest.php: -------------------------------------------------------------------------------- 1 | application = new Application($kernel); 23 | self::$cacheDir = self::$kernel->getCacheDir(); 24 | } 25 | 26 | public static function tearDownAfterClass(): void 27 | { 28 | parent::tearDownAfterClass(); 29 | /** Remove the cache dir */ 30 | if(!is_null(self::$cacheDir) and self::$cacheDir != '/') { 31 | (new Filesystem())->remove(self::$cacheDir); 32 | } 33 | } 34 | 35 | /** @dataProvider seedProvider */ 36 | public function testSeedsExist(string $seed) 37 | { 38 | $command = $this->application->find($seed); 39 | $this->assertEquals($seed, $command->getName()); 40 | } 41 | 42 | public function seedProvider(): Generator 43 | { 44 | yield 'Country Seed' => ['seed:country']; 45 | yield 'Glob Seed A' => ['seed:foo:bar']; 46 | yield 'Glob Seed B' => ['seed:foo:baz']; 47 | yield 'Postcode Seed' => ['seed:postcode']; 48 | yield 'Street Seed' => ['seed:street']; 49 | yield 'Town Seed' => ['seed:town']; 50 | yield 'Fail Seed' => ['seed:fail']; 51 | } 52 | 53 | public function testBadSeedNotExist() 54 | { 55 | $this->expectException(CommandNotFoundException::class); 56 | $this->application->find("seed:bad"); 57 | } 58 | 59 | public function testSeedCommandMethod() 60 | { 61 | $this->expectException(InvalidArgumentException::class); 62 | $this->expectExceptionMessage("Method should be one of: load, unload"); 63 | $command = $this->application->find('seed:country'); 64 | 65 | $commandTester = new CommandTester($command); 66 | $commandTester->execute(['command' => $command->getName(), 'method' => 'nonexistant']); 67 | 68 | $this->assertEquals(1, $commandTester->getStatusCode()); 69 | } 70 | 71 | public function testNoSeeds() 72 | { 73 | $tokenServiceMock = $this->getMockBuilder(SeedRegistry::class) 74 | ->disableOriginalConstructor() 75 | ->getMock(); 76 | self::getContainer()->set('seed.registry', $tokenServiceMock); 77 | 78 | $command = $this->application->find('seed:load'); 79 | $commandTester = new CommandTester($command); 80 | $commandTester->execute(['command' => $command->getName()]); 81 | 82 | $this->assertMatchesRegularExpression('/No seeds found/', $commandTester->getDisplay()); 83 | $this->assertEquals(1, $commandTester->getStatusCode()); 84 | } 85 | 86 | public function testLoadSeeds() 87 | { 88 | $command = $this->application->find('seed:load'); 89 | 90 | $commandTester = new CommandTester($command); 91 | $commandTester->execute(['command' => $command->getName()]); 92 | 93 | $output = $commandTester->getDisplay(); 94 | 95 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\CountrySeed/", $output); 96 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\CountrySeed/", $output); 97 | 98 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\TownSeed/", $output); 99 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\TownSeed/", $output); 100 | 101 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\StreetSeed/", $output); 102 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\StreetSeed/", $output); 103 | 104 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\PostcodeSeed/", $output); 105 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\PostcodeSeed/", $output); 106 | 107 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedA/", $output); 108 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedA/", $output); 109 | 110 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedB/", $output); 111 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedB/", $output); 112 | 113 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\FailSeed/", $output); 114 | $this->assertMatchesRegularExpression("/Failed processing seed Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\FailSeed/", $output); 115 | 116 | $this->assertEquals(0, $commandTester->getStatusCode()); 117 | } 118 | 119 | public function testUnloadSeeds() 120 | { 121 | $command = $this->application->find('seed:unload'); 122 | 123 | $commandTester = new CommandTester($command); 124 | $commandTester->execute(['command' => $command->getName()]); 125 | 126 | $output = $commandTester->getDisplay(); 127 | 128 | $this->assertMatchesRegularExpression("/Starting unload Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\CountrySeed/", $output); 129 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\CountrySeed/", $output); 130 | 131 | $this->assertMatchesRegularExpression("/Starting unload Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\TownSeed/", $output); 132 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\TownSeed/", $output); 133 | 134 | $this->assertMatchesRegularExpression("/Starting unload Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\StreetSeed/", $output); 135 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\StreetSeed/", $output); 136 | 137 | $this->assertMatchesRegularExpression("/Starting unload Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\PostcodeSeed/", $output); 138 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\PostcodeSeed/", $output); 139 | 140 | $this->assertMatchesRegularExpression("/Starting unload Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedA/", $output); 141 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedA/", $output); 142 | 143 | $this->assertMatchesRegularExpression("/Starting unload Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedB/", $output); 144 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedB/", $output); 145 | 146 | $this->assertMatchesRegularExpression("/Starting unload Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\FailSeed/", $output); 147 | $this->assertMatchesRegularExpression("/Failed processing seed Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\FailSeed/", $output); 148 | $this->assertEquals(0, $commandTester->getStatusCode()); 149 | } 150 | 151 | public function testNamedSeeds() 152 | { 153 | $command = $this->application->find('seed:load'); 154 | 155 | $commandTester = new CommandTester($command); 156 | $commandTester->execute(['command' => $command->getName(), 'seeds' => ['country']]); 157 | 158 | $output = $commandTester->getDisplay(); 159 | 160 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\CountrySeed/", $output); 161 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\CountrySeed/", $output); 162 | 163 | $this->assertDoesNotMatchRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\TownSeed/", $output); 164 | $this->assertDoesNotMatchRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\TownSeed/", $output); 165 | 166 | $this->assertDoesNotMatchRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\StreetSeed/", $output); 167 | $this->assertDoesNotMatchRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\StreetSeed/", $output); 168 | 169 | $this->assertDoesNotMatchRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\PostcodeSeed/", $output); 170 | $this->assertDoesNotMatchRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\PostcodeSeed/", $output); 171 | 172 | $this->assertDoesNotMatchRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedA/", $output); 173 | $this->assertDoesNotMatchRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedA/", $output); 174 | 175 | $this->assertDoesNotMatchRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedB/", $output); 176 | $this->assertDoesNotMatchRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedB/", $output); 177 | 178 | $this->assertDoesNotMatchRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\FailSeed/", $output); 179 | $this->assertDoesNotMatchRegularExpression("/Failed processing seed Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\FailSeed/", $output); 180 | 181 | $this->assertEquals(0, $commandTester->getStatusCode()); 182 | } 183 | 184 | public function testGlobSeeds() 185 | { 186 | $command = $this->application->find('seed:load'); 187 | 188 | $commandTester = new CommandTester($command); 189 | $commandTester->execute(['command' => $command->getName(), 'seeds' => ['foo:*']]); 190 | 191 | $output = $commandTester->getDisplay(); 192 | 193 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedA/", $output); 194 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedA/", $output); 195 | 196 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedB/", $output); 197 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedB/", $output); 198 | 199 | $this->assertEquals(0, $commandTester->getStatusCode()); 200 | } 201 | 202 | public function testSkipSeeds() 203 | { 204 | $command = $this->application->find('seed:load'); 205 | 206 | $commandTester = new CommandTester($command); 207 | $commandTester->execute(['command' => $command->getName(), '--skip' => ['Town', 'fail']]); 208 | 209 | $output = $commandTester->getDisplay(); 210 | 211 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\CountrySeed/", $output); 212 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\CountrySeed/", $output); 213 | 214 | $this->assertDoesNotMatchRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\TownSeed/", $output); 215 | $this->assertDoesNotMatchRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\TownSeed/", $output); 216 | 217 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\StreetSeed/", $output); 218 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\StreetSeed/", $output); 219 | 220 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\PostcodeSeed/", $output); 221 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\PostcodeSeed/", $output); 222 | 223 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedA/", $output); 224 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedA/", $output); 225 | 226 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedB/", $output); 227 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\GlobSeedB/", $output); 228 | 229 | $this->assertDoesNotMatchRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\FailSeed/", $output); 230 | $this->assertDoesNotMatchRegularExpression("/Failed processing seed Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\FailSeed/", $output); 231 | 232 | $this->assertEquals(0, $commandTester->getStatusCode()); 233 | } 234 | 235 | public function testBreakSeed() 236 | { 237 | $command = $this->application->find('seed:load'); 238 | 239 | $commandTester = new CommandTester($command); 240 | $commandTester->execute(['command' => $command->getName(), '-b' => true]); 241 | 242 | $output = $commandTester->getDisplay(); 243 | 244 | $this->assertDoesNotMatchRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\CountrySeed/", $output); 245 | $this->assertDoesNotMatchRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\CountrySeed/", $output); 246 | 247 | $this->assertDoesNotMatchRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\TownSeed/", $output); 248 | $this->assertDoesNotMatchRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\TownSeed/", $output); 249 | 250 | $this->assertDoesNotMatchRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\StreetSeed/", $output); 251 | $this->assertDoesNotMatchRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\StreetSeed/", $output); 252 | 253 | $this->assertMatchesRegularExpression('/Failed processing seed Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\FailSeed/', $output); 254 | $this->assertEquals(1, $commandTester->getStatusCode()); 255 | } 256 | 257 | public function testDebugSeed() 258 | { 259 | $command = $this->application->find('seed:load'); 260 | 261 | $commandTester = new CommandTester($command); 262 | $commandTester->execute(['command' => $command->getName(), '-d' => true, 'seeds' => ['country']]); 263 | 264 | $output = $commandTester->getDisplay(); 265 | 266 | $this->assertMatchesRegularExpression('/Debug loading Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\CountrySeed/', $output); 267 | $this->assertEquals(0, $commandTester->getStatusCode()); 268 | } 269 | 270 | public function testFromSeed() 271 | { 272 | $command = $this->application->find('seed:load'); 273 | 274 | $commandTester = new CommandTester($command); 275 | $commandTester->execute(['command' => $command->getName(), '-f' => 'street']); 276 | 277 | $output = $commandTester->getDisplay(); 278 | 279 | $this->assertDoesNotMatchRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\CountrySeed/", $output); 280 | $this->assertDoesNotMatchRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\CountrySeed/", $output); 281 | 282 | $this->assertDoesNotMatchRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\TownSeed/", $output); 283 | $this->assertDoesNotMatchRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\TownSeed/", $output); 284 | 285 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\StreetSeed/", $output); 286 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\StreetSeed/", $output); 287 | 288 | $this->assertMatchesRegularExpression("/Starting load Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\PostcodeSeed/", $output); 289 | $this->assertMatchesRegularExpression("/Seed done Evotodi\\\\SeedBundle\\\\Tests\\\\fixtures\\\\PostcodeSeed/", $output); 290 | 291 | $this->assertEquals(0, $commandTester->getStatusCode()); 292 | } 293 | 294 | } 295 | --------------------------------------------------------------------------------