Pagination changes in v4

Hello all,

I already discussed this issue a bit in the Discord server, but I'm still stuck so sorry to repeat myself.

Indeed migrating to v4 has at least one side-effect not (yet) mentionned in the upgrade documentation, which is that pagination now works in a completely backwards-incompatible way.

I use Volt to force myself to stick to MVC principles by not letting me introduce too much code in the view, so for most columns I used pagination in this way in v3 (simplified example):

{% if page.items is defined %}
    {% for place in page.items %}
    <tr>
        <td>{{ place.getPlaceId() }}</td>
        <td>...</td>
        ...
    </tr>
    {% endfor %}
{% endif %}

But "items" is now an array, so the following code is the v4-compliant one:

{% if page.items | length %}
    {% for place in page.items %}
    <tr>
        <td>{{ place['placeId'] }}</td>
        <td>...</td>
        ...
    </tr>
    {% endfor %}
{% endif %}

Which is good and all... but for the cases where we used objects in Volt from the paginator, how are we supposed to migrate?

Indeed in v3, even if I rarely used the getters to change values on the fly (but others may still use them that way), I did "model jumps" to quickly resolve simple DB relationships, based on the scaffolds from devtools.

For instance, here where "Currencies" is a relationship alias in the Country model, to get the name of a currency from the related table by its ID in the country table I previously did:

{% for country in page.items %}
    <tr>
        <td>{{ country.getCurrencies().currencyShort }}</td>
        <td>...</td>
        ...
    </tr>
{% endfor %}

(I couldn't chain "jumps" to go further than that, but I accepted this limitation given that what I was doing already felt quite hackish)

Is there a way to get the previous behavior back, or a new clean way to do this that I missed?

Or should every pagination query reaching other models now be converted to PHQL in the controllers to feed to a Paginator\Adapter\NativeArray?

If so then it would add quite a lot of code overall in my admin pages given my 73 interconnected tables (...yeah I know), but well...

I wonder if this isn't just an oversight as devtools still references the previous behavior by calling the getters of the now removed object when the getter option is selected:

https://github.com/phalcon/phalcon-devtools/blob/v4.0.1/src/Builder/Component/Scaffold.php#L726

Indeed as hinted to me on Discord the change has been made in Paginator/Adapter/Model.zep around this part:

v3: https://github.com/phalcon/cphalcon/blob/3.4.x/phalcon/paginator/adapter/model.zep#L92

v4: https://github.com/phalcon/cphalcon/blob/master/phalcon/Paginator/Adapter/Model.zep#L125

It has been suggested that I "create [my] own zephir/php adapter extension" to get the previous behavior back, but is it really the only option?

Maybe the previous behavior ("including objects in the pagination") has just been forgotten during the refactoring?

edited Jan '20

I think the rationale behind all this, was that the pagination component was not really extensible. It was good for quick&dirty displays, but other than that, you would've written your own logic anyway, considering caching and whatnot.

There were also cases where the SQL engine blocked successive requests until the cursor finished scrolling through the results, and in that case, you can't query relations for the item model instance. I think the devs went with the least common-denominator, and made it more robust this way, at the cost of that meager extensibility.

You are better off writing your own logic, that is streamlined for your application and environment.