6 Stimmen

Symfony2 und ParamConverter(s)

Zugang zu meiner Route /message/new Ich zeige ein Formular zum Senden einer neue Nachricht an einen oder mehrere Kunden . Form Modell hat (unter anderem) eine Sammlung von Customer Einheiten:

class MyFormModel
{
   /**
    * @var ArrayCollection
    */
    public $customers;
}

Ich würde gerne Folgendes umsetzen automatische Kundenauswahl mit customers GET-Parameter, etwa so:

message/new?customers=2,55,543

Dies funktioniert jetzt durch einfaches Splitten auf , und eine Abfrage zur Kundengewinnung durchführen:

public function newAction(Request $request)
{
    $formModel = new MyFormModel();

    // GET "customers" parameter
    $customersIds = explode($request->get('customers'), ',');

    // If something was found in "customers" parameter then get entities
    if(!empty($customersIds)) :

        $repo  = $this->getDoctrine()->getRepository('AcmeHelloBundle:Customer');
        $found = $repo->findAllByIdsArray($customersIds);

        // Assign found Customer entities
        $formModel->customers = $found;
    endif;

    // Go on showing the form
}

Wie kann ich das Gleiche mit Symfony 2 Konverter ? Zum Beispiel:

public function newAction(Request $request, $selectedCustomers)
{
}

13voto

gremo Punkte 48278

Antwort an mich selbst: Es gibt nichts, was einem das Leben leicht macht. Ich habe eine schnelle und schmutzige (und möglicherweise fehlerhafte) Lösung codiert, die ich gerne teilen möchte und warte auf die beste Lösung.

EDIT WARNUNG : Dies funktioniert nicht mit zwei Parameter-Konvertern der gleichen Klasse.

Url-Beispiel

/mesages/new?customers=2543,3321,445

Anmerkungen:

/**
 * @Route("/new")
 * @Method("GET|POST")
 * @ParamConverter("customers",
 *     class="Doctrine\Common\Collections\ArrayCollection", options={
 *         "finder"    = "getFindAllWithMobileByUserQueryBuilder",
 *         "entity"    = "Acme\HelloBundle\Entity\Customer",
 *         "field"     = "id",
 *         "delimiter" = ",",
 *     }
 * )
 */
public function newAction(Request $request, ArrayCollection $customers = null)
{
}

Option delimiter wird verwendet, um die GET Parameter während id wird zum Hinzufügen einer WHERE id IN... Klausel. Beide sind fakultativ.

Option class wird nur als "Signatur" verwendet, um zu sagen, dass der Konverter support es. entity muss ein FQCN einer Doctrine-Entität sein, während finder ist eine aufzurufende Repository-Methode, die einen Query Builder zurückgeben sollte (standardmäßig vorhanden).

Konverter

class ArrayCollectionConverter implements ParamConverterInterface
{
    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface
     */
    protected $container;

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

    function apply(Request $request, ConfigurationInterface $configuration)
    {
        $name    = $configuration->getName();
        $options = $this->getOptions($configuration);

        // Se request attribute to an empty collection (as default)
        $request->attributes->set($name, new ArrayCollection());

        // If request parameter is missing or empty then return
        if(is_null($val = $request->get($name)) || strlen(trim($val)) === 0)
            return;

        // If splitted values is an empty array then return
        if(!($items = preg_split('/\s*'.$options['delimiter'].'\s*/', $val,
            0, PREG_SPLIT_NO_EMPTY))) return;

        // Get the repository and logged user
        $repo = $this->getEntityManager()->getRepository($options['entity']);
        $user = $this->getSecurityContext->getToken()->getUser();

        if(!$finder = $options['finder']) :
            // Create a new default query builder with WHERE user_id clause
            $builder = $repo->createQueryBuilder('e');
            $builder->andWhere($builder->expr()->eq("e.user", $user->getId()));

            else :
                // Call finder method on repository
                $builder = $repo->$finder($user);
        endif;

        // Edit the builder and add WHERE IN $items clause
        $alias   = $builder->getRootAlias() . "." . $options['field'];
        $wherein = $builder->expr()->in($alias, $items);
        $result  = $builder->andwhere($wherein)->getQuery()->getResult();

        // Set request attribute and we're done
        $request->attributes->set($name, new ArrayCollection($result));
    }

    public function supports(ConfigurationInterface $configuration)
    {
        $class = $configuration->getClass();

        // Check if class is ArrayCollection from Doctrine
        if('Doctrine\Common\Collections\ArrayCollection' !== $class)
            return false;

        $options = $this->getOptions($configuration);
        $manager = $this->getEntityManager();

        // Check if $options['entity'] is actually a Dcontrine one
        try
        {
            $manager->getClassMetadata($options['entity']);
            return true;
        }
        catch(\Doctrine\ORM\Mapping\MappingException $e)
        {
            return false;
        }
    }

    protected function getOptions(ConfigurationInterface $configuration)
    {
        return array_replace(
            array(
                'entity'         => null,
                'finder'         => null,
                'field'          => 'id',
                'delimiter'      => ','

            ),
            $configuration->getOptions()
        );
    }

    /**
     * @return \Doctrine\ORM\EntityManager
     */
    protected function getEntityManager()
    {
        return $this->container->get('doctrine.orm.default_entity_manager');
    }

    /**
     * @return \Symfony\Component\Security\Core\SecurityContext
     */
    protected function getSecurityContext()
    {
        return $this->container->get('security.context');
    }
}

Definition der Dienstleistung

arraycollection_converter:
  class: Acme\HelloBundle\Request\ArrayCollectionConverter
  arguments: ['@service_container']
  tags:
    - { name: request.param_converter}

4voto

Oleg Andreyev Punkte 647

Es ist spät, aber laut neueste Dokumentation über @ParamConverter, können Sie es auf folgende Weise erreichen:

 * @ParamConverter("users", class="AcmeBlogBundle:User", options={
 *    "repository_method" = "findUsersByIds"
 * })

Sie müssen nur sicherstellen, dass die Repository-Methode kommagetrennte (,) Werte verarbeiten kann.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X