Move Fixtures Out of src/ Folder
Tags: doctrine, fixtures, php, symfony
Published: 2020-10-06 16:37:14

We'll see in this post an alternative place to write [fixtures][doctrine-data-fixtures] in an [Symfony] application.

---

According to the [Symfony Framework Best Practices][default-directory-structure], fixtures should be placed in `src/DataFixtures/`.

I'll briefly argue against this.

---

Development, tests, and build stuff is supposed to be discarded once the application is built. Fixtures are precisely this, a set of files for testing and/or development purposes.

I would say we should place fixtures outside of `src/` for the same reasons we write tests in the `tests/` directory. It's better to not bloat the `src/` with code that isn't business logic.

The golden rule is to not pollute `src/` directory with non-runtime stuff.

---

## Fixtures Under `fixtures/`

I propose to place fixtures inside the `fixtures/` directory in the root of the project instead of `src/DataFixtures/`.

From:

```
project/
└─ src/
   └─ DataFixtures/
```

To:

```
project/
├─ fixtures/
└─ src/
```

## Implementation

Let's make it real in your [Symfony] application. It may work with [Symfony Demo] as well.

### Move Files

1. Move the `src/DataFixtures/` directory to the root;
1. Rename it as `fixtures/`; and
1. Change its classes namespaces to `App\Fixtures`<sup>*</sup>.

At this point, the `doctrine:fixtures:load` command doesn't work because it can't find fixtures anymore. If you try running it you'll get this error message:

```
[ERROR] Could not find any fixture services to load.
```

In order to fix it, we must:

- Inform [Composer] there is a new directory that contains classes (dev only); and
- Make the classes inside this directory loadable as service (dev only as well).

### Fix Classes Autoloading

Add `"App\\Fixtures\\": "fixtures/"`<sup>*</sup> to the `autoload-dev` section in `composer.json`.

```diff
     "autoload-dev": {
         "psr-4": {
+            "App\\Fixtures\\": "fixtures/",
             "App\\Tests\\": "tests/"
         }
     },
```

Don't forget to run:

```bash
composer dump-autoload
```

### Configure Services Loading

Make the new `fixtures/` content<sup>*</sup> findable by [loading them automaticaly] in `config/services_dev.yaml`.

```yaml
# config/services_dev.yaml

services:
    _defaults:
        autowire: true
        autoconfigure: true

    App\Fixtures\:
        resource: '../fixtures/*'
```

If you need fixtures in another mode (e.g. `test`), create the corresponding file (e.g. `config/services_test.yaml`) with the same content above. 

## Fin

The command below should work as before.

```bash
bin/console doctrine:fixtures:load
```

---

<sup>*</sup> I use `App\Fixtures` instead of `App\DataFixtures` as namespace. It's up to you to adopt it or not.

[loading them automaticaly]: https://symfony.com/doc/current/service_container.html#service-container-services-load-example
[doctrine-data-fixtures]: https://github.com/doctrine/data-fixtures
[symfony]: https://symfony.com/
[default-directory-structure]: https://symfony.com/doc/5.1/best_practices.html#use-the-default-directory-structure
[composer]: https://getcomposer.org/
[Symfony Demo]: https://github.com/symfony/demo