Skip to content

Commit

Permalink
Merge 1.5.x into 1.6.x (#386)
Browse files Browse the repository at this point in the history
  • Loading branch information
derrabus authored Apr 13, 2022
2 parents 91f59e4 + 14efe5f commit 2bc0b82
Show file tree
Hide file tree
Showing 14 changed files with 386 additions and 205 deletions.
18 changes: 12 additions & 6 deletions .doctrine-project.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,27 @@
"docsSlug": "doctrine-data-fixtures",
"versions": [
{
"name": "1.5",
"branchName": "1.5.x",
"slug": "latest",
"name": "1.6",
"branchName": "1.6.x",
"slug": "1.6",
"upcoming": true
},
{
"name": "1.4",
"branchName": "1.4.x",
"slug": "1.4",
"name": "1.5",
"branchName": "1.5.x",
"slug": "latest",
"current": true,
"aliases": [
"current",
"stable"
]
},
{
"name": "1.4",
"branchName": "1.4.x",
"slug": "1.4",
"maintained": false
},
{
"name": "1.3",
"branchName": "1.3",
Expand Down
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* text=auto eol=lf

# Exclude non-essential files from dist
/docs export-ignore
/tests export-ignore
/.gitattributes export-ignore
/.github export-ignore
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
- "7.3"
- "7.4"
- "8.0"
- "8.1"
dependencies:
- "highest"
include:
Expand Down
188 changes: 4 additions & 184 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,192 +3,12 @@
[![Build Status](https://github.com/doctrine/data-fixtures/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/data-fixtures/actions)

This extension aims to provide a simple way to manage and execute the loading of data fixtures
for the [Doctrine ORM or ODM](http://www.doctrine-project.org/). You can write fixture classes
by implementing the [`Doctrine\Common\DataFixtures\FixtureInterface`](lib/Doctrine/Common/DataFixtures/FixtureInterface.php) interface:
for the [Doctrine ORM or ODM](http://www.doctrine-project.org/).

```php
namespace MyDataFixtures;
## More resources:

use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Persistence\ObjectManager;

class UserDataLoader implements FixtureInterface
{
public function load(ObjectManager $manager): void
{
$user = new User();
$user->setUsername('jwage');
$user->setPassword('test');

$manager->persist($user);
$manager->flush();
}
}
```

Now you can begin adding the fixtures to a loader instance:

```php
use Doctrine\Common\DataFixtures\Loader;
use MyDataFixtures\UserDataLoader;

$loader = new Loader();
$loader->addFixture(new UserDataLoader());
```

You can load a set of fixtures from a directory as well:

```php
$loader->loadFromDirectory('/path/to/MyDataFixtures');
```

Or you can load a set of fixtures from a file:

```php
$loader->loadFromFile('/path/to/MyDataFixtures/MyFixture1.php');
```

You can get the added fixtures using the getFixtures() method:

```php
$fixtures = $loader->getFixtures();
```

Now you can easily execute the fixtures:

```php
use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;

$purger = new ORMPurger();
$executor = new ORMExecutor($em, $purger);
$executor->execute($loader->getFixtures());
```

If you want to append the fixtures instead of purging before loading then pass true
to the 2nd argument of execute:

```php
$executor->execute($loader->getFixtures(), true);
```

## Sharing objects between fixtures

In case if fixture objects have relations to other fixtures, it is now possible
to easily add a reference to that object by name and later reference it to form
a relation. Here is an example fixtures for **Role** and **User** relation

```php
namespace MyDataFixtures;

use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Persistence\ObjectManager;

class UserRoleDataLoader extends AbstractFixture
{
public function load(ObjectManager $manager): void
{
$adminRole = new Role();
$adminRole->setName('admin');

$anonymousRole = new Role();
$anonymousRole->setName('anonymous');

$manager->persist($adminRole);
$manager->persist($anonymousRole);
$manager->flush();

// store reference to admin role for User relation to Role
$this->addReference('admin-role', $adminRole);
}
}
```

And the **User** data loading fixture:

```php
namespace MyDataFixtures;

use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Persistence\ObjectManager;

class UserDataLoader extends AbstractFixture
{
public function load(ObjectManager $manager): void
{
$user = new User();
$user->setUsername('jwage');
$user->setPassword('test');
$user->setRole(
$this->getReference('admin-role') // load the stored reference
);

$manager->persist($user);
$manager->flush();

// store reference of admin-user for other Fixtures
$this->addReference('admin-user', $user);
}
}
```

## Fixture ordering
**Notice** that the fixture loading order is important! To handle it manually
implement one of the following interfaces:

### OrderedFixtureInterface

Set the order manually:

```php
namespace MyDataFixtures;

use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;

class MyFixture extends AbstractFixture implements OrderedFixtureInterface
{
public function load(ObjectManager $manager): void
{}

public function getOrder(): int
{
return 10; // number in which order to load fixtures
}
}
```

### DependentFixtureInterface

Provide an array of fixture class names:

```php
namespace MyDataFixtures;

use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;

class MyFixture extends AbstractFixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{}

public function getDependencies(): array
{
return [MyOtherFixture::class]; // fixture classes fixture is dependent on
}
}

class MyOtherFixture extends AbstractFixture
{
public function load(ObjectManager $manager): void
{}
}
```

**Notice** the ordering is relevant to Loader class.
* [Website](http://www.doctrine-project.org)
* [Documentation](https://www.doctrine-project.org/projects/doctrine-data-fixtures/en/latest/index.html)

## Running the tests:

Expand Down
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
"doctrine/dbal": "^2.13 || ^3.0",
"doctrine/mongodb-odm": "^1.3.0 || ^2.0.0",
"doctrine/orm": "^2.7.0",
"jangregor/phpstan-prophecy": "^0.8.1",
"phpstan/phpstan": "^0.12.99",
"phpunit/phpunit": "^8.0",
"jangregor/phpstan-prophecy": "^1",
"phpstan/phpstan": "^1.5",
"phpunit/phpunit": "^8.5 || ^9.5",
"symfony/cache": "^5.0 || ^6.0",
"vimeo/psalm": "^4.10"
},
Expand Down
22 changes: 22 additions & 0 deletions docs/en/explanation/transactions-and-purging.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Transactions and purging
========================

This package exposes an ``AbstractExecutor`` class and 3 concrete
implementations for ``doctrine/orm``, ``doctrine/mongodb-odm`` and
``doctrine/phpcr-odm``.

The executors purge the database, then load the fixtures. The ORM
implementation wraps these two steps in a database transaction, which
provides a nice additional property: atomicity.
Because of that transaction, the loading either succeeds or fails
cleanly, meaning nothing is actually changed in the database if the
loading fails. It delegates the purging to a separate class that can be
configured to either use a ``TRUNCATE`` or a ``DELETE`` statement to
empty tables.

Not all RDBMS have the capability to allow ``TRUNCATE`` statements
inside transactions though. Notably, MySQL will produce the infamous
"There is no active transaction" message when we attempt to close a
transaction that was already `implicitly closed`_.

.. _implicitly closed: https://www.doctrine-project.org/projects/doctrine-migrations/en/stable/explanation/implicit-commits
89 changes: 89 additions & 0 deletions docs/en/how-to/fixture-ordering.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
Fixture ordering
================

There are two interfaces you can implement in your fixtures to control
in which order they are going to be loaded.

* By implementing ``OrderedFixtureInterface``, you will be able to
manually specify a priority for each fixture.
* By implementing ``DependencyFixtureInterface``, you will be able to
declare which class must be loaded after which classes (note the
plural), and let the package figure out the order for you.

.. note::
You may implement an interface in a fixture, and another interface
in another fixture, and no even interface (besides
``FixtureInterface``) in a third one. Implementing both in the same
fixture is an error.

Option 1: Controlling the order manually
----------------------------------------

.. code-block:: php
<?php
namespace MyDataFixtures;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
final class MyFixture extends AbstractFixture implements OrderedFixtureInterface
{
public function load(ObjectManager $manager): void
{
// …
}
public function getOrder(): int
{
return 10; // smaller means sooner
}
}
.. note::
While extending ``AbstractFixture`` is not required, it is likely
you are going to need it since people usually need fixtures to be
loading in a specific order because of references from one fixture
to the other.

Option 2: Declaring dependencies
--------------------------------

If you have many models, and a project that evolves, there may be
several correct orders. Using ``OrderedFixtureInterface`` may become
impractical in case you need to insert a new fixture in a position where
there is no gap in the order. Instead of always renumbering the
fixtures, or being careful to leave big gaps, you can declare that your
fixture must be loaded after some other fixtures, and let the package
figure out what to do.

.. code-block:: php
<?php
namespace MyDataFixtures;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
class MyFixture extends AbstractFixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{
}
/**
* @return list<class-string<FixtureInterface>>
*/
public function getDependencies(): array
{
return [MyOtherFixture::class];
}
}
class MyOtherFixture extends AbstractFixture
{
public function load(ObjectManager $manager): void
{}
}
Loading

0 comments on commit 2bc0b82

Please sign in to comment.