Tag Archives: doctrine

Sonata e sortable

Chi avesse l’esigenza di gestire in Sonata un’entità con applicato il behaviour sortable di Doctrine2 si troverebbe con la sgradita sorpresa di non poter operare le comuni operazioni necessarie in questi casi: tipicamente, spostare le righe in su, in giù o in cima alla lista.
Purtroppo tale behaviour non offre alcun metodo che astragga le operazioni di cui sopra: l’unico modo per spostare un oggetto è quello di assegnargli una nuova posizione, dopo di che gli altri oggetti saranno riordinati di conseguenza.
Vediamo dunque come ottenere il risultato desiderato in Sonata. Per farlo, supponiamo di avere un’entità chiamata Article. Supponiamo inoltre che la proprietà che indica la posizione in tale entità si chiami $position.
Per prima cosa, dobbiamo creare un controllore che implementi le nostre nuove azioni di spostamento.

<?php
 
namespace Acme\MioBundle\Controller;
 
use Sonata\AdminBundle\Controller\CRUDController;
use Symfony\Component\HttpFoundation\RedirectResponse;
 
class ArticleAdminController extends CRUDController
{
    /**
     * Move element up
     *
     * @param integer $id
     */
    public function moveupAction($id)
    {
        $object = $this->admin->getObject($id);
        if ($object->getPosition() > 0) {
            $object->setPosition($object->getPosition() - 1);
            $this->admin->update($object);
        }
        if ($this->isXmlHttpRequest()) {
            return $this->renderJson(array(
                'result'    => 'ok',
                'objectId'  => $this->admin->getNormalizedIdentifier($object)
            ));
        }
        $this->get('session')->setFlash('sonata_flash_info', 'Elemento spostato in su.');
 
        return new RedirectResponse($this->admin->generateUrl('list', $this->admin->getFilterParameters()));
    }
 
    /**
     * Move element top
     *
     * @param integer $id
     */
    public function movetopAction($id)
    {
        $object = $this->admin->getObject($id);
        if ($object->getPosition() > 0) {
            $object->setPosition(0);
            $this->admin->update($object);
        }
        if ($this->isXmlHttpRequest()) {
            return $this->renderJson(array(
                'result'    => 'ok',
                'objectId'  => $this->admin->getNormalizedIdentifier($object)
            ));
        }
        $this->get('session')->setFlash('sonata_flash_info', 'Elemento spostato in cima.');
 
        return new RedirectResponse($this->admin->generateUrl('list', $this->admin->getFilterParameters()));
    }
}

Le uniche parti da adattare in questo controllore sono il namespace e il nome della classe.
Ora occorre dire a Sonata di usare questo controllore: possiamo farlo nel file di configurazione dei servizi (services.xml o services.yml), semplicemente sostituendo SonataAdminBundle:CRUD con AcmeMioBundle:ArticleAdmin nel terzo argument.
L’ultima parte da modificare è la classe ArticleAdmin.
Innanzitutto sarebbe logico che gli elementi siano ordinati in base alla posizione: aggiungiamo quindi la seguente proprietà:

 protected $datagridValues = array(
    '_page'       => 1,
    '_sort_order' => 'ASC',
    '_sort_by'    => 'position',
 );

Modifichiamo quindi il metodo configureListFields() in questo modo (ovviamente campi e azioni possono variare):

public function configureListFields(ListMapper $listMapper)
{
    $listMapper
        ->add('title')
        ->add('abstract')
        ->add('position')
        ->add('_action', 'actions', array(
            'actions' => array(
              'edit'    => array(),
              'view'    => array(),
              'delete'  => array(),
              'moveUp'  => array('template' => 'AcmeMioBundle:Article:_moveup.html.twig'),
              'moveTop' => array('template' => 'AcmeMioBundle:Article:_movetop.html.twig'),
            )
        ))
    ;
}

Infine non resta che creare i template:

{# Acme/MioBundle/Resources/view/Article/_moveup.html.twig #}
{% if object.position > 0 %}
    <a class="moveup_link" href="{{ path('admin_article_moveup', {id: object.id}) }}" title="Sposta su">↑</a>
{% endif %}
 
{# Acme/MioBundle/Resources/view/Article/_movetop.html.twig #}
{% if object.position > 1 %}
    <a class="movetop_link" href="{{ path('admin_article_movetop', {id: object.id}) }}" title="Sposta in cima">↑↑</a>
{% endif %}

Purtroppo non ho potuto implementare lo spostamento in giù, non avendo ancora trovato il modo di verificare che la posizione non sia già l’ultima.

Utilizzare le Estensioni di Doctrine in progetti symfony2

Doctrine prevede un set di eventi che permettono di modificarne ed estenderne il comportamento. Tramite l’utilizzo di questi eventi è possibile implementare nuove funzionalità non previste dall’ ORM. Sfruttando questa potenzialità è stato creato un set di estensioni per mettere a disposizione degli sviluppatori alcuni comportamenti di uso comune. L’integrazione all’interno di symfony2 è facilitata dal bundle StofDoctrineExtensionsBundle.

Continue reading

Un anno senza ORM?

G9NGBH9YK85S
Se seguite questa discussione sul gruppo di Symfony su Linkedin avrete notato che è emersa una notizia abbastanza interessante.

The Doctrine 1.2 support seems to be extended to June, 1st 2011. But this post was written 11 months ago and I think the end of support was shortened…

Che affiancata al fatto che il supporto ufficiale a Symfony 1.x finirà il 31 dicembre 2012, fa evidenziare come per circa 1 anno e mezzo nessun ORM sarà ufficialmente supportato dal framework.

Che sia arrivato il tempo, per i progetti basati su symfony 1.x, di dare di nuovo un occhio a Propel?

test complessi con sfTesterDoctrine

A volte può capitare di dover testare delle condizioni complesse su un oggetto Doctrine. In questi casi, il semplice array solitamente usato col metodo check() può non bastare. Per esempio mi è capitato recentemente di dover testare alcuni campi data con una condizione >= (maggiore o uguale).
Ma lo stesso metodo check() è abbastanza flessibile da accettare come secondo parametro non solo un array, ma anche un oggetto Doctrine_Query. Basterà quindi costruire le condizioni in questo modo e passarle, e il gioco è fatto.