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:
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.
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.
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);
}
}
Declare it in Symofny's service container
<service id="..." class="...">
<!-- <argument ... /> -->
<tag name="doctrine.event_subscriber" />
</service>
You're done.
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?