Access a relationship on a collection

Submitted by riddles8888 - 10 years ago

I have put together a custom collection that will allow you to access a relationship on all objects in a collection. You can also run a method from an object in the collection on the entire collection such has touch or delete.

My Custom Collection Class

I placed this file in library/utility then added library to the auto load list in the composer.json file.

library/utility/collection.php
<?php
/**
 * Dev-Toolbox Custom Utility Collection.
 *
 * Extra methods for the eloquent collection.
 *
 *
 * @author      RiDdLeS <riddles@dev-toolbox.com>
 * @version     0.1
 */

class Utility_Collection extends Illuminate\Database\Eloquent\Collection {

    /**
	 * Dynamically retrieve attributes on the model.
	 *
	 * @param  string  $key
	 * @return mixed
	 */
	public function __get($key)
	{
		$newCollection = new Utility_Collection();
		foreach ($this->items as $item) {
			if ($item instanceof Utility_Collection) {
				foreach ($item as $subItem) {
					$newCollection->put($newCollection->count(), $subItem->$key);
				}
			}
			elseif (is_object($item) && !$item instanceof Utility_Collection && $item->$key instanceof Utility_Collection) {
				foreach ($item->$key as $subItem) {
					$newCollection->put($newCollection->count(), $subItem);
				}
			}
			else {
				$newCollection->put($newCollection->count(), $item->$key);
			}
		}
		return $newCollection;
	}

	/**
	 * Allow a method to be run on the enitre collection.
	 *
	 * @param string $method
	 * @param array $args
	 * @return Utility_Collection
	 */
	public function __call($method, $args)
	{
		if ($this->count() <= 0) {
			return $this;
		}

		foreach ($this->items as $item) {
			if (!is_object($item)) {
				continue;
			}
			call_user_func_array(array($item, $method), $args);
		}

		return $this;
	}
}

I then added the following to all of my models:
    /**
     * Use the custom collection that allows tapping
     *
     * @return Utility_Collection[]
     */
    public function newCollection(array $models = array())
    {
        return new Utility_Collection($models);
    }
    
For testing i created a user model and role model and an action model.
Users have roles and roles have actions.

Once you create all the proper relationships you can do somthing like this from your controller.
$user = User::find(1);
$actions = $user->roles->actions; // This will return a collection of all actions in all roles attached to the user.

You can also get all attrubites of one type on the collection.
$roleNames = $user->roles->name; // This will return all name attrubites of all roles the user is attached to.

Lastly you could do
$user->roles->delete(); // This will remove all roles from the user.