index.rst 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. DoctrineFixturesBundle
  2. ======================
  3. Fixtures are used to load a "fake" set of data into a database that can then
  4. be used for testing or to help give you some interesting data while you're
  5. developing your application.
  6. This bundle is compatible with any database supported by `Doctrine ORM`_
  7. (MySQL, PostgreSQL, SQLite, etc.). If you are using MongoDB, you must use
  8. `DoctrineMongoDBBundle`_ instead.
  9. Installation
  10. ------------
  11. In Symfony 4 or higher applications that use `Symfony Flex`_, open a command
  12. console, enter your project directory and run the following command:
  13. .. code-block:: terminal
  14. $ composer require --dev orm-fixtures
  15. Starting from Symfony 4.0, Flex should be used by default and register the
  16. bundle for you, and in that case you can skip to the next section and start
  17. writing fixtures.
  18. In Symfony 3 applications (or when not using Symfony Flex), run this other
  19. command instead:
  20. .. code-block:: terminal
  21. $ composer require --dev doctrine/doctrine-fixtures-bundle
  22. You will also need to enable the bundle. In Symfony 3 and earlier applications,
  23. update the ``AppKernel`` class::
  24. // app/AppKernel.php
  25. // ...
  26. // registerBundles()
  27. if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
  28. // ...
  29. $bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle();
  30. }
  31. Writing Fixtures
  32. ----------------
  33. Data fixtures are PHP classes where you create objects and persist them to the
  34. database.
  35. Imagine that you want to add some ``Product`` objects to your database. No problem!
  36. Create a fixtures class and start adding products::
  37. // src/DataFixtures/AppFixtures.php
  38. namespace App\DataFixtures;
  39. use App\Entity\Product;
  40. use Doctrine\Bundle\FixturesBundle\Fixture;
  41. use Doctrine\Persistence\ObjectManager;
  42. class AppFixtures extends Fixture
  43. {
  44. public function load(ObjectManager $manager)
  45. {
  46. // create 20 products! Bam!
  47. for ($i = 0; $i < 20; $i++) {
  48. $product = new Product();
  49. $product->setName('product '.$i);
  50. $product->setPrice(mt_rand(10, 100));
  51. $manager->persist($product);
  52. }
  53. $manager->flush();
  54. }
  55. }
  56. .. tip::
  57. You can also create multiple fixtures classes. See :ref:`multiple-files`.
  58. Loading Fixtures
  59. ----------------
  60. Once your fixtures have been written, load them by executing this command:
  61. .. code-block:: terminal
  62. # when using the ORM
  63. $ php bin/console doctrine:fixtures:load
  64. .. caution::
  65. By default the ``load`` command **purges the database**, removing all data
  66. from every table. To append your fixtures' data add the ``--append`` option.
  67. This command looks for all services tagged with ``doctrine.fixture.orm``. If you're
  68. using the `default service configuration`_, any class that implements ``ORMFixtureInterface``
  69. (for example, those extending from ``Fixture``) will automatically be registered
  70. with this tag.
  71. To see other options for the command, run:
  72. .. code-block:: terminal
  73. $ php bin/console doctrine:fixtures:load --help
  74. Accessing Services from the Fixtures
  75. ------------------------------------
  76. In some cases you may need to access your application's services inside a fixtures
  77. class. No problem! Your fixtures class is a service, so you can use normal dependency
  78. injection::
  79. // src/DataFixtures/AppFixtures.php
  80. use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
  81. class AppFixtures extends Fixture
  82. {
  83. private $encoder;
  84. public function __construct(UserPasswordEncoderInterface $encoder)
  85. {
  86. $this->encoder = $encoder;
  87. }
  88. // ...
  89. public function load(ObjectManager $manager)
  90. {
  91. $user = new User();
  92. $user->setUsername('admin');
  93. $password = $this->encoder->encodePassword($user, 'pass_1234');
  94. $user->setPassword($password);
  95. $manager->persist($user);
  96. $manager->flush();
  97. }
  98. }
  99. .. _multiple-files:
  100. Splitting Fixtures into Separate Files
  101. --------------------------------------
  102. In most applications, creating all your fixtures in just one class is fine.
  103. This class may end up being a bit long, but it's worth it because having one
  104. file helps keeping things simple.
  105. If you do decide to split your fixtures into separate files, Symfony helps you
  106. solve the two most common issues: sharing objects between fixtures and loading
  107. the fixtures in order.
  108. Sharing Objects between Fixtures
  109. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  110. When using multiple fixtures files, you can reuse PHP objects across different
  111. files thanks to the **object references**. Use the ``addReference()`` method to
  112. give a name to any object and then, use the ``getReference()`` method to get the
  113. exact same object via its name::
  114. // src/DataFixtures/UserFixtures.php
  115. // ...
  116. class UserFixtures extends Fixture
  117. {
  118. public const ADMIN_USER_REFERENCE = 'admin-user';
  119. public function load(ObjectManager $manager)
  120. {
  121. $userAdmin = new User('admin', 'pass_1234');
  122. $manager->persist($userAdmin);
  123. $manager->flush();
  124. // other fixtures can get this object using the UserFixtures::ADMIN_USER_REFERENCE constant
  125. $this->addReference(self::ADMIN_USER_REFERENCE, $userAdmin);
  126. }
  127. }
  128. // src/DataFixtures/GroupFixtures.php
  129. // ...
  130. class GroupFixtures extends Fixture
  131. {
  132. public function load(ObjectManager $manager)
  133. {
  134. $userGroup = new Group('administrators');
  135. // this reference returns the User object created in UserFixtures
  136. $userGroup->addUser($this->getReference(UserFixtures::ADMIN_USER_REFERENCE));
  137. $manager->persist($userGroup);
  138. $manager->flush();
  139. }
  140. }
  141. The only caveat of using references is that fixtures need to be loaded in a
  142. certain order (in this example, if the ``Group`` fixtures are load before the
  143. ``User`` fixtures, you'll see an error). By default Doctrine loads the fixture
  144. files in alphabetical order, but you can control their order as explained in the
  145. next section.
  146. Loading the Fixture Files in Order
  147. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  148. Instead of defining the exact order in which all fixture files must be loaded,
  149. Doctrine uses a smarter approach to ensure that some fixtures are loaded before
  150. others. Implement the ``DependentFixtureInterface`` and add a new
  151. ``getDependencies()`` method to your fixtures class. This will return
  152. an array of the fixture classes that must be loaded before this one::
  153. // src/DataFixtures/UserFixtures.php
  154. namespace App\DataFixtures;
  155. // ...
  156. class UserFixtures extends Fixture
  157. {
  158. public function load(ObjectManager $manager)
  159. {
  160. // ...
  161. }
  162. }
  163. // src/DataFixtures/GroupFixtures.php
  164. namespace App\DataFixtures;
  165. // ...
  166. use App\DataFixtures\UserFixtures;
  167. use Doctrine\Common\DataFixtures\DependentFixtureInterface;
  168. class GroupFixtures extends Fixture implements DependentFixtureInterface
  169. {
  170. public function load(ObjectManager $manager)
  171. {
  172. // ...
  173. }
  174. public function getDependencies()
  175. {
  176. return array(
  177. UserFixtures::class,
  178. );
  179. }
  180. }
  181. Fixture Groups: Only Executing Some Fixtures
  182. --------------------------------------------
  183. By default, *all* of your fixture classes are executed. If you only want
  184. to execute *some* of your fixture classes, you can organize them into
  185. groups.
  186. The simplest way to organize a fixture class into a group is to
  187. make your fixture implement ``FixtureGroupInterface``:
  188. .. code-block:: diff
  189. // src/DataFixtures/UserFixtures.php
  190. + use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
  191. - class UserFixtures extends Fixture
  192. + class UserFixtures extends Fixture implements FixtureGroupInterface
  193. {
  194. // ...
  195. + public static function getGroups(): array
  196. + {
  197. + return ['group1', 'group2'];
  198. + }
  199. }
  200. To execute all of your fixtures for a given group, pass the ``--group``
  201. option:
  202. .. code-block:: terminal
  203. $ php bin/console doctrine:fixtures:load --group=group1
  204. # or to execute multiple groups
  205. $ php bin/console doctrine:fixtures:load --group=group1 --group=group2
  206. Alternatively, instead of implementing the ``FixtureGroupInterface``,
  207. you can also tag your service with ``doctrine.fixture.orm`` and add
  208. an extra ``group`` option set to a group your fixture should belong to.
  209. Regardless of groups defined in the fixture or the service definition, the
  210. fixture loader always adds the short name of the class as a separate group so
  211. you can load a single fixture at a time. In the example above, you can load the
  212. fixture using the ``UserFixtures`` group:
  213. .. code-block:: terminal
  214. $ php bin/console doctrine:fixtures:load --group=UserFixtures
  215. .. _`ORM`: https://symfony.com/doc/current/doctrine.html
  216. .. _`installation chapter`: https://getcomposer.org/doc/00-intro.md
  217. .. _`Symfony Flex`: https://symfony.com/doc/current/setup/flex.html
  218. .. _`default service configuration`: https://symfony.com/doc/current/service_container.html#service-container-services-load-example
  219. Specifying purging behavior
  220. ---------------------------
  221. By default all previously existing data is purged using ``DELETE FROM table`` statements. If you prefer to use
  222. ``TRUNCATE table`` statements for purging, use ``--purge-with-truncate``.
  223. If you want to exclude a set of tables from being purged, e.g. because your schema comes with pre-populated,
  224. semi-static data, pass the option ``--purge-exclusions``. Specify ``--purge-exclusions`` multiple times to exclude
  225. multiple tables.
  226. You can also customize purging behavior significantly more and implement a custom purger plus a custom purger factory::
  227. // src/Purger/CustomPurger.php
  228. namespace App\Purger;
  229. use Doctrine\Common\DataFixtures\Purger\PurgerInterface;
  230. // ...
  231. class CustomPurger implements PurgerInterface
  232. {
  233. public function purge() : void
  234. {
  235. // ...
  236. }
  237. }
  238. // src/Purger/CustomPurgerFactory.php
  239. namespace App\Purger;
  240. // ...
  241. use Doctrine\Bundle\FixturesBundle\Purger\PurgerFactory;
  242. class CustomPurgerFactory implements PurgerFactory
  243. {
  244. public function createForEntityManager(?string $emName, EntityManagerInterface $em, array $excluded = [], bool $purgeWithTruncate = false) : PurgerInterface;
  245. {
  246. return new CustomPurger($em);
  247. }
  248. }
  249. The next step is to register our custom purger factory and specify its alias.
  250. .. configuration-block::
  251. .. code-block:: yaml
  252. # config/services.yaml
  253. services:
  254. App\Purger\CustomPurgerFactory:
  255. tags:
  256. - { name: 'doctrine.fixtures.purger_factory', alias: 'my_purger' }
  257. .. code-block:: xml
  258. <!-- config/services.xml -->
  259. <?xml version="1.0" encoding="UTF-8" ?>
  260. <container xmlns="http://symfony.com/schema/dic/services"
  261. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  262. xsi:schemaLocation="http://symfony.com/schema/dic/services
  263. https://symfony.com/schema/dic/services/services-1.0.xsd">
  264. <services>
  265. <service id="App\Purger\CustomPurgerFactory">
  266. <tag name="doctrine.fixtures.purger_factory" alias="my_purger"/>
  267. </service>
  268. </services>
  269. </container>
  270. .. code-block:: php
  271. // config/services.php
  272. namespace Symfony\Component\DependencyInjection\Loader\Configurator;
  273. use App\Purger\CustomerPurgerFactory;
  274. return function(ContainerConfigurator $configurator) : void {
  275. $services = $configurator->services();
  276. $services->set(CustomerPurgerFactory::class)
  277. ->tag('doctrine.fixtures.purger_factory', ['alias' => 'my_purger'])
  278. ;
  279. };
  280. With the ``--purger`` option we can now specify to use ``my_purger`` instead of the ``default`` purger.
  281. .. code-block:: terminal
  282. $ php bin/console doctrine:fixtures:load --purger=my_purger
  283. .. _`Doctrine ORM`: https://symfony.com/doc/current/doctrine.html
  284. .. _`DoctrineMongoDBBundle`: https://github.com/doctrine/DoctrineMongoDBBundle