Skip to content
This issue has been moved to a discussionGo to the discussion

How to override default ordering with an order filter #2690

Closed
@tezvi

Description

@tezvi

Hi everyone!

I've added default ordering to resource attributes (yaml). So far so good.
However, the default order is still applied when querying the collection with an explicit order filter (query param).

The query builder used by data provider orders by default and by order filter.

Is there a way to ditch default order when order filter has been activated?

Also is it possible to define default order at operation level?

Activity

teohhanhui

teohhanhui commented on Apr 5, 2019

@teohhanhui
Contributor

The default order is used to ensure a stable ordering of items, as otherwise the order is undefined as per the SQL standard. I don't see any case where you should have a need to remove the default order when using custom ordering.

teohhanhui

teohhanhui commented on Apr 5, 2019

@teohhanhui
Contributor

Also is it possible to define default order at operation level?

It does not seem to be supported at this time: https://github.com/api-platform/core/blob/v2.4.2/src/Bridge/Doctrine/Orm/Extension/OrderExtension.php#L54

But indeed we could. Actually we shouldn't, as it makes no sense.

tezvi

tezvi commented on Apr 5, 2019

@tezvi
Author

The default order is used to ensure a stable ordering of items, as otherwise the order is undefined as per the SQL standard. I don't see any case where you should have a need to remove the default order when using custom ordering.

Let me put it this way. The user should be able to order collection by using a specific order filter. If no filter is used the collection should be ordered by default order.
It seems I cannot recreate that with the current implementation.

teohhanhui

teohhanhui commented on Apr 5, 2019

@teohhanhui
Contributor

The user should be able to order collection by using a specific order filter. If no filter is used the collection should be ordered by default order.

Sorry, I don't understand. The default order is exactly what that's for? I've already explained above why the default order is always added to the end. You should choose something that is definitely able to order items to avoid running into undefined ordering.

To give you an example, if the user chooses to order by name, what happens when 2 items have the same name? That's the job of the default order (say, order by id), to make sure that the order is deterministic.

teohhanhui

teohhanhui commented on Apr 5, 2019

@teohhanhui
Contributor

In fact, the default order is not used by the OrderFilter (which is applied by the FilterExtension), but by the OrderExtension. Perhaps that's the source of your confusion. It should probably be renamed the DefaultOrderExtension (default_order in metadata attributes). 😄

teohhanhui

teohhanhui commented on Apr 5, 2019

@teohhanhui
Contributor

It should probably be renamed the DefaultOrderExtension (default_order in metadata attributes).

Keeping open for this.

tezvi

tezvi commented on Apr 5, 2019

@tezvi
Author

Hi teohhanhui,

thanks for your input and clarification. I understand the difference between OrderExtension and FilterExtension. However, I'm not really sure if we have an understanding. Let's assume we have a simple entity, just for the sake of example.

/**
 * @ORM\Table(name="bar")
 * @ORM\Entity
 */
class Bar
{
     /**
     * @var integer
     *
     * @ORM\Id
     * @ORM\Column(name="id", type="integer")
     */
    private $id;

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

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

    /**
     * @var string
     *
     * @ORM\Column(name="description", type="string", length=100)
     */
    private $description;
}

ApiPlatform resource definition:

Bar:
    collectionOperations:
        get:
            path: '/api/bars'
            filters:
                - 'api_filter.bar.order'
    itemOperations:
        get:
            path: '/api/bars/{id}'
    attributes:
        order:
            code: asc
            id: desc

Filter service

api_filter.bar.order:
    parent: api_platform.doctrine.orm.order_filter
    arguments:
       properties: 
          id: ~
          code: ~
          name: ~
          description: ~

when querying /api/bars API endpoint the api_platform data provider would generate something like this (approximation, writing from top of my head)

SELECT * FROM bars ORDER BY code ASC, id DESC

When querying /api/bars?order[name]=asc&order[description]=desc the query would look like this (not really sure about order of ORDER clause identifiers):

SELECT * FROM bars ORDER BY code ASC, id DESC, name ASC, description DESC
or
SELECT * FROM bars ORDER BY name ASC, description DESC, code ASC, id DESC

Either way, default order is unnecessary applied. For huge tables this would present an overhead at database level and eventually wrong ordering.

Sorry if I make this unnecessary difficult or if I don't see a solution out-of-the-box.

A potential solution that does not touch any api-platform implementation is to decorate OrderExtension and detect if order filter is being activated, before or after the OrderFilter is processed.

tezvi

tezvi commented on May 20, 2019

@tezvi
Author

If anyone stumbles upon the same problem this gist has the solution mentioned in previous post.
https://gist.github.com/tezvi/d0974664a423a3052518bfb47bac672c

8 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @dunglas@teohhanhui@wibimaster@shehi@soyuka

        Issue actions

          How to override default ordering with an order filter · Issue #2690 · api-platform/core