DDC-293: Patch for "orderBy" attribute for @ManyToMany #367

Closed
opened 2026-01-22 12:36:09 +01:00 by admin · 6 comments
Owner

Originally created by @doctrinebot on GitHub (Jan 31, 2010).

Originally assigned to: @beberlei on GitHub.

Jira issue originally created by user @beberlei:

There are lots of scenarios where a many to many collection has semantics in regard to the order of the entities. Here is a prove of concept patch that implementing an attribute "orderBy" for the ManyToMany annotation. The same can be implemented for OneToMany using the same pattern easily. Here are some excerpts from the test-case:

class RoutingRoute
{
    /****
     * @Id
     * @generatedValue(strategy="AUTO")
     * @column(type="integer")
     */
    public $id;

    /****
     * @ManyToMany(targetEntity="Doctrine\Tests\Models\Routing\RoutingLeg", cascade={"all"}, orderBy="departureDate ASC")
     * @JoinTable(name="RoutingRouteLegs",
     *     joinColumns={@JoinColumn(name="route_id", referencedColumnName="id")},
     *     inverseJoinColumns={@JoinColumn(name="leg_id", referencedColumnName="id", unique=true)}
     * )
     */
    public $legs;
    public function testOrderedCollection()
    {
        $route = new RoutingRoute();

        $leg1 = new RoutingLeg();
        $leg1->fromLocation = $this->locations['Berlin'];
        $leg1->toLocation   = $this->locations['Bonn'];
        $leg1->departureDate = new \DateTime("now");
        $leg1->arrivalDate = new \DateTime("now <ins>5 hours");

        $leg2 = new RoutingLeg();
        $leg2->fromLocation = $this->locations['Bonn'];
        $leg2->toLocation   = $this->locations['Brasilia'];
        $leg2->departureDate = new \DateTime("now </ins>6 hours");
        $leg2->arrivalDate = new \DateTime("now +24 hours");

        $route->legs[] = $leg2;
        $route->legs[] = $leg1;

        $this->_em->persist($route);
        $this->_em->flush();
        $routeId = $route->id;
        $this->_em->clear();

        $route = $this->_em->find('Doctrine\Tests\Models\Routing\RoutingRoute', $routeId);

        $this->assertEquals(2, count($route->legs));
        $this->assertEquals("Berlin", $route->legs[0]->fromLocation->getName());
        $this->assertEquals("Bonn", $route->legs[1]->fromLocation->getName());
    }
Originally created by @doctrinebot on GitHub (Jan 31, 2010). Originally assigned to: @beberlei on GitHub. Jira issue originally created by user @beberlei: There are lots of scenarios where a many to many collection has semantics in regard to the order of the entities. Here is a prove of concept patch that implementing an attribute "orderBy" for the ManyToMany annotation. The same can be implemented for OneToMany using the same pattern easily. Here are some excerpts from the test-case: ``` class RoutingRoute { /**** * @Id * @generatedValue(strategy="AUTO") * @column(type="integer") */ public $id; /**** * @ManyToMany(targetEntity="Doctrine\Tests\Models\Routing\RoutingLeg", cascade={"all"}, orderBy="departureDate ASC") * @JoinTable(name="RoutingRouteLegs", * joinColumns={@JoinColumn(name="route_id", referencedColumnName="id")}, * inverseJoinColumns={@JoinColumn(name="leg_id", referencedColumnName="id", unique=true)} * ) */ public $legs; ``` ``` public function testOrderedCollection() { $route = new RoutingRoute(); $leg1 = new RoutingLeg(); $leg1->fromLocation = $this->locations['Berlin']; $leg1->toLocation = $this->locations['Bonn']; $leg1->departureDate = new \DateTime("now"); $leg1->arrivalDate = new \DateTime("now <ins>5 hours"); $leg2 = new RoutingLeg(); $leg2->fromLocation = $this->locations['Bonn']; $leg2->toLocation = $this->locations['Brasilia']; $leg2->departureDate = new \DateTime("now </ins>6 hours"); $leg2->arrivalDate = new \DateTime("now +24 hours"); $route->legs[] = $leg2; $route->legs[] = $leg1; $this->_em->persist($route); $this->_em->flush(); $routeId = $route->id; $this->_em->clear(); $route = $this->_em->find('Doctrine\Tests\Models\Routing\RoutingRoute', $routeId); $this->assertEquals(2, count($route->legs)); $this->assertEquals("Berlin", $route->legs[0]->fromLocation->getName()); $this->assertEquals("Bonn", $route->legs[1]->fromLocation->getName()); } ```
admin closed this issue 2026-01-22 12:36:10 +01:00
Author
Owner

@doctrinebot commented on GitHub (Jan 31, 2010):

@doctrinebot commented on GitHub (Jan 31, 2010): - is referenced by [DDC-195: Ordering of associations](http://www.doctrine-project.org/jira/browse/DDC-195)
Author
Owner

@doctrinebot commented on GitHub (Feb 14, 2010):

Comment created by @beberlei:

Discussion in IRC had the following results:

  • Snippet should be SQL to allow for more flexibility
  • Snippet should always be appended to any existing Order By statements, thereby only affecting the emitation of the collection elemets and not any previously requested order
  • If the DQL revereses the order previously this should be overwritten, very simple:
1. @orderBy("b.start*year ASC, b.end*year DESC")
2. SELECT a, b FROM a JOIN b ORDER BY b.startYear DESC
1+2 => ORDER BY b.start*year DESC, b.start_year ASC, b.end*year DESC
@doctrinebot commented on GitHub (Feb 14, 2010): Comment created by @beberlei: Discussion in IRC had the following results: - Snippet should be SQL to allow for more flexibility - Snippet should always be appended to any existing Order By statements, thereby only affecting the emitation of the collection elemets and not any previously requested order - If the DQL revereses the order previously this should be overwritten, very simple: ``` 1. @orderBy("b.start*year ASC, b.end*year DESC") 2. SELECT a, b FROM a JOIN b ORDER BY b.startYear DESC 1+2 => ORDER BY b.start*year DESC, b.start_year ASC, b.end*year DESC ```
Author
Owner

@doctrinebot commented on GitHub (Feb 14, 2010):

Comment created by @beberlei:

Implementation Details:

  • The Table alias is set by replacing a magic %alias% string. This is ugly but the most simple solution. The next viable solution would mean implementing a parser for SQL, which is too complex.
  • In SqlWalker::walkJoinVariableDeclaration() - If an ordered collection valued association is joined that is also present in $_selectedClasses (i.e. fetch joined) set a flag in a new array $_orderCollections for this dql alias => sql snippet (Replace %alias% with the table alias of the fetch joined colleciton)
  • In SqlWalker::walkOrderByClause - After the user defined ORDER BY Items, loop over the order collections and append the appropriate sql snippets to the already generated ORDER BY stuff

Question now:

How do i add an AST\OrderBy node if none is requested in the DQL?

Or should we just always add an OrderBy node to the AST?

@doctrinebot commented on GitHub (Feb 14, 2010): Comment created by @beberlei: Implementation Details: - The Table alias is set by replacing a magic %alias% string. This is ugly but the most simple solution. The next viable solution would mean implementing a parser for SQL, which is too complex. - In SqlWalker::walkJoinVariableDeclaration() - If an ordered collection valued association is joined that is also present in $_selectedClasses (i.e. fetch joined) set a flag in a new array $_orderCollections for this dql alias => sql snippet (Replace %alias% with the table alias of the fetch joined colleciton) - In SqlWalker::walkOrderByClause - After the user defined ORDER BY Items, loop over the order collections and append the appropriate sql snippets to the already generated ORDER BY stuff Question now: How do i add an AST\OrderBy node if none is requested in the DQL? Or should we just always add an OrderBy node to the AST?
Author
Owner

@doctrinebot commented on GitHub (Feb 14, 2010):

Comment created by @beberlei:

I'll close this one and attach some more prominent parts of this feature as sub-tasks to the parent issue.

@doctrinebot commented on GitHub (Feb 14, 2010): Comment created by @beberlei: I'll close this one and attach some more prominent parts of this feature as sub-tasks to the parent issue.
Author
Owner

@doctrinebot commented on GitHub (Feb 14, 2010):

Issue was closed with resolution "Invalid"

@doctrinebot commented on GitHub (Feb 14, 2010): Issue was closed with resolution "Invalid"
Author
Owner

@doctrinebot commented on GitHub (Dec 13, 2015):

Imported 1 attachments from Jira into https://gist.github.com/cd2b8be2e7cef0ac53bb

@doctrinebot commented on GitHub (Dec 13, 2015): Imported 1 attachments from Jira into https://gist.github.com/cd2b8be2e7cef0ac53bb - [10335_manytomany_orderby.patch](https://gist.github.com/cd2b8be2e7cef0ac53bb#file-10335_manytomany_orderby-patch)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#367