7

I'm trying to remove the first two items in an Object. For example, if I wanted to remove the first two items from an array, I'd use array_slice($arrayName, 2).

I've tried this on my object (Hey, why not? I know it's not technically an array, but I'm optimistic) and it didn't work.

When searching for this, all I found were methods for removing items from arrays.

    $categories = array_slice(Mage::getModel('catalog/category')->getCollection()->addAttributeToSelect('*'), 2);


    foreach($categories as $category){
        echo "<div class='col'>{$category->getName()}</div>";
    }

In the example above, I'd like to remove the first two categories from the $categories (which are 'Root Category' and 'Default') object before running it through the foreach loop. What would be the best method to go about this? I know I could do;

if($category->getName() != 'Root Category' && $category->getName() != 'Default'){
  echo $category->getName();
}

But this feels like a dirty solution.

Edit

After reading Patrick Q's comment, I realised that this is indeed an array of objects. So my question now becomes, why when applying an array_slice to this array, does it result in a blank screen? The loop works fine when array_slice is not applied.

Edit 2

Ignore the last Edit. It is an Object.

As for possible duplication, while the question (in question) did indeed help me solve my problem, I think, inherently they are different questions. This question, at it's core, centred around finding a useful alternative to array_slice() for objects. The question linked on the other hand, wants to to find a way, specifically, to filter Magento collections based on a drop-down attribute. Whilst they may have arrived at the same destination, the purpose and journey are very different.

Lewis
  • 3,479
  • 25
  • 40
  • 2
    Wait, isn't `$categories` an array of `category` objects? – Patrick Q Mar 11 '16 at 15:04
  • @Patrick Q That's what I thought. But when I tried to use array_slice($categories, 2) it resulted in a blank screen. It works fine without it. – Lewis Mar 11 '16 at 15:05
  • How about casting your object to an array and then using the array_slice() ? like this $array = (array) $yourObject; – Panda Mar 11 '16 at 15:07
  • 2
    "blank screen" could mean an error. Did you check your error logs when this happened? – Patrick Q Mar 11 '16 at 15:08
  • try using var_dump();. have u enabled on screen logs ? – Panda Mar 11 '16 at 15:09
  • 2
    *But this feels like a dirty solution.* ... that's the feeling I've got from the whole of Magento from my exposure to it so far \*sighs\* – CD001 Mar 11 '16 at 15:10
  • Hmm, it does indeed think it's an object: Warning: array_slice() expects parameter 1 to be array, object given in .../app/design/frontend/rwd/mobile/template/page/1column.phtml on line 11 – Lewis Mar 11 '16 at 15:10
  • In your first block of code, the first line is using `array_slice()`. Is that the line that is throwing the error? Or are you then attempting to call `array_slice()` again after that? It is a little unclear as to what code is working and what isn't. – Patrick Q Mar 11 '16 at 15:12
  • It's the first line (Line 11 in my .php file) – Lewis Mar 11 '16 at 15:13
  • If you know the object property names to delete, simply use `unset( $category->propertyName );` – fusion3k Mar 11 '16 at 15:13
  • @fusion3k The problem is, I think it's an object filled with objects. In this case, filled with category objects. I need to delete the first two. I'll try unset as mentioned further up or casting it to array first. – Lewis Mar 11 '16 at 15:14
  • 1
    If you cast as array a not-stdObject you will loose all methods object – fusion3k Mar 11 '16 at 15:16
  • I did think about that. I'm not sure how to handle this then. My PHP Zen is not as strong as I thought. – Lewis Mar 11 '16 at 15:18
  • 1
    I've never used Magento, but based on the answers to [this question](http://stackoverflow.com/questions/14778634/how-do-i-filter-a-magento-collection-by-a-select-drop-down-attribute), it appears that there is an `addAttributeToFilter()` function that can be called on your collection that might help. – Patrick Q Mar 11 '16 at 15:23
  • @PatrickQ That's perfect, thank you! It allows me to select categories from level 2, ignoring the ones above. If you could put that as an answer, I'll gladly accept. – Lewis Mar 11 '16 at 15:26
  • I'm actually voting to close as a duplicate. That's not my answer (so I'm not just going to copy-paste) and I don't know the details well enough to write up a new answer that is more specific to your case than what's in the other question. If you want to write up your own answer to this, explaining in detail what you did and how it works, that would be acceptable. – Patrick Q Mar 11 '16 at 15:30
  • Thanks for your help. However, I've edited my question to explain why I think this isn't a possible duplicate. However, if it is deemed to be a duplicate, and as I can't answer the original intent of the question, I'll answer the assumed intent. Thanks again. – Lewis Mar 11 '16 at 15:30
  • As @PatrickQ said, you can remove elements from objects :) because objects does not contain "elements" (so It can't make sense). You have an array of objects instead! – boctulus Mar 11 '16 at 15:36

2 Answers2

6

The functionality doesn't, to my knowledge, exist in Magento.

I'm trying to remove the first two items in an Object (emphasis mine)

By default, PHP objects do not act like arrays. There's no internal to PHP concept of what it would mean for an object to have a first, second, or third item.

The reason you can foreach or count a Magento collection object as though it were an array is because the base collection object implements special interfaces from PHP's standard library -- IteratorAggregate and Countable

#File: lib/Varien/Data/Collection.php
class Varien_Data_Collection implements IteratorAggregate, Countable
{
}

By implementing these interface, (by defining methods in Varien_Data_Collection per the manual links above) the object gets foreach and count() functionality.

Magento's IteratorAggregate implementation (the thing that gives you foreach functionality) relies on PHP's built in ArrayIterator class

#File: lib/Varien/Data/Collection.php
class Varien_Data_Collection implements IteratorAggregate, Countable
{
    public function getIterator()
    {
        $this->load();
        return new ArrayIterator($this->_items);
    }
}

And objets created from the ArrayIterator class have no built in slice functionality. This makes sense -- conceptually the idea behind an iterator is that it allows you to traverse a list without loading the entire underlying list into memory at once. That Magento and PHP's base iterators work with already loaded arrays is a bit of all-to-common redundancy in OO PHP.

So, if you wanted to use slice with a Magento collection object, I'd try the getArrayCopy method of the underlying iterator.

$array = array_slice($categories->getIterator()->getArrayCopy(), 2);

This should (untested) return a PHP array with the expected elements sliced.

Hope that helps!

Alana Storm
  • 164,128
  • 91
  • 395
  • 599
  • This is very interesting, thank you! However, duplicating it to an array and slicing that, I'd assume that the resultant array loses the object methods rendering them difficult to use in the foreach loop? – Lewis Mar 11 '16 at 17:46
  • 1
    @Lewis The **collection** object would lose its methods. However, the resulting array should still contain individual category objects. i.e. $category->getName() would still work. – Alana Storm Mar 11 '16 at 18:07
3

LimitIterator is iterator related version of slice function. You can use it like:

$categories = new LimitIterator(
    Mage::getModel('catalog/category')
    ->getCollection()
    ->addAttributeToSelect('*')
    ->getIterator(), 
    2
);


foreach($categories as $category){
    echo "<div class='col'>{$category->getName()}</div>";
}
KAndy
  • 761
  • 7
  • 10