2010-11-18 6 views
2

Der Kunde muss die Reihenfolge der Artikel ändern, wie er will, was bedeutet, ich brauche einige "Reihenfolge" oder "Sequenz" -Spalte, um die tatsächliche Position jedes Artikels zu speichern.Doctrine 2 Sortierbar

Wie kann ich dies mit Doctrine 2 implementieren?

+0

haben Sie es geschafft, eine Lösung zu finden? Ich bin jetzt auf der Suche nach und fragte mich, was Sie am Ende benutzt haben? – DavidW

Antwort

0

weiteren hinzufügen Spalte:

 
    sort_order: 
     type: integer(4) 
     default: 10 

nun, dass der Eintritt von 10 bis etwas zu ändern sonst bewegt er sich in der Ergebnismenge, die durch etwas abgerufen werden würde wie:

 
$this->result = Doctrine_Core::getTable('CustomerTable') 
    ->createQuery('a')->orderBy("a.sort_order asc, a.id desc")->execute(); 
+0

Nein. Nicht was ich meinte. Ich habe die Reihenfolge wie 1, 2, 3, 4, 5. Jetzt bewegt Benutzer (per Drag & Drop) Element 2 zum Beispiel auf Position 4, also muss ich Änderungen wie folgt vornehmen: 2-> 4, 3-> 2, 4-> 3 – enumag

+0

Sie benötigen noch eine Sortierspalte, um diese Bestellung zu speichern. Ich würde die Sortierspalte so einstellen, dass sie die Primärschlüssel-ID als Standard hat und später die Sortierspaltenwerte tauscht, wenn Sie sie ziehen. – dsomnus

+0

Natürlich, aber wie Sie diese Änderungen automatisch tun? Ideal wäre es, einfach $ entity-> order = 5; $ em-> flush(); und die anderen Entitäten sollten sich automatisch ändern. – enumag

0

Sie automatisch Sammlungen abrufen können bestellt von einem bestimmten Feld:

http://www.doctrine-project.org/projects/orm/2.0/docs/reference/association-mapping/en#ordering-to-many-collections

So können Sie den Auftrag über die Spalte "sort_order" definieren. Dann benötigen Sie einige Methoden, um die Sortierspalten aus Performancegründen mit Hilfe von DQL-Update-Anweisungen korrekt zu aktualisieren, d. H. "MoveTo ($ pos, $ entity)" und die entsprechende Anzahl an Updates zu veröffentlichen.

Aber das löst die Hälfte Ihres Problems, wenn Sie die Sammlung in derselben Anfrage wiederholen müssen, in der die Reihenfolge geändert wird. Dies ist jedoch selten ein Anwendungsfall, so dass es oft ignoriert werden kann.

+0

Ich weiß, ich benutze die "sort_order" -Spalte, wie du sagst, aber es wäre schön, diese Update-Methoden nicht zu schreiben und sie mit etwas Doktrin-Verhalten zu automatisieren. – enumag

3

Ich würde es mit Doctrine event system implementieren. Um Verhaltensweisen hinzuzufügen, schreibe ich normalerweise einen Ereignisteilnehmer und erzwinge die Regeln mit einer Schnittstelle, die von meinen Entitätsklassen implementiert wird. Die eigentliche Logik, die ich irgendwo in einem Serviceobjekt aufbewahre (du bist dafür alleine).

use Doctrine\Common\EventSubscriber, 
    Doctrine\ORM\Events, 
    Doctrine\ORM\Event\LifecycleEventArgs, 
    Doctrine\ORM\Event\PreUpdateEventArgs; 


class SortableBehavior implements EventSubscriber 
{ 
    public function getSubscribedEvents() 
    { 
     return array(Events::prePersist, Events::preUpdate); 
    } 

    public function prePersist(LifeCycleEventsArgs $args) 
    { 
    // the entity being persisted 
    $entity = $args->getEntity(); 
    if ($entity instanceof SortableInterface) { 
     //perform sorting magic 
    } 
    } 

    public function preUpdate(preUpdateEventsArgs $args) 
    { 
    // the entity being updated 
    $entity = $args->getEntity(); 
    if ($entity instanceof SortableInterface) { 
     //perform sorting magic 
    } 
    } 
} 

Vergessen Sie nicht, die Teilnehmer zu registrieren, wenn Sie Ihre App Bootstrapping:

$eventManager = $entityManager->getEventManager(); 
$eventManager->addEventSubscriber(new SortableBehavior()); 
+0

Also die Sortierung Magie ist das Repository zu bekommen, dann alle anderen Entitäten und inkrementieren (oder dekrementieren) den Wert sort_order für einige von ihnen? Was ist mit Leistung? Ich müsste alle Entitäten wieder laden und speichern. Ohne Doctrine könnte ich einzelne UPDATE-SQL-Abfragen verwenden. – enumag

+0

Wenn Sie den UPDATE-Abfrageansatz verwenden möchten, können Sie das NativeQuery-Objekt von D2 verwenden. Als ORM würde der Standardansatz von Doctrine darin bestehen, mit Ihren Entitäten zu arbeiten, was bedeutet, dass sie zuerst von der Datenbank abgerufen werden müssen. Die Leistung könnte verbessert werden, indem die verschiedenen von Doctrine bereitgestellten Caches verwendet werden. –

0

ich mit dem EventSubscriber einige Tests haben könnte, aber es nicht richtig zu arbeiten, so habe ich beschlossen, nur direkt über das Hinzufügen der Code zu meiner Klasse (q & d). Ich benutze Zend Framework, also ändere das Holen des Entity Managers, wenn du eine andere Lösung hast.

Es funktioniert wie folgt:

  1. Wenn das Unternehmen die GetLast verwenden Erstellen von() und fügen Sie die neue Einheit letzte ($ last_entity-> getSort() + 1)
  2. Fügen Sie die SortUp und sortDown Funktionen und ihre Subroutinen auf die Entität Code
  3. Add „sort ASC“ in allen DQL-Abfragen, wo Sie es

Das Unternehmen Code sortiert werden sollen, wie folgt:

/** 
* Searches for the element above and switches them 
* with eachother. Performs a EntityManager::flush() 
* to save the results after the switch. 
*/ 
public function sortUp() { 

    try { 
     $em = \Zend_Registry::get("entitymanager"); 

     $class_name = get_class($this); 
     $dql = "SELECT ut FROM $class_name ut WHERE ut.inactive IS NULL AND ut.inactive IS NULL AND ut.sort < '" . $this->getSort() . "' ORDER BY ut.sort DESC"; 
     $query = $em->createQuery($dql); 
     $query->setMaxResults(1); 
     $ut = $query->getResult(); 
    } catch (Exception $exc) { 
     throw new Exception("Error when looking for sortable partner: " . $exc->getMessage()); 
    } 

    if (count($ut)) { 
     $this->_switchSortAndSave($ut[0]); 
    } 
} 

/** 
* Searches for the element below and switches them 
* with eachother. Performs a EntityManager::flush() 
* to save the results after the switch. 
*/ 
public function sortDown() { 
    try { 
     $em = \Zend_Registry::get("entitymanager"); 

     $class_name = get_class($this); 
     $dql = "SELECT ut FROM $class_name ut WHERE ut.inactive IS NULL AND ut.sort > '" . $this->getSort() . "' ORDER BY ut.sort ASC"; 
     $query = $em->createQuery($dql); 
     $query->setMaxResults(1); 
     $ut = $query->getResult(); 
    } catch (Exception $exc) { 
     throw new Exception("Error when looking for sortable partner: " . $exc->getMessage()); 
    } 


    if (count($ut)) { 
     $this->_switchSortAndSave($ut[0]); 
    } 
} 

private function _switchSortAndSave(\Entities\Usertype $switch_entity) { 
    $new_sort = $switch_entity->getSort(); 
    $switch_entity->setSort($this->getSort()); 
    $this->setSort($new_sort); 

    $em = \Zend_Registry::get("entitymanager"); 
    $em->persist($switch_entity); 
    $em->persist($this); 
    $em->flush(); 
} 

/** 
* Looks for the last entry according to sort order 
* and returns that if found. 
* 
* @return Entity|null 
*/ 
public static function findLast() { 
    try { 
     $em = \Zend_Registry::get("entitymanager"); 

     $class_name = get_called_class(); 
     $dql = "SELECT ut FROM $class_name ut ORDER BY ut.sort DESC"; 
     $query = $em->createQuery($dql); 
     $query->setMaxResults(1); 
     $ut = $query->getResult(); 
    } catch (Exception $exc) { 
     throw new Exception("Error when searching for last $class_name: " . $exc->getMessage()); 
    } 

    if (count($ut)) 
     return $ut[0]; 
    else 
     return null; 
} 

ich mit dieser Lösung nicht so zufrieden bin so, wenn jemand mit einem schönen Sortable für Lehre 2 bitte teilen :)