在持久化之前创建机器可读的名称

In a Symfony2/Doctrine project, I have an Entity called Developer including those fields in particular:

 1. firstName
 2. lastName
 3. machineName

The form to create a Developer item only shows firstName and lastName fields. I'd like the machineName to be automatically generated when the user creates a Developer item, based on the two other fields.

For instance, John Doe would give john_doe and Jérémy Arçouille would give jeremy_arcouille.

So my questions are:

  1. Is there a general best practice for this (pretty common) case?
  2. Do I have to code something from my own or is it something pretty standard?
  3. If (2 == true) what would be the best place (services? utils?) to put that trunk of code?
  4. Should I rather call this portion of code from the controller or from the entity?

Note: because it would be quite a portion of code, and I'd like it to be reusable, I don't want to put into a prePersist lifecycle callback

I once developed a full solution for this problem and it worked well, but was really lame and spaghetti-esque, so I'd rather make something more in the proper Symfony2 way by now.

Thanks for any help.

There are at least two approaches you could try in this case.

  1. Create prePresists event listener. This solution is very easy to implement, works transparently from the application point of view and can be used with existing code.

    1. Define your listener service:

      use Doctrine\Common\EventSubscriber;
      use Doctrine\ORM\Events;
      use Doctrine\ORM\Event\LifecycleEventArgs;
      
      class MyEventListener implements EventSubscriber
      {
          public function __construct(/* ... */)
          {
              /* you can use other services here */
          }
      
          public function prePersist(LifecycleEventArgs $event)
          {
              $developer = $event->getEntity();
      
              if (!($developer instanceof Developer) || $developer->hasMachineName()) {
                  return;
              }
      
              ...
              $developer->setMachineName(...);
          }
      
          public function getSubscribedEvents()
          {
              return array(Events::prePersist);
          }
      }
      
    2. Declare it in Symofny's service container

      <service id="..." class="...">
          <!-- <argument ... /> -->
          <tag name="doctrine.event_subscriber" />
      </service>
      
    3. You're done.

  2. Create appropriate domain/bussines layer for your application. This requires more work, forces you to follow some general guidelines but makes your code much more flexible and easy to maintain. In a nutshell, instead of using Doctrine's ObjectManager directly inside your controllers create a whole new layer of servers dedicated to work with your domain objects. This layer sholud contain, among others, a service that's responsible for persisting developers with save(Developer $dev) method. This method should do exactly the same job as MyEventListener from first approach.

PS. You shouldn't do any complex operations or refer to external classes from within your entities.

ok, here is what I came up with for the moment.

I created a class file in MyBundle\Utils\MachinesNames.php, containing a method called by Developer entity's class:

// MyBundle\Utils\MachineNames.php
class MachinesNames
{
    public static function createDeveloperName(array $nameArray)
    {
        // code goes here

        return $machineName;
    }

    public static function createActivityName(array $nameArray)
    {
        // other stuff...

        return $machineName;
    }
}


// MyBundle\Entity\Developer.php
class Developer
{
    public function setMachineName()
    {
        $nameArray = array(
            'firstName' => $this->getFirstName(),
            'lastName' => $this->getLastName(),
        );

        $machineName = MachineNames::createDeveloperName($nameArray);

        $this->setName($machineName);
    }
}

This function is called on prePersist with a lifecycle callback.

Any remarks? Is there a better way? How would you have done this?