I know that a lot of code that is currently in Magento 2 (2.1.2) is more or less ported from Magento 1 and that a lot of code will be substituted by an equivalent in the future. In this aspect, I'm wondering what's the future of collections in Magento 2.

Let me explain:

Magento 1:

In Magento 1 we are used to get a collection like this:

$products = Mage::getModel('catalog/product')->getCollection();

We could then apply filters and other operations to the collection:

$products->addAttributeToFilter('price', ['gteq' => 10]);
$products->addFieldToFilter('created_at', ['lt' => '2016-10-10']);
$products->setPageSize(10);
// ... etc ...

And last but not least, our collection would return the models:

foreach ($products as $product) {
    echo get_class($product); // Mage_Catalog_Model_Product
}

Magento 2:

Magento adds a lot of new layers of abstraction, implementing a more SOLID way of working. This means that when we want a list of entities, we ask it from a repository:

$productResults = $this->productRepository->getList($searchCriteria);

If we want to apply filters we use a combination of the SearchCriteriaBuilder, the FilterGroupBuilder, the FilterBuilder and the SortOrderBuilder:

$this->searchCriteriaBuilder->addSortOrder(
    $this->sortOrderBuilder
        ->setField('created_at')
        ->setAscendingDirection()
        ->create()
);
$priceFilter = $this->filterBuilder
    ->setField('price')
    ->setValue(10)
    ->setConditionType('gteq')
    ->create();
$createdAtFilter = $this->filterBuilder
    ->setField('created_at')
    ->setValue('2016-10-10')
    ->setConditionType('lt')
    ->create();
$filterGroups = [
    $this->filterGroupBuilder->addFilter($priceFilter)->create(),
    $this->filterGroupBuilder->addFilter($createdAtFilter)->create()
];

And if we want to iterate over our results, we get Data Models, not actual (inherited) models:

foreach ($productResults->getItems() as $product) {
    echo get_class($product); // \Magento\Catalog\Model\Data\Product
}

This kind of abstraction follows the SOLID principle and embraces the 'composition over inheritance'-principle. Any 'exotic' operations that would be otherwise done on the collection (like joins for examples) are done internaly in the repository, which makes it also easier to use outside of the module.

The question:

All of this makes me wonder: with the whole repository / data model-approach, is there any room in the future of Magento 2 for collections? Are collections only to be used internally by the module itself and not outside of it? Or are the going to be deprecated in favour of the Entity Manager?

Currently, if you want to embrace Data Models, you still have to create an inherited model (inherited from \Magento\Framework\Model\AbstractModel) just to get the collection working (since Magento\Framework\Data\Collection::setItemObjectClass requires the model to extend from Magento\Framework\DataObject). And you need to collection to be able to filter in your repository. But then again, in the repository you have to 'convert' your (regular) Model to a Data Model.

Or do we have to implement it like the Order Repository, where the getList() returns an instance of Magento\Sales\Api\Data\OrderSearchResultInterface, but under water the search results are nothing more than a regular collection that implements this interface. Fun fact: the search results states it will return an array of Data Models (Magento\Sales\Api\Data\OrderInterface[]), but if you analyze the code, getItems() will execute Magento\Framework\Data\Collection::getItems() which in return returns not the data models, but the order models (as set by Magento\Sales\Model\ResourceModel\Order\Collection::_construct()). So much for 'composition over inheritance'.

A lot of questions on what's the proper way in Magento 2. Again, there are 100 ways of doing the same thing, but what is 'The Magento Way'? Or am I just totally on the wrong track here?

  • 2
    Asking the real questions here +1. I would really love a core dev answer here – Marius Dec 16 '16 at 8:19
  • I believe the plan is for Collections to be phased out. However as you noticed this is not nearly even close to being accomplished and there are lots of areas which seem to be in various states of being refactored (having the stable api as Magento\Sales\Api\Data\OrderSearchResultInterface, allows Magento to replace what happens under the hood more easily later on). It doesn't help that the various implementations of getList aren't yet as capable as what we can currently do with collections. The inconsistency you noted around stated return might be worthy for an issue on github. – Kristof at Fooman Dec 16 '16 at 8:38
up vote 14 down vote accepted

Collections are not deprecated now. While some modules already expose Service Contract APIs, others still expose only Model/Collection APIs.

The plan is:

  1. Reflect current state with better @api coverage: annotate abstract collections and specific collections in some modules with @api
  2. Improve persistence framework to allow for easy creation of Service Contracts without reliance on inheritance-based APIs: Collections, Models, Resource models
  3. Deprecate Abstract Collection to not promote collection-based implementations of Service Contracts
  4. Gradually release newer versions of modules with Service Contract APIs

So collections will be deprecated at some point, but now they are one of Magento 2 APIs.

As for implementation of Service Contracts, - Models and Collections are the only convenient way to implement them in Magento <= 2.1. Service Contracts are just Interfaces. Their implementation is not part of public API and may be changed later.

  • 1
    Thanks for your answer. So what's your advice for developers who create new modules? My current strategy is to create service contracts that (under water) still use collections because a) it makes filtering easy, and b) entity manager is still too experimental/undocumented. At some point the inner workings can be replaced by anything else but the interface remains the same. But if I understand your answer correctly that's the proper way for now right? – Giel Berkers Dec 16 '16 at 9:55
  • Correct. I edited my answer to reflect this. – Anton Kril Dec 16 '16 at 10:03
  • 1
    Considering the above, what would be proper way to implement functionality which requires data that can not be fetched through service contracts? For an example, if module A requires all orders filtered by payment method. – Stjepan Dec 22 '16 at 17:45

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.