Skip to content

Commit a9222c1

Browse files
committed
initial commit
0 parents  commit a9222c1

19 files changed

+652
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/vendor
2+
composer.phar
3+
composer.lock

.travis.yml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
language: php
2+
3+
php:
4+
- 5.6
5+
- 5.4
6+
- 5.5
7+
8+
before_script:
9+
- curl -s http://getcomposer.org/installer | php
10+
- php composer.phar install --dev
11+
12+
script: phpunit

CONTRIBUTING.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Contributing
2+
3+
If you want to add a new feature, make an issue rather than a pull request.
4+
5+
Code style is pretty much PSR-2, but with tabs instead of 4 spaces. Use common sense.
6+
7+
Make separate pull requests for separate changes/issues.
8+
9+
Please don't be offended if I don't merge a pull request :)

LICENSE

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2014 Andreas Lutro
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
this software and associated documentation files (the "Software"), to deal in
7+
the Software without restriction, including without limitation the rights to
8+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
the Software, and to permit persons to whom the Software is furnished to do so,
10+
subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Menu Builder
2+
3+
Simple dynamic menu building system.
4+
5+
PHP framework agnostic. Uses Twitter Bootstrap 3 class names and is not very configurable in that regard (yet?).
6+
7+
## Installation
8+
9+
`composer require anlutro/menu` - pick the latest tag visible in the github tag list or on packagist.
10+
11+
#### Laravel 4
12+
13+
Add `anlutro\Menu\ServiceProvider` to the list of providers in app/config/app.php. Optionally, add an alias for `'Menu' => 'anlutro\Menu\Facade'` as well. The menu builder instance can be accessed via the facade or via automatic dependency injection by type hinting.
14+
15+
## Usage
16+
17+
Documentation is under construction.
18+
19+
```php
20+
$builder = new anlutro\Menu\Builder;
21+
$builder->createMenu('left');
22+
$builder->getMenu('left')->addItem('Foo Bar', URL::to('foo-bar'));
23+
$builder->getMenu('left')->addItem('Bar Baz', URL::to('bar-baz'));
24+
$builder->getMenu('left')->addSubmenu('Sub Menu');
25+
$builder->getMenu('left')->getItem('sub-menu')->addItem('Baz Foo', URL::to('baz-foo'));
26+
echo $builder->render('left');
27+
```
28+
29+
## Contact
30+
31+
Open an issue on GitHub if you have any problems or suggestions.
32+
33+
## License
34+
35+
The contents of this repository is released under the [MIT license](http://opensource.org/licenses/MIT).

composer.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "anlutro/menu",
3+
"description": "Dynamic menu builder.",
4+
"license": "MIT",
5+
"authors": [
6+
{
7+
"name": "Andreas Lutro",
8+
"email": "[email protected]"
9+
}
10+
],
11+
"require": {
12+
"php": ">=5.4.0",
13+
"illuminate/support": "4.1.*",
14+
"patchwork/utf8": "*"
15+
},
16+
"require-dev": {
17+
"mockery/mockery": "dev-master"
18+
},
19+
"autoload": {
20+
"psr-4": {
21+
"anlutro\\LaravelMenu\\": "src/"
22+
}
23+
},
24+
"minimum-stability": "stable"
25+
}

phpunit.xml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit backupGlobals="false"
3+
backupStaticAttributes="false"
4+
bootstrap="vendor/autoload.php"
5+
colors="true"
6+
convertErrorsToExceptions="true"
7+
convertNoticesToExceptions="true"
8+
convertWarningsToExceptions="true"
9+
processIsolation="false"
10+
stopOnFailure="false"
11+
syntaxCheck="false"
12+
>
13+
<testsuites>
14+
<testsuite name="Package Test Suite">
15+
<directory suffix=".php">./tests/</directory>
16+
</testsuite>
17+
</testsuites>
18+
</phpunit>

src/Builder.php

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace anlutro\Menu;
4+
5+
use Illuminate\Support\Str;
6+
7+
class Builder
8+
{
9+
protected $menus = [];
10+
protected $topMenuClass = 'nav navbar-nav';
11+
12+
public function __construct(array $options = array())
13+
{
14+
if (isset($options['top-menu-class'])) {
15+
$this->topMenuClass = $options['top-menu-class'];
16+
}
17+
}
18+
19+
public function createMenu($key, array $attributes = array())
20+
{
21+
if (isset($this->menus[$key])) {
22+
throw new \InvalidArgumentException("Menu $key already exists");
23+
}
24+
25+
$attributes['id'] = isset($attributes['id']) ? $attributes['id'] : $key;
26+
$attributes['class'] = isset($attributes['class']) ? $attributes['class'] : $this->topMenuClass;
27+
28+
return $this->menus[$key] = $this->makeMenuCollection($attributes);
29+
}
30+
31+
public function getMenu($key)
32+
{
33+
return array_key_exists($key, $this->menus) ? $this->menus[$key] : null;
34+
}
35+
36+
public function hasMenu($key)
37+
{
38+
return array_key_exists($key, $this->menus);
39+
}
40+
41+
public function render($key)
42+
{
43+
if ($menu = $this->getMenu($key)) return $menu->render();
44+
}
45+
46+
protected function makeMenuCollection(array $attributes)
47+
{
48+
return new Collection($attributes);
49+
}
50+
}

src/Collection.php

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
namespace anlutro\Menu;
4+
5+
use Illuminate\Support\Str;
6+
use Illuminate\Support\Collection as BaseCollection;
7+
8+
class Collection// extends BaseCollection
9+
{
10+
const DIVIDER = 'divider';
11+
12+
protected $items = [];
13+
protected $ids;
14+
15+
public function __construct(array $attributes = array())
16+
{
17+
$this->attributes = $this->parseAttributes($attributes);
18+
}
19+
20+
protected function parseAttributes(array $in)
21+
{
22+
$out = $in;
23+
if (isset($in['id']) && !Str::startsWith('menu-', $in['id'])) {
24+
$out['id'] = 'menu-' . $in['id'];
25+
}
26+
$out['class'] = isset($in['class']) ? explode(' ', $in['class']) : [];
27+
return $out;
28+
}
29+
30+
public function renderAttributes()
31+
{
32+
$attributes = $this->attributes;
33+
$attributes['class'] = implode(' ', $this->attributes['class']);
34+
$strings = [];
35+
foreach ($attributes as $key => $value) {
36+
if (!empty($value)) $strings[] = "$key=\"$value\"";
37+
}
38+
return implode(' ', $strings);
39+
}
40+
41+
public function addItemInstance(ItemInterface $item, $priority = null)
42+
{
43+
$priority = (int) $priority;
44+
$this->items[$priority][] = $item;
45+
$this->ids[$item->getId()] = $item;
46+
return $item;
47+
}
48+
49+
public function addItem($title, $url, array $attributes = array(), $priority = null)
50+
{
51+
return $this->addItemInstance($this->makeItem($title, $url, $attributes), $priority);
52+
}
53+
54+
public function makeItem($title, $url, array $attributes = array())
55+
{
56+
return new Item($title, $url, $attributes);
57+
}
58+
59+
public function addSubmenu($title, array $attributes = array(), $priority = null)
60+
{
61+
return $this->addItemInstance($this->makeSubmenu($title), $priority);
62+
}
63+
64+
public function makeSubmenu($title)
65+
{
66+
return new SubmenuItem($title);
67+
}
68+
69+
public function addDivider()
70+
{
71+
$this->items[] = 'divider';
72+
}
73+
74+
public function getItem($id)
75+
{
76+
return array_key_exists($id, $this->ids) ? $this->ids[$id] : null;
77+
}
78+
79+
public function render()
80+
{
81+
$items = '';
82+
$sorted = $this->items;
83+
ksort($sorted);
84+
foreach (array_flatten($sorted) as $item) {
85+
if ($item === static::DIVIDER) $items .= '<li class="divider"></li>';
86+
else $items .= '<li>'.$item->render().'</li>';
87+
}
88+
return '<ul '.$this->renderAttributes().'>'.$items.'</ul>';
89+
}
90+
}

src/Facade.php

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
namespace anlutro\Menu;
3+
4+
class Facade extends \Illuminate\Support\Facades\Facade
5+
{
6+
protected static function getFacadeAccessor()
7+
{
8+
return 'anlutro\Menu\Builder';
9+
}
10+
}

src/Item.php

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
namespace anlutro\Menu;
4+
5+
use Illuminate\Support\Str;
6+
7+
class Item implements ItemInterface
8+
{
9+
protected $title;
10+
protected $url;
11+
protected $attributes;
12+
protected $glyphicon;
13+
14+
public function __construct($title, $url, array $attributes = array())
15+
{
16+
$this->title = $title;
17+
$this->url = $url;
18+
$this->attributes = $this->parseAttributes($attributes);
19+
}
20+
21+
protected function parseAttributes(array $in)
22+
{
23+
if (isset($in['glyphicon'])) {
24+
$this->glyphicon = $in['glyphicon'];
25+
}
26+
27+
$out = array_except($in, ['glyphicon', 'href']);
28+
$out['class'] = isset($in['class']) ? explode(' ', $in['class']) : [];
29+
$out['id'] = isset($in['id']) ? $in['id'] : Str::slug($this->title);
30+
return $out;
31+
}
32+
33+
public function getId()
34+
{
35+
return $this->attributes['id'];
36+
}
37+
38+
public function renderLink()
39+
{
40+
return '<a href="' . $this->renderUrl() . '" ' .$this->renderAttributes() .
41+
'>' . $this->renderTitle() . '</a>';
42+
}
43+
44+
public function renderAttributes()
45+
{
46+
$attributes = $this->attributes;
47+
$attributes['class'] = implode(' ', $this->attributes['class']);
48+
$strings = [];
49+
foreach ($attributes as $key => $value) {
50+
if (!empty($value)) $strings[] = "$key=\"$value\"";
51+
}
52+
return implode(' ', $strings);
53+
}
54+
55+
public function renderUrl()
56+
{
57+
return $this->url;
58+
}
59+
60+
public function renderTitle()
61+
{
62+
$prepend = '';
63+
if ($this->glyphicon) {
64+
$prepend = "<span class=\"glyphicon glyphicon-{$this->glyphicon}\"></span> ";
65+
}
66+
return $prepend . e($this->title);
67+
}
68+
69+
public function render()
70+
{
71+
return $this->renderLink();
72+
}
73+
74+
public function __toString()
75+
{
76+
return $this->render();
77+
}
78+
}

src/ItemInterface.php

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace anlutro\Menu;
4+
5+
interface ItemInterface
6+
{
7+
public function render();
8+
}

src/ServiceProvider.php

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
namespace anlutro\Menu;
3+
4+
class ServiceProvider extends \Illuminate\Support\ServiceProvider
5+
{
6+
protected $defer = true;
7+
8+
public function register()
9+
{
10+
$this->app->bindShared('anlutro\Menu\Builder', function($app) {
11+
return new Builder($app['config']['anlutro/menu::config']);
12+
});
13+
}
14+
15+
public function boot()
16+
{
17+
$this->app['config']->package('anlutro/menu', __DIR__.'/config', 'anlutro/menu');
18+
}
19+
}

0 commit comments

Comments
 (0)