Custom Alice Fixture Processor Using Symfony

Fixtures, those nice little bits of data that you can put into your database so that when you’re developing locally you actually have something to look at: like products or users or whatever else you want to play with.
I am using https://github.com/hautelook/AliceBundle, a Symfony bundle to manage fixtures with Alice and Faker.
I’ll create the DataFixtures/ORM directory inside UserBundle. And I’ll create a file called UserFixtures. Copy the contents in there and don’t forget to update your namespace and rename the class:
<?php

// src/UserBundle/DataFixtures/ORM/UserFixtures.php
namespace UserBundle\DataFixtures\ORM;

use Hautelook\AliceBundle\Doctrine\DataFixtures\AbstractLoader;
use Nelmio\Alice\Fixtures;

class UserFixtures extends AbstractLoader
{
    /**
    * {@inheritDoc}
    */
    public function getFixtures()
    {
        return  array(
                __DIR__ . '/users.yml',
        );
    }
}
The fixtures class is special because it’s already wired up to load yml files. Let’s call ours users.yml and then go ahead and create that file:

# src/UserBundle/DataFixtures/ORM/users.yml
UserBundle\Entity\user:
    user_1:
        name: Anup Shakya
        email_address: anup.shakya@example.com
        password: testing
 
Loading your Fixtures
This is a wrapper around the Doctrine fixtures library so we use the same doctrine command php app/console hautelook_alice:doctrine:fixtures:load to load fixtures.

Creating the Processor
Whenever you need to do something other than just setting simple data, you'll use a Processor, which is like a hook that's called before and after each object is saved. For example, We need to encode the password using Symfony security password encoder. This is where Processors come in.

Step 1. Create a new class. It doesn't matter where it goes, so put it inside ORM/Processor/ and call it UserProcessor. The only rule of a processor is that it needs to implement ProcessorInterface. And that means we have to have two methods: postProcess() and preProcess().

Each is passed whatever object is being saved right now, so let's just dump the class of the object:
<?php
// src/UserBundle/DataFixtures/ORM/Processor/UserProcessor.php
namespace UserBundle\DataFixtures\Processor;

use Nelmio\Alice\ProcessorInterface;
use UserBundle\Entity\User;

class UserProcessor implements ProcessorInterface
{
    protected $encoder;

    public function __construct($encoder)
    {
        $this->encoder = $encoder;
    }

    public function preProcess($object)
    {
        if (!$object instanceof User) {
            return;
        }

        $password = $this->encoder->encodePassword($object, $object->getPassword());
        $object->setPassword($password);
    }

    public function postProcess($object)
    {

    }
}
Given you declared a processor UserBundle\DataFixtures\Processor\UserProcessor, you have to declare it as a service with the tag hautelook_alice.alice.processor to register it:
# app/config/services.yml
services:
    alice.processor.user:
        class: UserBundle\DataFixtures\Processor\UserProcessor
        arguments: ["@security.password_encoder"]
        tags: [ { name: hautelook_alice.alice.processor } ]
Let's reload the fixtures to see what happens!
php app/console hautelook_alice:doctrine:fixtures:load
Cool! It calls preProcessor for every object. And password is encoded.

I just wanted to share this, even if some already knows about alice processors. Ref: https://knpuniversity.com/screencast/alice-fixtures

Comments

Popular Posts