Repository: vespakoen/menu Branch: master Commit: a3922c07c5ae Files: 24 Total size: 68.7 KB Directory structure: gitextract_dkc3rpkb/ ├── .gitignore ├── .travis.yml ├── README.md ├── composer.json ├── phpdoc.dist.xml ├── phpunit.xml.dist ├── src/ │ ├── Menu/ │ │ ├── Items/ │ │ │ ├── Contents/ │ │ │ │ ├── Link.php │ │ │ │ └── Raw.php │ │ │ ├── Item.php │ │ │ └── ItemList.php │ │ ├── Menu.php │ │ ├── MenuHandler.php │ │ ├── MenuServiceProvider.php │ │ └── Traits/ │ │ ├── Content.php │ │ └── MenuObject.php │ └── config/ │ └── config.php ├── start.php └── tests/ ├── ItemListTest.php ├── ItemTest.php ├── LinkTest.php ├── MenuHandlerTest.php ├── MenuTest.php ├── RawTest.php └── _start.php ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .DS_Store vendor data ================================================ FILE: .travis.yml ================================================ language: php php: - 5.4 - 5.5 - 5.6 - hhvm sudo: false before_script: - composer update ================================================ FILE: README.md ================================================ # Menu [](http://travis-ci.org/vespakoen/menu) [](https://packagist.org/packages/vespakoen/menu) [](https://packagist.org/packages/vespakoen/menu) [](https://packagist.org/packages/vespakoen/menu) [](https://packagist.org/packages/vespakoen/menu) [API Docs](http://vespakoen.github.io/menu/) Are you the type of person that writes menus by hand in view files or do you find yourself looking for the best place to store links to pages on your website? then Menu is for you! # Quick overview example ```php $menu = Menu::handler('mailbox'); // items $menu ->add('contacts', 'Contacts') ->add('inbox', 'Inbox') ->raw(null, null, ['class' => 'divider']) ->add('folders', 'Folders', Menu::items() ->prefixParents() ->add('urgent', 'Urgent') // with prefix: /folders/urgent ->add('sent', 'Sent') ->add('deleted', 'Deleted') ); // styling $menu ->addClass('nav navbar-nav') ->getItemsByContentType(Menu\Items\Contents\Link::class) ->map(function($item) { if ( $item->isActive() ) { $item->addClass('active'); } }); ``` `{!! $menu !!}` will output: ```html
``` # Key concepts ## Item lists An item list is what a menu is all about and it should be pretty self explanatory because it simply stores a list of items. there are some configurations available for an item list. You can, for example set the HMTL element that will be used to render the list, prefix every item in the list with all the parent's url segments, and a lot more. We will explore these options later. ## Menu handlers Menu handlers allow us to create and interact with item lists and act as a place to store and retrieve our menus. Because we are able to interact with multiple item lists at the same time some interesting possibilities become available to us. ## Items The Menu package has 2 types of items available out of the box. - Link For creating links to other pages - Raw Be free to add anything you like in the item. This type is usually used for dividers, titles etc. The HTML element and attributes for the item can also be changed, more on this topic later. # Installing ## Laravel 3 Install Menu via the artisan command line tool. Open the terminal and navigate to your Laravel project's root. Now type the following command : ```shell php artisan bundle:install menu ``` To let Laravel know the Laravel Menu package should be started, open up `application/packages.php` and add the following lines to the packages array. ```php 'menu' => array('auto' => true), ``` ## Laravel 4 Add this to your `composer.json` file's `"require"` : ```json "vespakoen/menu": "2.*" ``` And add the following to your `app/config/app.php` file : - In the Service Providers array : `'Menu\MenuServiceProvider',` - In the aliases array : `'Menu' => 'Menu\Menu',` ## Laravel 5 Add this to your `composer.json` file's `"require"` : ```json "vespakoen/menu": "3.*" ``` And add the following to your `config/app.php` file : - In the Service Providers array : `'Menu\MenuServiceProvider',` - In the aliases array : `'Menu' => 'Menu\Menu',` Lastly, run the following from your project's root dir: ``` php artisan vendor:publish ``` # Basic usage First, let's load some pages into the menu. We will do this by utilising the `hydrate` method. ```php Menu::handler('main')->hydrate(function() { return Page::with('translation') ->where('group', '=', 'main') ->get(); }, function($children, $item) { $children->add($item->translation->slug, $item->translation->name, Menu::items($item->as)); }); /* the hydrate method takes these arguments $resolver Closure A callback to resolve results $decorator Closure A callback that gets called for every result fetched from the resolver with the corresponding ItemList and result as the arguments $idField integer (default = 'id') the property on the result that contains the id $parentIdField integer (default = 'parent_id') the property on the result that contains the parent id $parentId integer (default = 0) the parentId to start hydrating from */ ``` Now that we have loaded our pages into the menu, and even identified every menu item with a name (via `Menu::items($item->as)`) a lot of options are available to us. Find a node by it's name and add a subitem. ```php Menu::find('users') ->add('users/create', 'Create new user'); ``` Add some properties to the root node ```php Menu::handler('main') ->addClass('nav navbar-nav'); ``` Get all `ItemList`s at a certain depth and add a class ```php Menu::handler('main') ->getItemListsAtDepth(0) ->addClass('level-1'); ``` Get all `ItemList`s at a depth range and change the element ```php Menu::handler('main') ->getItemListsAtDepthRange(0,2) ->setElement('div'); ``` Get all `Item`s at a certain depth and add a class ```php Menu::handler('main') ->getItemsAtDepth(0) ->addClass('level-1'); ``` Get `Item`s by it's content type and use the map function to walk over the results and perform actions based on gathered information ```php Menu::handler('main') ->getItemsByContentType('Menu\Items\Contents\Link') ->map(function($item) { if($item->isActive() && $item->hasChildren()) { $item->addClass('is-active-link-with-children'); } if($item->getContent()->getUrl() == 'home') { $item->addClass('is-home'); } }); ``` Get all `ItemList`s and add a class to them if they have children ```php Menu::handler('main') ->getAllItemLists() ->map(function($itemList) { if($itemList->hasChildren()) { $itemList->addClass('has-children'); } }); ``` # Breadcrumbs Breadcrumb hell is a thing of the past. Bootstrap ready breadcrums are as easy as this ```php Menu::handler('main') ->breadcrumbs() ->setElement('ol') ->addClass('breadcrumb'); ``` The breadcrumbs method searches all handlers and returns a plain old ItemList, that you can manipulate. If you call the breadcrumbs method directly on the Menu class, it will search all your handlers for breadcrumbs, and by default will return the first match. However, there might be cases where you want to choose the breadcrumbs out of the ones it found, for this you can provide a callback method as the first argument. And example is shown below: ```php Menu::breadcrumbs(function($itemLists) { return $itemLists[0]; // returns first match }) ->setElement('ol') ->addClass('breadcrumb'); ``` # Diving deeper The Laravel Menu packages consists of a couple of classes, but you can interact with all of them via the _Menu_ class. Let's take a look at the **handler** method. it takes a string or an array as the only argument, the string(s) given are the names for the item lists we want to retrieve. If an itemlist we asked for didn't exist yet, it will create it for us. After the menu class has found and created the item lists we want, it will hand back a menuhandler that handles the item lists we asked for. ```php // Get a MenuHandler instance that handles an ItemList named "main" Menu::handler('main'); ``` When we call a method on this menu handler, it will simply forward the call to all the item lists that it handles. In order to find out what we can do now that we have a handler, we need to take a look at the methods on the ItemList class. The _ItemList_ class has a method called **add** that you are probably going to use a lot. It adds an _Item_ of type "link" to the _ItemList_. ```php Menu::handler('main')->add('home', 'Homepage'); /* The add method takes these arguments $url string The URL to another page $title string The visible string on the link $children (default = null) ItemList (optional) The children of this page $link_attributes (default = array()) array (optional) HTML attributes for the element $item_attributes (default = array()) array (optional) HTML attributes for the list element (usually
');
/* The raw method takes these arguments
$html string The contents of the item
$children (default = null) ItemList (optional) The children of this item
$item_attributes (default = array()) array (optional) HTML attributes for the list element (usually
* // Add a item to the default menu
* Menu::add('home', 'Homepage');
*
* // Add a item with a subitem to the default menu
* Menu::add('home', 'Homepage', Menu::items()->add('home/sub', 'Subitem'));
*
* // Add a item with attributes for the item's HTML element
* Menu::add('home', 'Homepage', null, array('class' => 'fancy'));
*
*
* @param string $url Url of the link
* @param string $value (H)T(ML) inside of the link
* @param ItemList $children Children
* @param array $linkAttributes Attributes for the link
* @param array $itemAttributes Attributes for the item
* @param string $itemElement The element for the item
* @param string $beforeContent String to add before the link
* @param string $afterContent String to add after the link
*
* @return ItemList
*/
public function add($url, $value, $children = null, $linkAttributes = array(), $itemAttributes = array(), $itemElement = null, $beforeContent = null, $afterContent = null)
{
$content = new Link($url, $value, $linkAttributes);
$item = $this->addContent($content, $children, $itemAttributes, $itemElement, $beforeContent, $afterContent);
return $this;
}
/**
* Add a raw html item to the ItemList instance.
*
*
* // Add a raw item to the default main menu
* Menu::raw('
');
*
*
* @param string $raw The raw content
* @param ItemList $children Children
* @param array $itemAttributes The item attributes
* @param string $itemElement The item element
* @param string $beforeContent String to add before the raw content
* @param string $afterContent String to add after the raw content
*
* @return ItemList
*/
public function raw($raw, $children = null, $itemAttributes = array(), $itemElement = null, $beforeContent = null, $afterContent = null)
{
$content = new Raw($raw);
$item = $this->addContent($content, $children, $itemAttributes, $itemElement, $beforeContent, $afterContent);
return $this;
}
/**
* Add content to the ItemList
*
* @param Content $content Content object
* @param ItemList $children Children
* @param array $itemAttributes Attributes for the item (li)
* @param string $itemElement Element for the item (li is default)
* @param string $beforeContent String to add before the content
* @param string $afterContent String to add after the content
*/
public function addContent($content, $children = null, $itemAttributes = array(), $itemElement = null, $beforeContent = null, $afterContent = null)
{
$item = new Item($this, $content, $children, $itemElement, $beforeContent, $afterContent);
$item->setAttributes($itemAttributes);
// Set Item as parent of its children
if (!is_null($children)) {
$children->setParent($item);
}
$this->setChild($item);
return $item;
}
/**
* Add an active pattern to the ItemList instance.
*
*
* // Add a item to the default menu and set an active class for /user/5/edit
* Menu::add('user', 'Users')->activePattern('\/user\/\d\/edit');
*
*
* @param string $pattern
*
* @return ItemList
*/
public function activePattern($pattern)
{
$pattern = (array) $pattern;
$item = end($this->children);
$item->setActivePatterns($pattern);
return $this;
}
/**
* Add menu items to another ItemList.
*
*
* // Attach menu items to the default MenuHandler
* Menu::attach(Menu::items()->add('home', 'Homepage'));
*
*
* @param ItemList $itemList
*
* @return ItemList
*/
public function attach(ItemList $itemList)
{
$this->nestChildren($itemList->getChildren());
return $this;
}
/**
* Set the name for this ItemList
*
* @param string $name
*
* @return ItemList
*/
public function name($name)
{
$this->name = $name;
return $this;
}
/**
* Get the name of the ItemList
*
* @return string Name of the ItemList
*/
public function getName()
{
return $this->name;
}
////////////////////////////////////////////////////////////////////
///////////////////////////// PREFIXES /////////////////////////////
////////////////////////////////////////////////////////////////////
/**
* Prefix this ItemList with a string
*
* @param string $prefix
*
* @return ItemList
*/
public function prefix($prefix)
{
$this->setOption('item_list.prefix', $prefix);
return $this;
}
/**
* Prefix this ItemList with the parent ItemList(s) name(s)
*
* @param boolean $prefixParents
*
* @return ItemList
*/
public function prefixParents($prefixParents = true)
{
$this->setOption('item_list.prefix_parents', $prefixParents);
return $this;
}
/**
* Prefix this ItemList with the name of the ItemList at the very top of the tree
*
* @param boolean $prefixMenuHandler
*
* @return ItemList
*/
public function prefixMenuHandler($prefixMenuHandler = true)
{
$this->setOption('item_list.prefix_handler', $prefixMenuHandler);
return $this;
}
/**
* Set the Item's element
*
* @param string $element
*/
public function setElement($element = null)
{
$this->element = $element;
return $this;
}
/**
* Get the Item's element
*
* @return string
*/
public function getElement()
{
if (is_null($this->element)) {
return $this->getOption('item_list.element');
}
return $this->element;
}
/**
* Get all items with the depth as key
*
* @return array
*/
public function getItemsWithDepth()
{
return $this->getItemsRecursivelyWithDepth($this->getChildren());
}
/**
* Get all items for an array of items recursively for a specific depth
*
* @return array
*/
protected function getItemsRecursivelyWithDepth($items, $depth = 0)
{
$results = array();
foreach($items as $item)
{
$results[$depth][] = $item;
$subItems = $item->getChildren()
->getChildren();
foreach($this->getItemsRecursivelyWithDepth($subItems, $depth + 1) as $childrenDepth => $children)
{
foreach($children as $child)
{
$results[$childrenDepth][] = $child;
}
}
}
return $results;
}
/**
* Get all itemlists with the depth as key
*
* @return array
*/
public function getItemListsWithDepth()
{
return $this->getItemListsRecursivelyWithDepth($this);
}
/**
* Get all itemlists for an itemlsit recursively for a specific depth
*
* @return array
*/
protected function getItemListsRecursivelyWithDepth($itemList, $depth = 0)
{
$results = array();
$results[$depth][] = $itemList;
$items = $itemList->getChildren();
foreach($items as $item)
{
foreach($this->getItemListsRecursivelyWithDepth($item->getChildren(), $depth + 1) as $childrenDepth => $children)
{
foreach($children as $child)
{
$results[$childrenDepth][] = $child;
}
}
}
return $results;
}
/**
* Get all items
*
* @return \Vespakoen\Menu\MenuHandler
*/
public function getAllItems()
{
$results = array();
foreach($this->getItemsWithDepth() as $depth => $items)
{
foreach($items as $item)
{
$results[] = $item;
}
}
return new MenuHandler($results);
}
/**
* Get items by their content type
*
* @param string $contentType The full object name
*
* @return \VEspakoen\Menu\MenuHandler
*/
public function getItemsByContentType($contentType)
{
$results = array();
$itemList = $this->getAllItems();
foreach($itemList->getMenuObjects() as $item)
{
$content = $item->getContent();
if(get_class($content) == $contentType)
{
$results[] = $item;
}
}
return new MenuHandler($results);
}
/**
* Get all itemlists
*
* @return \Vespakoen\Menu\MenuHandler
*/
public function getAllItemLists()
{
$results = array();
foreach($this->getItemListsWithDepth() as $depth => $items)
{
foreach($items as $item)
{
$results[] = $item;
}
}
return new MenuHandler($results);
}
/**
* Get all itemslists including this one
*
* @return \Vespakoen\Menu\MenuHandler
*/
public function getAllItemListsIncludingThisOne()
{
return $this->getAllItemLists()
->addMenuObject($this);
}
/**
* Get itemlists at a certain depth
*
* @return \Vespakoen\Menu\MenuHandler
*/
public function getItemListsAtDepth($depth)
{
$itemListsWithDepth = $this->getItemListsWithDepth();
if (array_key_exists($depth, $itemListsWithDepth)) {
return new MenuHandler($itemListsWithDepth[$depth]);
}
return new MenuHandler(array());
}
/**
* Get itemlists in a range of depths
*
* @return \Vespakoen\Menu\MenuHandler
*/
public function getItemListsAtDepthRange($from, $to)
{
$itemListsWithDepth = $this->getItemListsWithDepth();
$results = array();
foreach($itemListsWithDepth as $depth => $itemLists)
{
if($depth >= $from && $depth <= $to)
{
foreach($itemLists as $itemList)
{
$results[] = $itemList;
}
}
}
return new MenuHandler($results);
}
/**
* Get all items at a certain depth
*
* @return \Vespakoen\Menu\MenuHandler
*/
public function getItemsAtDepth($depth)
{
$itemsWithDepth = $this->getItemsWithDepth();
if (array_key_exists($depth, $itemsWithDepth)) {
return new MenuHandler($itemsWithDepth[$depth]);
}
return new MenuHandler(array());
}
/**
* Get items in a range of depths
*
* @return \Vespakoen\Menu\MenuHandler
*/
public function getItemsAtDepthRange($from, $to)
{
$itemsWithDepth = $this->getItemsWithDepth();
$results = array();
foreach($itemsWithDepth as $depth => $items)
{
if($depth >= $from && $depth <= $to)
{
foreach($items as $item)
{
$results[] = $item;
}
}
}
return new MenuHandler($results);
}
public function reverse()
{
$this->children = array_reverse($this->children);
return $this;
}
public function findActiveItem()
{
$items = $this->getAllItems()
->getMenuObjects();
// Find the active one
foreach($items as $item) {
if($item->isActive()) {
return $item;
}
}
return null;
}
public function getSubmenu()
{
if($activeItem = $this->findActiveItem())
{
return $activeItem->getChildren();
}
return new ItemList;
}
public function breadcrumbs()
{
// Collect all items
$activeItem = $this->findActiveItem();
$separator = $this->getOption('item_list.breadcrumb_separator');
// Make the breadcrumbs
$itemList = new ItemList(array(), 'breadcrumbs');
// Fill her up if we found the active link
if( ! is_null($activeItem)) {
// Add the found item
$itemList->addContent($activeItem->getContent());
// Loop throught the parents until we hit the root
while($nextItem = $activeItem->getParent()) {
if(is_null($nextItem->getParent())) break;
// Add a separator and the link
if ( ! empty($separator))
{
$itemList->raw($separator);
}
$itemList->addContent($nextItem->getParent()->getContent());
// Set the activeItem for the next iteration
$activeItem = $nextItem->getParent();
}
}
// Correct order
$itemList->reverse();
return $itemList;
}
public function map($callback)
{
array_map($callback, $this->children);
return $this;
}
/**
* Find an itemlist by it's name
*
* @return \Vespakoen\Menu\Items\ItemLists|false
*/
public function findItemListByName($name)
{
$itemLists = $this->getAllItemListsIncludingThisOne()
->getMenuObjects();
foreach($itemLists as $itemList)
{
if($itemList->getName() == $name)
{
return $itemList;
}
}
return false;
}
/**
* Find an itemlist by it's name
*
* alias for findItemListByName
*
* @return \Vespakoen\Menu\Items\ItemLists|false
*/
public function findByName($name)
{
return $this->findItemListByName($name);
}
/**
* Find an itemlist by it's name
*
* alias for findItemListByName
*
* @return \Vespakoen\Menu\Items\ItemLists|false
*/
public function find($name)
{
return $this->findItemListByName($name);
}
/**
* Find an item by an attribute
*
* @return \Vespakoen\Menu\Items\Item|false
*/
public function findItemByAttribute($key, $value)
{
$itemLists = $this->getAllItemListsIncludingThisOne()
->getMenuObjects();
foreach($itemLists as $itemList)
{
if($itemList->getAttibute($key) == $value)
{
return $itemList;
}
}
return false;
}
/**
* Find an item by it's link's URL
*
* @return \Vespakoen\Menu\Items\Item|false
*/
public function findItemByUrl($url)
{
$itemList = $this->getItemsByContentType('Menu\Items\Contents\Link');
foreach($itemList->getChildren() as $item)
{
$content = $item->getContent();
if($content->getUrl() == $url)
{
return $item;
}
}
return false;
}
/**
* Easily create items while looping over DB results
* that have a reference to the parent (usually via parentId)
*
*
* Menu::hydrate(function($parentId)
* {
* return Page::where('parent_id', $parentId)
* ->get();
* },
* function($children, $page)
* {
* $children->add($page->slug, $page->name);
* });
*
*
* @param Closure $resolver the callback to resolve results for a given parentId
* @param Closure $decorator the callback that modifies the ItemList for the given node
* @param integer $idField the id column that matches with the parentId
* @param integer $parentId the parentId to start hydrating from
*
* @return ItemList the
*/
public function hydrate($resolver, $decorator, $idField = 'id', $parentIdField = 'parent_id', $parentId = 0)
{
$items = is_callable($resolver) ? $resolver() : $resolver;
if($items instanceof Collection)
{
$items = $items->all();
}
$itemsForThisLevel = array_filter($items, function($item) use ($parentId, $parentIdField)
{
return $parentId == (is_object($item) ? (isset($item->$parentIdField) ? $item->$parentIdField : 0) : (isset($item[$parentIdField]) ? $item[$parentIdField] : 0));
});
foreach($itemsForThisLevel as $item)
{
// Let the decorator add the item(s) (and maybe set some attributes)
$decorator($this, $item);
// Grab the newest item
$newestItem = end($this->children);
// If there is an item, add hydrate it
if($newestItem)
{
// Grab the newest itemlist
$newestItemList = $newestItem->getChildren();
// Get the id of the item
$parentId = is_object($item) ? $item->$idField : $item[$idField];
// Hydrate the children
$newestItemList->hydrate($items, $decorator, $idField, $parentIdField, $parentId);
}
}
return $this;
}
/**
* Get the evaluated string content of the ItemList.
*
* @param integer $depth The depth at which the ItemList should be rendered
*
* @return string
*/
public function render($depth = 0)
{
if( ! is_int($depth))
{
throw new Exception("The render method doesn't take any arguments anymore, you can now configure your menu via the config file.");
}
// Check for maximal depth
$maxDepth = $this->getOption('max_depth');
if ($maxDepth !== -1 and $depth > $maxDepth) return false;
// Render contained items
$contents = null;
if(count($this->children) == 0)
{
return "";
}
foreach ($this->children as $item) {
$contents .= $item->render($depth + 1);
}
$element = $this->getElement();
if ($element) $contents = Element::create($element, $contents, $this->attributes)->render();
return $contents;
}
}
================================================
FILE: src/Menu/Menu.php
================================================
* // Get the menu handler that handles the default name
* $handler = Menu::handler();
*
* // Get a named menu handler for a single name
* $handler = Menu::handler('backend');
*
* // Get a menu handler that handles multiple names
* $handler = Menu::handler(array('admin', 'sales'));
*
*
* @param string|array $names The name this handler should respond to
* @param array $attributes Its attributes
* @param string $element Its element
*
* @return MenuHandler
*/
public static function handler($names = '', $attributes = array(), $element = 'ul')
{
$names = (array) $names;
$itemLists = array();
// Create a new ItemList instance for the names that don't exist yet
foreach ($names as $name) {
if (!array_key_exists($name, static::$itemLists)) {
$itemList = new ItemList(array(), $name, $attributes, $element);
static::setItemList($name, $itemList);
}
else {
$itemList = static::getItemList($name);
}
$itemLists[] = $itemList;
}
// Return a Handler for the item lists
return new MenuHandler($itemLists);
}
/**
* Get a MenuHandler for all registered ItemLists
*
* @return MenuHandler
*/
public static function allHandlers()
{
return new MenuHandler(static::$itemLists);
}
/**
* Erase all menus in memory
*/
public static function reset()
{
static::$itemLists = array();
}
////////////////////////////////////////////////////////////////////
//////////////////////// ITEM LISTS MANAGING ///////////////////////
////////////////////////////////////////////////////////////////////
/**
* Create a new ItemList
*
* @param string $name The name of the ItemList
* @param array $attributes The HTML attributes for the list element
* @param string $element The HTML element for the list (ul or dd)
*
* @return ItemList
*/
public static function items($name = null, $attributes = array(), $element = 'ul')
{
return new ItemList(array(), $name, $attributes, $element);
}
/**
* Store an ItemList in memory
*
* @param string $name The handle to store it to
* @param ItemList $itemList
*
* @return ItemList
*/
public static function setItemList($name, $itemList)
{
static::$itemLists[$name] = $itemList;
return $itemList;
}
/**
* Get an ItemList from the memory
*
* @param string $name The ItemList handle
*
* @return ItemList
*/
public static function getItemList($name = null)
{
if (is_null($name)) return static::$itemLists;
return static::$itemLists[$name];
}
////////////////////////////////////////////////////////////////////
/////////////////////////// MAGIC METHODS //////////////////////////
////////////////////////////////////////////////////////////////////
/**
* Magic Method for calling methods on the default handler.
*
*
* // Call the "render" method on the default handler
* echo Menu::render();
*
* // Call the "add" method on the default handler
* Menu::add('home', 'Home');
*
*
* @param string $method
* @param array $parameters
*
* @return mixed
*/
public static function __callStatic($method, $parameters = array())
{
return call_user_func_array(array(static::handler(), $method), $parameters);
}
////////////////////////////////////////////////////////////////////
/////////////////////// DEPENDENCY INJECTIONS //////////////////////
////////////////////////////////////////////////////////////////////
/**
* Get the current dependencies
*
* @param string $dependency A dependency to make on the fly
*
* @return Container
*/
public static function getContainer($dependency = null)
{
if (!static::$container) {
$container = new Container;
// Create HTML
$container->bindIf('html', 'LaravelBook\Laravel4Powerpack\HTML');
// Create basic Request instance to use
$container->alias('Symfony\Component\HttpFoundation\Request', 'request');
$container->bindIf('Symfony\Component\HttpFoundation\Request', function() {
return Request::createFromGlobals();
});
static::setContainer($container);
}
// Shortcut for getting a dependency
if ($dependency) {
return static::$container->make($dependency);
}
return static::$container;
}
/**
* Set the Container to use
*
* @param Container $container
*/
public static function setContainer($container)
{
static::$container = $container;
}
/**
* Get an option from the options array
*
* @param string $option The option key
*
* @return mixed Its value
*/
public static function getOption($option = null)
{
if ($option == null) {
return static::getContainer('config')->get('menu');
}
return static::getContainer('config')->get('menu.'.$option);
}
/**
* Set a global option
*
* @param key $option The option
* @param mixed $value Its value
*/
public static function setOption($option, $value)
{
if ($option == null) {
$option = 'config';
}
static::getContainer('config')->set('menu.'.$option, $value);
}
}
================================================
FILE: src/Menu/MenuHandler.php
================================================
array(
'getAllItems',
'getItemsAtDepth',
'getItemsAtDepthRange',
'getItemsByContentType',
'getAllItemLists',
'getSubmenu',
'getItemListsAtDepth',
'getItemListsAtDepthRange',
'onItem',
'getContent',
'stop',
'filter'
),
'getMatchFromResults' => array(
'findItemListByName',
'findActiveItem',
'findByName',
'findItemByUrl',
'find'
),
'getCombinedResults' => array(
'lists'
),
'getCombindedResultsByKey' => array(
'getItemsWithDepth',
'getItemListsWithDepth'
),
'getImplodedResults' => array(
'render'
)
);
/**
* Set the menuobjects on which this menu should act
*
* @param array $menuObjects The menuobjects
*
* @return void
*/
public function __construct($menuObjects = array())
{
$this->menuObjects = $menuObjects;
}
////////////////////////////////////////////////////////////////////
////////////////////////// PUBLIC INTERFACE ////////////////////////
////////////////////////////////////////////////////////////////////
public function setMenuObjects($menuObjects)
{
$this->menuObjects = $menuObjects;
return $this;
}
public function getMenuObjects()
{
return $this->menuObjects;
}
public function addMenuObject($menuObject)
{
$this->menuObjects[] = $menuObject;
return $this;
}
public function map($callback)
{
array_map($callback, $this->getMenuObjects());
}
public function breadcrumbs($choosePath = null)
{
if(is_null($choosePath)) {
$choosePath = function($itemLists) {
return $itemLists[0];
};
}
$menuObjects = array();
foreach (Menu::allHandlers()->getMenuObjects() as $itemList) {
$breadcrumbs = $itemList->breadcrumbs();
if($breadcrumbs->hasChildren()) {
$menuObjects[] = $breadcrumbs;
}
}
if(count($menuObjects) > 1)
{
return $choosePath($menuObjects);
}
return isset($menuObjects[0]) ? $menuObjects[0] : new MenuHandler;
}
////////////////////////////////////////////////////////////////////
//////////////////////////// RESPONDERS ////////////////////////////
////////////////////////////////////////////////////////////////////
protected function getHandlerFromResults($menuHandlers)
{
if(is_array($menuHandlers) && count($menuHandlers) > 0 && ! $menuHandlers[0] instanceof MenuHandler) {
foreach ($menuHandlers as &$menuHandler) {
$menuHandler = new MenuHandler(array($menuHandler));
}
}
$menuObjects = $this->getMenuObjectsFromHandlers($menuHandlers);
return new MenuHandler($menuObjects);
}
protected function getMatchFromResults($results)
{
foreach($results as $result)
{
if($result !== false)
{
return $result;
}
}
return false;
}
protected function getCombinedResults($results)
{
return call_user_func_array('array_merge', $results);
}
protected function getCombindedResultsByKey($results)
{
$combinedResults = array();
foreach ($results as $result)
{
foreach($result as $key => $items)
{
foreach($items as $item)
{
$combinedResults[$key][] = $item;
}
}
}
return $combinedResults;
}
protected function getImplodedResults($results)
{
return implode('', $results);
}
////////////////////////////////////////////////////////////////////
///////////////////////// RESULT EXTRACTORS ////////////////////////
////////////////////////////////////////////////////////////////////
protected function getMenuObjectsFromHandlers($menuHandlers)
{
$results = array();
foreach($menuHandlers as $menuHandler)
{
foreach($menuHandler->getMenuObjects() as $item)
{
$results[] = $item;
}
}
return $results;
}
////////////////////////////////////////////////////////////////////
/////////////////////////// MAGIC METHODS //////////////////////////
////////////////////////////////////////////////////////////////////
/**
* Magic method that will pass the incoming calls to
* all of the ItemLists this handler acts on
*
* @param string $method
* @param array $parameters
*
* @return MenuHandler
*/
public function __call($method, $parameters = array())
{
$results = array();
foreach ($this->menuObjects as &$menuObject) {
$result = call_user_func_array(array($menuObject, $method), $parameters);
if (Str::startsWith($method, static::$override)) {
$menuObject = $result;
}
$results[] = $result;
}
foreach (static::$responses as $responseMethod => $methods) {
if(in_array($method, $methods)) {
return $this->$responseMethod($results);
}
}
return $this;
}
/**
* Render the MenuHandler
*
* @return string
*/
public function __toString()
{
return $this->render();
}
}
================================================
FILE: src/Menu/MenuServiceProvider.php
================================================
mergeConfigFrom($configPath, 'menu');
$container = Menu::getContainer();
$container['url'] = $this->app['url'];
$container['config'] = $this->app['config'];
Menu::setContainer($container);
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array('menu');
}
/**
* Declare publishable assets
*
* @return void
*/
public function boot()
{
$configPath = __DIR__ . '/../config/config.php';
$this->publishes([$configPath => config_path('menu.php')], 'config');
}
}
================================================
FILE: src/Menu/Traits/Content.php
================================================
getParent(1);
}
}
================================================
FILE: src/Menu/Traits/MenuObject.php
================================================
options = array();
foreach($options as $key => $value) {
$this->setOption($key, $value);
}
return $this;
}
/**
* Set a particular option in the array
*
* @param string $option The option
* @param mixed $value Its new value
*
* @return MenuObject
*/
public function setOption($option, $value)
{
$this->options = ArraysMethods::set($this->options, $option, $value);
return $this;
}
/**
* Get a particular option in the array
*
* @param string $option An option
*
* @return mixed Its value
*/
public function getOption($option = null)
{
$globalOptions = Menu::getOption();
$combinedOptions = array_replace_recursive($globalOptions, $this->options);
if (!$option) return $combinedOptions;
return ArraysMethods::get($combinedOptions, $option);
}
}
================================================
FILE: src/config/config.php
================================================
-1,
// Items --------------------------------------------------------- /
// Various options related to Items
'item' => array(
// The default Item element
'element' => 'li',
// Various classes to mark active items or children
'active_class' => 'active',
'active_child_class' => 'active-child',
),
// ItemLists ----------------------------------------------------- /
'item_list' => array(
// The default ItemList element
'element' => 'ul',
// The default breadcrumb separator, set to '' to not output any separators for
// use with bootstrap.
'breadcrumb_separator' => '/',
// A prefix to prepend the links URLs with
'prefix' => null,
// Whether links should inherit their parent/handler's prefix
'prefix_parents' => false,
'prefix_handler' => false,
),
);
================================================
FILE: start.php
================================================
assertTrue('' == static::$itemList->render());
}
public function testCanCreateListsOfADifferentElement()
{
$list = static::$itemList->add('some', 'item');
$list->setElement('ol');
$this->assertHTML($this->matchList('ol'), $list->render());
}
public function testCanPrefixItems()
{
$list = static::$itemList;
$list->prefixParents()->prefix('foo');
$list->add('bar', 'foo');
$matcher = $this->matchListWithItem();
$matcher['child']['child'] = $this->matchLink(URL::to('foo/bar'));
$this->assertHTML($matcher, $list->render());
}
public function testCanSetClassOnLists()
{
$list = static::$itemList;
$list->addClass('foo')->data_foo('bar');
$list->add('some', 'item');
$matcher = $this->matchList();
$matcher['attributes']['class'] = 'foo';
$matcher['attributes']['data-foo'] = 'bar';
$this->assertHTML($matcher, $list);
}
public function testCanSetClassOnItems()
{
$list = static::$itemList;
$list->add('#', 'foo')->onItem()->addClass('foo')
->getContent()->href('#lol');
$matcher = $this->matchListWithItem('ul', 'li');
$matcher['child']['attributes']['class'] = 'foo';
$matcher['child']['child']['attributes']['href'] = '#lol';
$this->assertHTML($matcher, $list);
}
public function testChainingMethods()
{
$menu = static::$itemList
->add('#', 'foo')->onItem()->data_foo('bar')->addClass('active')
->getContent()->href('lol')->stop()
->add('#', 'bar');
$this->assertEquals(
'', $menu->render());
}
public function testCanAttachMenus()
{
$list = static::$itemList;
$list->add('#', 'foo');
$list->attach(Menu::items()->add('#', 'bar'));
$this->assertHTML($this->matchListWithItem(), $list);
$this->assertHTML($this->matchLink('#', 'bar'), $list);
}
}
================================================
FILE: tests/ItemTest.php
================================================
assertHTML($this->matchItem(), static::$item->render());
}
public function testCanCreateItemOfADifferentElement()
{
$item = static::$item;
$item->setElement('dl');
$this->assertHTML($this->matchItem('dl'), $item->render());
}
public function testCanCreateRawItem()
{
$item = new Item(static::$itemList, static::$raw);
$matcher = array('tag' => 'li', 'content' => 'foo');
$this->assertHTML($matcher, $item->render());
}
public function testCanCreateItemWithSublist()
{
$sublist = static::$itemList;
$sublist->add('#', 'foo');
$item = new Item(static::$itemList, static::$link, $sublist);
$matchSublist = array(
'tag' => 'li',
'child' => array(
'tag' => 'ul',
'child' => $this->matchItem(),
),
);
$this->assertHTML($this->matchItem(), $item->render());
$this->assertHTML($matchSublist, $item->render());
}
public function testCanCreateElementlessItems()
{
$item = new Item(static::$itemList, static::$link);
$item->setElement(null);
$this->assertHTML($this->matchLink(), $item->render());
}
}
================================================
FILE: tests/LinkTest.php
================================================
assertHTML($this->matchLink(), static::$link->render());
}
public function testLinksAreLinks()
{
$this->assertTrue(static::$link->isLink());
}
public function testDoesntAlterSpecialUrls()
{
$link = new Link('javascript:void(0);', 'foo');
$matcher = $this->matchLink('javascript:void(0);');
$this->assertHTML($matcher, $link);
}
public function testCanSetAttributesOnLinks()
{
$link = static::$link;
$link->class('foobar');
$matcher = $this->matchLink();
$matcher['attributes']['class'] = 'foobar';
$this->assertHTML($matcher, $link->render());
}
}
================================================
FILE: tests/MenuHandlerTest.php
================================================
assertEquals(array_values(Menu::getItemList()), $menu->getMenuObjects());
}
}
================================================
FILE: tests/MenuTest.php
================================================
assertInstanceOf('Menu\MenuHandler', $menu);
}
public function testCanGetAMenuThatHandlesEverything()
{
Menu::handler('foo');
Menu::handler('bar');
$allHandlers = Menu::allHandlers();
$this->assertEquals(array('foo', 'bar'), array_keys($allHandlers->getMenuObjects()));
}
public function testCanResetAllHandles()
{
Menu::handler('foo');
Menu::reset();
$this->assertEquals(array(), Menu::getItemList());
}
public function testCanReturnItemLists()
{
$itemList = Menu::items('foo');
$this->assertInstanceOf('Menu\Items\ItemList', $itemList);
}
public function testCanSetItemLists()
{
$itemList = Menu::items('foo');
Menu::setItemList('foo', $itemList);
$this->assertArrayHasKey('foo', Menu::getItemList());
}
public function testCanRenderManuallyBindedItemLists()
{
$menu = Menu::handler('categories')
->add('algorithms', 'Algorithms', Menu::items()->prefixParents()
->add('cryptography', 'Cryptography')
->add('data-structures', 'Data Structures')
->add('digital-image-processing', 'Digital Image Processing')
->add('memory-management', 'Memory Management'))
->add('graphics-and-multimedia', 'Graphics & Multimedia', Menu::items()->prefixParents()
->add('directx', 'DirectX')
->add('flash', 'Flash')
->add('opengl', 'OpenGL'));
$matcher =
'