phpsymfonydesign-patternsdoctrine-ormentitymanager

How to have a model Manager in Symfony2?


Sorry if this question has already been answered, I couldn't find any.

I'm building this model in Symfony2:

class LogEntry {
    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var \DateTime $log_timestamp
     *
     * @ORM\Column(name="log_timestamp", type="datetime")
     */
    private $log_timestamp;

    /**
     * @var TranslationMapping $source
     *
     * @ORM\ManyToOne(targetEntity="TranslationMapping", cascade={"persist"})
     * @ORM\JoinColumn(name="source", referencedColumnName="id")
     */
    private $source;

    /**
     * @var TranslationMapping $target
     *
     * @ORM\ManyToOne(targetEntity="TranslationMapping", cascade={"persist"})
     * @ORM\JoinColumn(name="target", referencedColumnName="id")
     */
    private $target;
...
}

With TranslationMapping like this :

/**
 * LogAnalyzer\Bundle\CombatLogBundle\Entity\TranslationMapping
 *
 * @ORM\Table(name="TranslationMapping", uniqueConstraints={@ORM\UniqueConstraint(name="idValue_idx", columns={"stringId", "stringValue"})})
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks()
 */
class TranslationMapping
{
    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string $stringId
     *
     * @ORM\Column(name="stringId", type="string", length=255)
     */
    private $stringId;

    /**
     * @var string $stringValue
     *
     * @ORM\Column(name="stringValue", type="string", length=255)
     */
    private $stringValue;


    /**
     * @ORM\PrePersist
     */
    public function beforePersist()
    {
        if ($this->stringId == null) {
            $this->stringId = "laGen_".time();
        }
    }

LogEntry is built based on a string parsed through regex. TranslationMapping represent a key/value stored translation string.

Currently what I'm doing is :

  1. Retrieving the string to build the LogEntry
  2. Building the LogEntry from the string in the LogEntryRepository

    $logEntry = new LogEntry();
    $source = new TranslationMapping();
    if ($logEntry->getSourceIsPlayer()) {
        $source->setValueKey(str_replace("@", "", $matches["source"][0]));
    } else {
        $source->setValueKey($matches["source"][0], $matches["source_id"][0]);
        if (isset($matches["source_companion_name"][0])) { // It's a companion !
            $companion = new TranslationMapping();
            $companion->setValueKey($matches["source_companion_name"][0], $matches["source_companion_id"][0]);
            $logEntry->setSourceCompanion($companion);
            $source->setValueKey(str_replace("@", "", $matches["source"][0])); // And the source is the player's character name
        }
    }
    $logEntry->setSource($source);
    $logEntry->setTargetIsPlayer(strpos($matches["target"][0], "@") !== false);
    $target = new TranslationMapping();
    if ($logEntry->getTargetIsPlayer()) {
        $target->setValueKey(str_replace("@", "", $matches["target"][0]));
    } else {
        $target->setValueKey($matches["target"][0], $matches["target_id"][0]);
        if (isset($matches["target_companion_name"][0])) { // It's a companion !
            $companion = new TranslationMapping();
            $companion->setValueKey($matches["target_companion_name"][0], $matches["target_companion_id"][0]);
            $logEntry->setTargetCompanion($companion);
            $target->setValueKey(str_replace("@", "", $matches["target"][0])); // And the target is the player's character name
        }
    }
    $logEntry->setTarget($target);
    
  3. Displaying the LogEntry

My issue is that I want to create a translation mapping entity if the key/value pair is non-existent yet. However, I don't see how I can do that since :

Basically what I'm trying to do is to get a Manager for my TranslationMapping entities, which would manage DB operations (fetch & insert if needed) and expose the entities through all the Symfony application, and mostly to the Repositories.

I've tried several solutions and ran out of options, does anyone have a clue of how I can achieve this ?

Thanks.


Solution

  • Basically, you want to create a S2 service and inject your entity manager into it. Plenty of examples in the manual though I could post one if you really needed it.

    Repositories are great when dealing with one entity type but, as you found out, not so much when dealing with multiple types. I seldom them use them anymore. Just wrap up the functionality in a service.

    The INSERT ... ON DUPLICATE KEY UPDATE is unfortunately not standard sql and thus not supported by Doctrine though you could possible add it as a custom function. But your best bet is to just check to see if the key exists and then adjust accordingly. Be sure to catch any exceptions just in case.

    I didn't really go through your code in any detail but S2 does have a bunch of translation stuff in it. It's possible that some of it may help as well.

    UPDATE:

    Info on creating services can be found here: http://symfony.com/doc/current/book/service_container.html

    In your services.xml file you might have something like:

    <service 
        id="zayso.core.project.manager"        
        class="Zayso\ZaysoBundle\Component\Manager\ProjectManager" public="true">
            <argument type="service" id="doctrine.orm.entity_manager" />
    </service>
    

    You manager would have a __construct like:

    class ProjectManager
    {
        protected $em = null;
    
        public function getEntityManager() { return $this->em; }
    
        public function __construct($em) { $this->em = $em; }
    

    And then in your controller you would do something like:

    $manager = $this->get(zayso.core.project.manager);
    $manager->newLogEntry($params);