├── .github └── workflows │ └── php.yml ├── .gitignore ├── .php_cs ├── .travis.yml ├── LICENSE ├── composer.json ├── config └── sidebar.php ├── phpunit.xml ├── readme.md ├── resources └── views │ ├── adminlte-2 │ ├── append.blade.php │ ├── badge.blade.php │ ├── group.blade.php │ ├── item.blade.php │ └── menu.blade.php │ └── adminlte-3 │ ├── append.blade.php │ ├── badge.blade.php │ ├── group.blade.php │ ├── item.blade.php │ └── menu.blade.php ├── src ├── Append.php ├── Authorizable.php ├── Badge.php ├── Domain │ ├── DefaultAppend.php │ ├── DefaultBadge.php │ ├── DefaultGroup.php │ ├── DefaultItem.php │ ├── DefaultMenu.php │ └── Events │ │ ├── FlushesSidebarCache.php │ │ └── ShouldFlushCache.php ├── Exceptions │ ├── CacheTagsNotSupported.php │ ├── LogicException.php │ ├── SidebarFlusherNotSupported.php │ └── SidebarResolverNotSupported.php ├── Group.php ├── Infrastructure │ ├── CacheKey.php │ ├── ContainerResolver.php │ ├── NullSidebarFlusher.php │ ├── SidebarFlusher.php │ ├── SidebarFlusherFactory.php │ ├── SidebarResolver.php │ ├── SidebarResolverFactory.php │ ├── StaticCacheResolver.php │ ├── StaticSidebarFlusher.php │ ├── SupportsCacheTags.php │ ├── UserBasedCacheResolver.php │ └── UserBasedSidebarFlusher.php ├── Item.php ├── Itemable.php ├── Menu.php ├── Middleware │ └── ResolveSidebars.php ├── Presentation │ ├── ActiveStateChecker.php │ ├── Illuminate │ │ ├── IlluminateAppendRenderer.php │ │ ├── IlluminateBadgeRenderer.php │ │ ├── IlluminateGroupRenderer.php │ │ ├── IlluminateItemRenderer.php │ │ └── IlluminateSidebarRenderer.php │ └── SidebarRenderer.php ├── Routeable.php ├── ShouldCache.php ├── Sidebar.php ├── SidebarExtender.php ├── SidebarManager.php ├── SidebarServiceProvider.php └── Traits │ ├── AuthorizableTrait.php │ ├── CacheableTrait.php │ ├── CallableTrait.php │ ├── ItemableTrait.php │ └── RouteableTrait.php └── tests ├── Domain ├── DefaultAppendTest.php ├── DefaultBadgeTest.php ├── DefaultGroupTest.php ├── DefaultItemTest.php └── DefaultMenuTest.php ├── SidebarExtenderTest.php └── Traits ├── AuthorizableTraitTest.php ├── ItemableTraitTest.php └── RouteableTraitTest.php /.github/workflows/php.yml: -------------------------------------------------------------------------------- 1 | name: PHP Pipeline 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | max-parallel: 2 12 | matrix: 13 | php-versions: ['8.1', '8.2', '8.3'] 14 | 15 | name: PHP ${{ matrix.php-versions }} 16 | 17 | steps: 18 | - uses: actions/checkout@v1 19 | 20 | - name: Setup PHP 21 | uses: shivammathur/setup-php@master 22 | with: 23 | php-version: ${{ matrix.php-versions }} 24 | coverage: xdebug 25 | 26 | - name: Validate composer.json and composer.lock 27 | run: composer validate 28 | 29 | - name: Install dependencies 30 | run: composer install --prefer-dist --no-progress --no-suggest 31 | 32 | - name: Run test suite 33 | run: composer run-script test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | .DS_Store 5 | .php_cs.cache 6 | /build 7 | coverage 8 | .phpunit.result.cache 9 | /.idea 10 | build/report.junit.xml 11 | 12 | -------------------------------------------------------------------------------- /.php_cs: -------------------------------------------------------------------------------- 1 | exclude('vendor') 5 | ->in(__DIR__); 6 | 7 | return Symfony\CS\Config\Config::create() 8 | ->setUsingCache(true) 9 | ->level(Symfony\CS\FixerInterface::PSR2_LEVEL) 10 | ->fixers(array( 11 | 'psr0', 12 | 'encoding', 13 | 'short_tag', 14 | 'blankline_after_open_tag', 15 | 'namespace_no_leading_whitespace', 16 | 'no_blank_lines_after_class_opening', 17 | 'single_array_no_trailing_comma', 18 | 'no_empty_lines_after_phpdocs', 19 | 'concat_with_spaces', 20 | 'eof_ending', 21 | 'ordered_use', 22 | 'extra_empty_lines', 23 | 'single_line_after_imports', 24 | 'trailing_spaces', 25 | 'remove_lines_between_uses', 26 | 'return', 27 | 'indentation', 28 | 'linefeed', 29 | 'braces', 30 | 'visibility', 31 | 'unused_use', 32 | 'whitespacy_lines', 33 | 'php_closing_tag', 34 | 'phpdoc_order', 35 | 'phpdoc_params', 36 | 'phpdoc_trim', 37 | 'phpdoc_scalar', 38 | 'short_array_syntax', 39 | 'align_double_arrow', 40 | 'align_equals', 41 | 'lowercase_constants', 42 | 'lowercase_keywords', 43 | 'multiple_use', 44 | 'line_after_namespace', 45 | 'function_call_space', 46 | ))->finder($finder); 47 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.4 5 | - 5.5 6 | - 5.6 7 | 8 | before_script: 9 | - travis_retry composer self-update 10 | - travis_retry composer install --prefer-source --no-interaction 11 | 12 | after_script: 13 | - wget https://scrutinizer-ci.com/ocular.phar 14 | - php ocular.phar code-coverage:upload --format=php-clover coverage.clover 15 | 16 | script: phpunit --coverage-clover=coverage.clover 17 | 18 | matrix: 19 | fast_finish: true 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Maatwebsite 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "maatwebsite/laravel-sidebar", 3 | "description": "A sidebar builder for Laravel", 4 | "license": "MIT", 5 | "keywords": [ 6 | "laravel", 7 | "sidebar", 8 | "menu", 9 | "acp" 10 | ], 11 | "authors": [ 12 | { 13 | "name": "Maatwebsite.nl", 14 | "email": "patrick@maatwebsite.nl" 15 | } 16 | ], 17 | "require": { 18 | "php": "^8.1", 19 | "illuminate/cache": "~10.0|~11.0", 20 | "illuminate/container": "~10.0|~11.0", 21 | "illuminate/contracts": "~10.0|~11.0", 22 | "illuminate/support": "~10.0|~11.0", 23 | "illuminate/routing": "~10.0|~11.0", 24 | "illuminate/view": "~10.0|~11.0" 25 | }, 26 | "require-dev": { 27 | "mockery/mockery": "^1.6", 28 | "phpunit/phpunit": "^10.4" 29 | }, 30 | "autoload": { 31 | "psr-4": { 32 | "Maatwebsite\\Sidebar\\": "src/" 33 | } 34 | }, 35 | "autoload-dev": { 36 | "psr-4": { 37 | "Maatwebsite\\Sidebar\\Tests\\": "tests/" 38 | } 39 | }, 40 | "extra": { 41 | "laravel": { 42 | "providers": [ 43 | "Maatwebsite\\Sidebar\\SidebarServiceProvider" 44 | ] 45 | } 46 | }, 47 | "config": { 48 | "preferred-install": "dist" 49 | }, 50 | "scripts": { 51 | "test": "vendor/bin/phpunit", 52 | "test-coverage": "vendor/bin/phpunit --coverage-html coverage" 53 | }, 54 | "minimum-stability": "dev", 55 | } 56 | -------------------------------------------------------------------------------- /config/sidebar.php: -------------------------------------------------------------------------------- 1 | [ 16 | 'method' => null, 17 | 'duration' => 1440 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | View Name 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Choose a view to use to render the sidebar. 26 | | Built in templates are: 27 | | 28 | | - 'AdminLTE2' - Bootstrap 3 29 | | - 'AdminLTE3' - Bootstrap 4 30 | | - 'AdminLTE4' - Bootstrap 5 (coming soon) 31 | | Or a custom view, for example 'custom'. [by default AdminLTE2 will be used so you can publish and modify it as you wish ]. 32 | | 33 | */ 34 | 'view' => 'AdminLTE2', 35 | ]; 36 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests/ 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | ./src 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # WARNING! Not actively supported or maintained. 2 | 3 | # Laravel Sidebar 4 | 5 | [![GitHub release](https://img.shields.io/github/release/Maatwebsite/Laravel-Sidebar.svg?style=flat)](https://packagist.org/packages/maatwebsite/laravel-sidebar) 6 | [![Travis](https://img.shields.io/travis/Maatwebsite/Laravel-Sidebar.svg?style=flat)](https://travis-ci.org/Maatwebsite/Laravel-Sidebar) 7 | [![Scrutinizer](https://img.shields.io/scrutinizer/g/Maatwebsite/Laravel-Sidebar.svg?style=flat)](https://github.com/Maatwebsite/Laravel-Sidebar) 8 | [![Packagist](https://img.shields.io/packagist/dd/Maatwebsite/Laravel-Sidebar.svg?style=flat)](https://packagist.org/packages/maatwebsite/laravel-sidebar) 9 | [![Packagist](https://img.shields.io/packagist/dm/Maatwebsite/Laravel-Sidebar.svg?style=flat)](https://packagist.org/packages/maatwebsite/laravel-sidebar) 10 | [![Packagist](https://img.shields.io/packagist/dt/Maatwebsite/Laravel-Sidebar.svg?style=flat)](https://packagist.org/packages/maatwebsite/laravel-sidebar) 11 | 12 | ## Installation 13 | 14 | Require this package in your `composer.json` and run `composer update`. 15 | 16 | ```php 17 | "maatwebsite/laravel-sidebar": "~2.1" 18 | ``` 19 | 20 | After updating composer, add the ServiceProvider to the providers array in `config/app.php` 21 | 22 | ```php 23 | 'Maatwebsite\Sidebar\SidebarServiceProvider', 24 | ``` 25 | 26 | Add the package middleware to `App\Http\Kernel`: 27 | 28 | ```php 29 | `'Maatwebsite\Sidebar\Middleware\ResolveSidebars'` 30 | ``` 31 | 32 | To publish the default views use: 33 | 34 | ```php 35 | php artisan vendor:publish --tag="views" 36 | ``` 37 | 38 | To publish the config use: 39 | 40 | ```php 41 | php artisan vendor:publish --tag="config" 42 | ``` 43 | 44 | ## Documentation 45 | 46 | See the wiki: https://github.com/Maatwebsite/Laravel-Sidebar/wiki 47 | 48 | ## Contributing 49 | 50 | **ALL contributions** should be made to appropriate branch (e.g. 2.0 for 2.0.* bug fixes). Bug fixes should never be sent to the master branch. 51 | 52 | We follow PSR-1, PSR-2 and PSR-4 coding styles. 53 | 54 | Added or fixed functionality should be backed with unit tests. 55 | 56 | ## License 57 | 58 | This package is licensed under MIT. You are free to use it in personal and commercial projects. 59 | -------------------------------------------------------------------------------- /resources/views/adminlte-2/append.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/views/adminlte-2/badge.blade.php: -------------------------------------------------------------------------------- 1 | {{ $badge->getValue() }} 2 | -------------------------------------------------------------------------------- /resources/views/adminlte-2/group.blade.php: -------------------------------------------------------------------------------- 1 | @if($group->shouldShowHeading()) 2 | 3 | @endif 4 | 5 | @foreach($items as $item) 6 | {!! $item !!} 7 | @endforeach 8 | -------------------------------------------------------------------------------- /resources/views/adminlte-2/item.blade.php: -------------------------------------------------------------------------------- 1 |
  • 2 | getNewTab())target="_blank"@endif> 3 | 4 | {{ $item->getName() }} 5 | 6 | @foreach($badges as $badge) 7 | {!! $badge !!} 8 | @endforeach 9 | 10 | @if($item->hasItems())@endif 11 | 12 | 13 | @foreach($appends as $append) 14 | {!! $append !!} 15 | @endforeach 16 | 17 | @if(count($items) > 0) 18 | 23 | @endif 24 |
  • 25 | -------------------------------------------------------------------------------- /resources/views/adminlte-2/menu.blade.php: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /resources/views/adminlte-3/append.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/views/adminlte-3/badge.blade.php: -------------------------------------------------------------------------------- 1 | {{ $badge->getValue() }} 2 | -------------------------------------------------------------------------------- /resources/views/adminlte-3/group.blade.php: -------------------------------------------------------------------------------- 1 | @if($group->shouldShowHeading()) 2 | 3 | @endif 4 | 5 | @foreach($items as $item) 6 | {!! $item !!} 7 | @endforeach 8 | -------------------------------------------------------------------------------- /resources/views/adminlte-3/item.blade.php: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /resources/views/adminlte-3/menu.blade.php: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/Append.php: -------------------------------------------------------------------------------- 1 | container = $container; 47 | } 48 | 49 | /** 50 | * @return null|string 51 | */ 52 | public function getName() 53 | { 54 | return $this->name; 55 | } 56 | 57 | /** 58 | * @param null|string $name 59 | * 60 | * @return $this 61 | */ 62 | public function name($name) 63 | { 64 | $this->name = $name; 65 | 66 | return $this; 67 | } 68 | 69 | /** 70 | * @return string 71 | */ 72 | public function getIcon() 73 | { 74 | return $this->icon; 75 | } 76 | 77 | /** 78 | * @param string $icon 79 | * 80 | * @return $this 81 | */ 82 | public function icon($icon) 83 | { 84 | $this->icon = $icon; 85 | 86 | return $this; 87 | } 88 | 89 | public function __serialize():array 90 | { 91 | return [ 92 | 'name' => $this->name, 93 | 'url' => $this->url, 94 | 'icon' => $this->icon, 95 | ]; 96 | } 97 | 98 | public function __unserialize(array $data): void 99 | { 100 | $this->name = $data['name']; 101 | $this->url = $data['url']; 102 | $this->icon = $data['icon']; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/Domain/DefaultBadge.php: -------------------------------------------------------------------------------- 1 | container = $container; 45 | } 46 | 47 | /** 48 | * @return mixed 49 | */ 50 | public function getValue() 51 | { 52 | return $this->value; 53 | } 54 | 55 | /** 56 | * @param mixed $value 57 | * 58 | * @return Badge 59 | */ 60 | public function setValue($value) 61 | { 62 | $this->value = $value; 63 | 64 | return $this; 65 | } 66 | 67 | /** 68 | * @return string 69 | */ 70 | public function getClass() 71 | { 72 | return $this->class; 73 | } 74 | 75 | /** 76 | * @param string $class 77 | * 78 | * @return Badge 79 | */ 80 | public function setClass($class) 81 | { 82 | $this->class = $class; 83 | 84 | return $this; 85 | } 86 | 87 | public function __serialize():array 88 | { 89 | return [ 90 | 'value' => $this->value, 91 | 'class' => $this->class, 92 | ]; 93 | } 94 | 95 | public function __unserialize(array $data): void 96 | { 97 | $this->value = $data['value']; 98 | $this->class = $data['class']; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Domain/DefaultGroup.php: -------------------------------------------------------------------------------- 1 | container = $container; 56 | $this->items = new Collection(); 57 | } 58 | 59 | /** 60 | * @param string $name 61 | * 62 | * @return Group 63 | */ 64 | public function name($name) 65 | { 66 | $this->name = $name; 67 | 68 | return $this; 69 | } 70 | 71 | /** 72 | * @return string 73 | */ 74 | public function getName() 75 | { 76 | return $this->name; 77 | } 78 | 79 | /** 80 | * @param int $weight 81 | * 82 | * @return Group 83 | */ 84 | public function weight($weight) 85 | { 86 | if (!is_int($weight)) { 87 | throw new LogicException('Weight should be an integer'); 88 | } 89 | 90 | $this->weight = $weight; 91 | 92 | return $this; 93 | } 94 | 95 | /** 96 | * @return int 97 | */ 98 | public function getWeight() 99 | { 100 | return $this->weight; 101 | } 102 | 103 | /** 104 | * @param bool $hide 105 | * 106 | * @return Group 107 | */ 108 | public function hideHeading($hide = true) 109 | { 110 | $this->heading = !$hide; 111 | 112 | return $this; 113 | } 114 | 115 | /** 116 | * @return bool 117 | */ 118 | public function shouldShowHeading() 119 | { 120 | return $this->heading ? true : false; 121 | } 122 | 123 | public function __serialize():array 124 | { 125 | return [ 126 | 'name' => $this->name, 127 | 'items' => $this->items, 128 | 'weight' => $this->weight, 129 | 'heading' => $this->heading, 130 | ]; 131 | } 132 | 133 | public function __unserialize(array $data): void 134 | { 135 | $this->name = $data['name']; 136 | $this->items = $data['items']; 137 | $this->weight = $data['weight']; 138 | $this->heading = $data['heading']; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/Domain/DefaultItem.php: -------------------------------------------------------------------------------- 1 | container = $container; 94 | $this->items = new Collection(); 95 | $this->badges = new Collection(); 96 | $this->appends = new Collection(); 97 | } 98 | 99 | /** 100 | * @return string 101 | */ 102 | public function getName() 103 | { 104 | return $this->name; 105 | } 106 | 107 | /** 108 | * @param mixed $name 109 | * 110 | * @return Item $item 111 | */ 112 | public function name($name) 113 | { 114 | $this->name = $name; 115 | 116 | return $this; 117 | } 118 | 119 | /** 120 | * @param int $weight 121 | * 122 | * @return Item 123 | */ 124 | public function weight($weight) 125 | { 126 | if (!is_int($weight)) { 127 | throw new LogicException('Weight should be an integer'); 128 | } 129 | 130 | $this->weight = $weight; 131 | 132 | return $this; 133 | } 134 | 135 | /** 136 | * @return int 137 | */ 138 | public function getWeight() 139 | { 140 | return $this->weight; 141 | } 142 | 143 | /** 144 | * @return string 145 | */ 146 | public function getIcon() 147 | { 148 | return $this->icon; 149 | } 150 | 151 | /** 152 | * @param string $icon 153 | * 154 | * @return Item 155 | */ 156 | public function icon($icon) 157 | { 158 | $this->icon = $icon; 159 | 160 | return $this; 161 | } 162 | 163 | /** 164 | * @return string 165 | */ 166 | public function getToggleIcon() 167 | { 168 | return $this->toggleIcon; 169 | } 170 | 171 | /** 172 | * @param string $icon 173 | * 174 | * @return Item 175 | */ 176 | public function toggleIcon($icon) 177 | { 178 | $this->toggleIcon = $icon; 179 | 180 | return $this; 181 | } 182 | 183 | /** 184 | * @param callable|null|string $callbackOrValue 185 | * @param string|null $className 186 | * 187 | * @return Badge 188 | */ 189 | public function badge($callbackOrValue = null, $className = null) 190 | { 191 | $badge = $this->container->make('Maatwebsite\Sidebar\Badge'); 192 | 193 | if (is_callable($callbackOrValue)) { 194 | $this->call($callbackOrValue, $badge); 195 | } elseif ($callbackOrValue) { 196 | $badge->setValue($callbackOrValue); 197 | } 198 | 199 | if ($className) { 200 | $badge->setClass($className); 201 | } 202 | 203 | $this->addBadge($badge); 204 | 205 | return $badge; 206 | } 207 | 208 | /** 209 | * @param Badge $badge 210 | * 211 | * @return Badge 212 | */ 213 | public function addBadge(Badge $badge) 214 | { 215 | $this->badges->push($badge); 216 | 217 | return $badge; 218 | } 219 | 220 | /** 221 | * @return Collection|Badge[] 222 | */ 223 | public function getBadges() 224 | { 225 | return $this->badges; 226 | } 227 | 228 | /** 229 | * @param null $callbackOrRoute 230 | * @param string|null $icon 231 | * @param null $name 232 | * 233 | * @return Append 234 | */ 235 | public function append($callbackOrRoute = null, $icon = null, $name = null) 236 | { 237 | $append = $this->container->make('Maatwebsite\Sidebar\Append'); 238 | 239 | if (is_callable($callbackOrRoute)) { 240 | $this->call($callbackOrRoute, $append); 241 | } elseif ($callbackOrRoute) { 242 | $append->route($callbackOrRoute); 243 | } 244 | 245 | if ($name) { 246 | $append->name($name); 247 | } 248 | 249 | if ($icon) { 250 | $append->icon($icon); 251 | } 252 | 253 | $this->addAppend($append); 254 | 255 | return $append; 256 | } 257 | 258 | /** 259 | * @param Append $append 260 | * 261 | * @return Append 262 | */ 263 | public function addAppend(Append $append) 264 | { 265 | $this->appends->push($append); 266 | 267 | return $append; 268 | } 269 | 270 | /** 271 | * @return Collection|Append[] 272 | */ 273 | public function getAppends() 274 | { 275 | return $this->appends; 276 | } 277 | 278 | /** 279 | * @param string $path 280 | * 281 | * @return $this 282 | */ 283 | public function isActiveWhen($path) 284 | { 285 | // Remove unwanted chars 286 | $path = ltrim($path, '/'); 287 | $path = rtrim($path, '/'); 288 | $path = rtrim($path, '?'); 289 | 290 | $this->activeWhen = $path; 291 | 292 | return $this; 293 | } 294 | 295 | /** 296 | * @return string 297 | */ 298 | public function getActiveWhen() 299 | { 300 | return $this->activeWhen; 301 | } 302 | 303 | /** 304 | * @param bool $newTab 305 | * 306 | * @return $this 307 | */ 308 | public function isNewTab($newTab = true) 309 | { 310 | $this->newTab = $newTab; 311 | 312 | return $this; 313 | } 314 | 315 | /** 316 | * @return bool 317 | */ 318 | public function getNewTab() 319 | { 320 | return $this->newTab; 321 | } 322 | 323 | /** 324 | * @param string $itemClass 325 | * 326 | * @return $this 327 | */ 328 | public function setItemClass($itemClass) 329 | { 330 | $this->itemClass = $itemClass; 331 | 332 | return $this; 333 | } 334 | 335 | /** 336 | * @return string 337 | */ 338 | public function getItemClass() 339 | { 340 | return $this->itemClass; 341 | } 342 | 343 | public function __serialize():array 344 | { 345 | return [ 346 | 'name' => $this->name, 347 | 'weight' => $this->weight, 348 | 'url' => $this->url, 349 | 'icon' => $this->icon, 350 | 'toggleIcon' => $this->toggleIcon, 351 | 'items' => $this->items, 352 | 'badges' => $this->badges, 353 | 'appends' => $this->appends, 354 | 'authorized' => $this->authorized, 355 | ]; 356 | } 357 | 358 | public function __unserialize(array $data): void 359 | { 360 | $this->name = $data['name']; 361 | $this->weight = $data['weight']; 362 | $this->url = $data['url']; 363 | $this->icon = $data['icon']; 364 | $this->toggleIcon = $data['toggleIcon']; 365 | $this->items = $data['items']; 366 | $this->badges = $data['badges']; 367 | $this->appends = $data['appends']; 368 | $this->authorized = $data['authorized']; 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /src/Domain/DefaultMenu.php: -------------------------------------------------------------------------------- 1 | container = $container; 43 | $this->groups = new Collection(); 44 | } 45 | 46 | /** 47 | * Init a new group or call an existing group and add it to the menu 48 | * 49 | * @param $name 50 | * @param callable $callback 51 | * 52 | * @return Group 53 | */ 54 | public function group($name, Closure $callback = null) 55 | { 56 | if ($this->groups->has($name)) { 57 | $group = $this->groups->get($name); 58 | } else { 59 | $group = $this->container->make('Maatwebsite\Sidebar\Group'); 60 | $group->name($name); 61 | } 62 | 63 | $this->call($callback, $group); 64 | 65 | $this->addGroup($group); 66 | 67 | return $group; 68 | } 69 | 70 | /** 71 | * Add a Group instance to the Menu 72 | * 73 | * @param Group $group 74 | * 75 | * @return $this 76 | */ 77 | public function addGroup(Group $group) 78 | { 79 | $this->groups->put($group->getName(), $group); 80 | 81 | return $this; 82 | } 83 | 84 | /** 85 | * Get collection of Group instances sorted by their weight 86 | * @return Collection|Group[] 87 | */ 88 | public function getGroups() 89 | { 90 | return $this->groups->sortBy(function (Group $group) { 91 | return $group->getWeight(); 92 | }); 93 | } 94 | 95 | /** 96 | * Add another Menu instance and combined the two 97 | * Groups with the same name get combined, but 98 | * inherit each other's items 99 | * 100 | * @param Menu $menu 101 | * 102 | * @return Menu $menu 103 | */ 104 | public function add(Menu $menu) 105 | { 106 | foreach ($menu->getGroups() as $group) { 107 | if ($this->groups->has($group->getName())) { 108 | $existingGroup = $this->groups->get($group->getName()); 109 | 110 | $group->hideHeading(!$group->shouldShowHeading()); 111 | 112 | foreach ($group->getItems() as $item) { 113 | $existingGroup->addItem($item); 114 | } 115 | } else { 116 | $this->addGroup($group); 117 | } 118 | } 119 | 120 | return $this; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/Domain/Events/FlushesSidebarCache.php: -------------------------------------------------------------------------------- 1 | manager = $manager; 27 | $this->container = $container; 28 | } 29 | 30 | /** 31 | * Flush the sidebar cache 32 | */ 33 | public function handle() 34 | { 35 | $this->container->call([ 36 | $this->manager, 37 | 'flush' 38 | ]); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Domain/Events/ShouldFlushCache.php: -------------------------------------------------------------------------------- 1 | container = $container; 22 | } 23 | 24 | /** 25 | * @param $name 26 | * 27 | * @throws LogicException 28 | * @return Sidebar 29 | */ 30 | public function resolve($name) 31 | { 32 | $sidebar = $this->container->make($name); 33 | 34 | if (!$sidebar instanceof Sidebar) { 35 | throw new LogicException('Your sidebar should implement the Sidebar interface'); 36 | } 37 | 38 | $sidebar->build(); 39 | 40 | return $sidebar; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Infrastructure/NullSidebarFlusher.php: -------------------------------------------------------------------------------- 1 | cache = $cache; 33 | $this->resolver = $resolver; 34 | $this->config = $config; 35 | } 36 | 37 | /** 38 | * @param $name 39 | * 40 | * @return Sidebar 41 | */ 42 | public function resolve($name) 43 | { 44 | $duration = $this->config->get('sidebar.cache.duration'); 45 | 46 | return $this->cache->remember(CacheKey::get($name), $duration, function () use ($name) { 47 | return $this->resolver->resolve($name); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Infrastructure/StaticSidebarFlusher.php: -------------------------------------------------------------------------------- 1 | cache = $cache; 20 | } 21 | 22 | /** 23 | * Flush 24 | * 25 | * @param $name 26 | */ 27 | public function flush($name) 28 | { 29 | $this->cache->forget(CacheKey::get($name)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Infrastructure/SupportsCacheTags.php: -------------------------------------------------------------------------------- 1 | getStore(), 'tags')) { 19 | throw new CacheTagsNotSupported('Cache tags are necessary to use this kind of caching. Consider using a different caching method'); 20 | } 21 | 22 | return true; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Infrastructure/UserBasedCacheResolver.php: -------------------------------------------------------------------------------- 1 | cache = $cache; 40 | $this->resolver = $resolver; 41 | $this->guard = $guard; 42 | $this->config = $config; 43 | } 44 | 45 | /** 46 | * @param $name 47 | * 48 | * @return Sidebar 49 | */ 50 | public function resolve($name) 51 | { 52 | if ((new SupportsCacheTags())->isSatisfiedBy($this->cache)) { 53 | $userId = $this->guard->check() ? $this->guard->user()->getAuthIdentifier() : null; 54 | $duration = $this->config->get('sidebar.cache.duration'); 55 | 56 | return $this->cache->tags(CacheKey::get($name))->remember(CacheKey::get($name, $userId), $duration, function () use ($name) { 57 | return $this->resolver->resolve($name); 58 | }); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Infrastructure/UserBasedSidebarFlusher.php: -------------------------------------------------------------------------------- 1 | cache = $cache; 20 | } 21 | 22 | /** 23 | * Flush 24 | * 25 | * @param $name 26 | */ 27 | public function flush($name) 28 | { 29 | if ((new SupportsCacheTags())->isSatisfiedBy($this->cache)) { 30 | $this->cache->tags(CacheKey::get($name))->flush(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Item.php: -------------------------------------------------------------------------------- 1 | manager = $manager; 21 | } 22 | 23 | /** 24 | * Handle an incoming request. 25 | * 26 | * @param \Illuminate\Http\Request $request 27 | * @param \Closure $next 28 | * 29 | * @return mixed 30 | */ 31 | public function handle($request, Closure $next) 32 | { 33 | $this->manager->resolve(); 34 | 35 | return $next($request); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Presentation/ActiveStateChecker.php: -------------------------------------------------------------------------------- 1 | getItems() as $child) { 19 | if ($this->isActive($child)) { 20 | return true; 21 | } 22 | } 23 | 24 | // Custom set active path 25 | if ($path = $item->getActiveWhen()) { 26 | return Request::is( 27 | $path 28 | ); 29 | } 30 | 31 | $path = ltrim(str_replace(url('/'), '', $item->getUrl()), '/'); 32 | 33 | return Request::is( 34 | $path, 35 | $path . '/*' 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Presentation/Illuminate/IlluminateAppendRenderer.php: -------------------------------------------------------------------------------- 1 | factory = $factory; 26 | } 27 | 28 | /** 29 | * @param Append $append 30 | * 31 | * @return \Illuminate\Contracts\View\View 32 | */ 33 | public function render(Append $append) 34 | { 35 | if ($append->isAuthorized()) { 36 | return $this->factory->make($this->view, [ 37 | 'append' => $append 38 | ])->render(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Presentation/Illuminate/IlluminateBadgeRenderer.php: -------------------------------------------------------------------------------- 1 | factory = $factory; 26 | } 27 | 28 | /** 29 | * @param Badge $badge 30 | * 31 | * @return \Illuminate\Contracts\View\View 32 | */ 33 | public function render(Badge $badge) 34 | { 35 | if ($badge->isAuthorized()) { 36 | return $this->factory->make($this->view, [ 37 | 'badge' => $badge 38 | ])->render(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Presentation/Illuminate/IlluminateGroupRenderer.php: -------------------------------------------------------------------------------- 1 | factory = $factory; 26 | } 27 | 28 | /** 29 | * @param Group $group 30 | * 31 | * @return \Illuminate\Contracts\View\View 32 | */ 33 | public function render(Group $group) 34 | { 35 | if ($group->isAuthorized()) { 36 | $items = []; 37 | foreach ($group->getItems() as $item) { 38 | $items[] = (new IlluminateItemRenderer($this->factory))->render($item); 39 | } 40 | 41 | return $this->factory->make($this->view, [ 42 | 'group' => $group, 43 | 'items' => $items 44 | ])->render(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Presentation/Illuminate/IlluminateItemRenderer.php: -------------------------------------------------------------------------------- 1 | factory = $factory; 27 | } 28 | 29 | /** 30 | * @param Item $item 31 | * 32 | * @return \Illuminate\Contracts\View\View 33 | */ 34 | public function render(Item $item) 35 | { 36 | if ($item->isAuthorized()) { 37 | $items = []; 38 | foreach ($item->getItems() as $child) { 39 | $items[] = (new IlluminateItemRenderer($this->factory))->render($child); 40 | } 41 | 42 | $badges = []; 43 | foreach ($item->getBadges() as $badge) { 44 | $badges[] = (new IlluminateBadgeRenderer($this->factory))->render($badge); 45 | } 46 | 47 | $appends = []; 48 | foreach ($item->getAppends() as $append) { 49 | $appends[] = (new IlluminateAppendRenderer($this->factory))->render($append); 50 | } 51 | 52 | return $this->factory->make($this->view, [ 53 | 'item' => $item, 54 | 'items' => $items, 55 | 'badges' => $badges, 56 | 'appends' => $appends, 57 | 'active' => (new ActiveStateChecker())->isActive($item), 58 | ])->render(); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Presentation/Illuminate/IlluminateSidebarRenderer.php: -------------------------------------------------------------------------------- 1 | factory = $factory; 27 | } 28 | 29 | /** 30 | * @param Sidebar $sidebar 31 | * 32 | * @return \Illuminate\Contracts\View\View 33 | */ 34 | public function render(Sidebar $sidebar) 35 | { 36 | $menu = $sidebar->getMenu(); 37 | 38 | if ($menu->isAuthorized()) { 39 | $groups = []; 40 | foreach ($menu->getGroups() as $group) { 41 | $groups[] = (new IlluminateGroupRenderer($this->factory))->render($group); 42 | } 43 | 44 | return $this->factory->make($this->view, [ 45 | 'groups' => $groups 46 | ]); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Presentation/SidebarRenderer.php: -------------------------------------------------------------------------------- 1 | container = $container; 34 | $this->resolver = $resolver; 35 | } 36 | 37 | /** 38 | * Register the sidebar 39 | * 40 | * @param $name 41 | * 42 | * @throws LogicException 43 | * @return $this 44 | */ 45 | public function register($name) 46 | { 47 | if (class_exists($name)) { 48 | $this->sidebars[] = $name; 49 | } else { 50 | throw new LogicException('Sidebar [' . $name . '] does not exist'); 51 | } 52 | 53 | return $this; 54 | } 55 | 56 | /** 57 | * Bind sidebar instances to the ioC 58 | */ 59 | public function resolve() 60 | { 61 | foreach ($this->sidebars as $name) { 62 | $sidebar = $this->resolver->resolve($name); 63 | 64 | $this->container->singleton($name, function () use ($sidebar) { 65 | return $sidebar; 66 | }); 67 | } 68 | } 69 | 70 | /** 71 | * @param SidebarFlusher $flusher 72 | */ 73 | public function flush(SidebarFlusher $flusher) 74 | { 75 | foreach ($this->sidebars as $name) { 76 | $flusher->flush($name); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/SidebarServiceProvider.php: -------------------------------------------------------------------------------- 1 | registerViews(); 30 | } 31 | 32 | /** 33 | * Register the service provider. 34 | * @return void 35 | */ 36 | public function register() 37 | { 38 | // Register config 39 | $this->registerConfig(); 40 | 41 | // Bind SidebarResolver 42 | $this->app->bind('Maatwebsite\Sidebar\Infrastructure\SidebarResolver', function (Application $app) { 43 | 44 | $resolver = SidebarResolverFactory::getClassName( 45 | $app['config']->get('sidebar.cache.method') 46 | ); 47 | 48 | return $app->make($resolver); 49 | }); 50 | 51 | // Bind SidebarFlusher 52 | $this->app->bind('Maatwebsite\Sidebar\Infrastructure\SidebarFlusher', function (Application $app) { 53 | 54 | $resolver = SidebarFlusherFactory::getClassName( 55 | $app['config']->get('sidebar.cache.method') 56 | ); 57 | 58 | return $app->make($resolver); 59 | }); 60 | 61 | // Bind manager 62 | $this->app->singleton('Maatwebsite\Sidebar\SidebarManager'); 63 | 64 | // Bind Menu 65 | $this->app->bind( 66 | 'Maatwebsite\Sidebar\Menu', 67 | 'Maatwebsite\Sidebar\Domain\DefaultMenu' 68 | ); 69 | 70 | // Bind Group 71 | $this->app->bind( 72 | 'Maatwebsite\Sidebar\Group', 73 | 'Maatwebsite\Sidebar\Domain\DefaultGroup' 74 | ); 75 | 76 | // Bind Item 77 | $this->app->bind( 78 | 'Maatwebsite\Sidebar\Item', 79 | 'Maatwebsite\Sidebar\Domain\DefaultItem' 80 | ); 81 | 82 | // Bind Badge 83 | $this->app->bind( 84 | 'Maatwebsite\Sidebar\Badge', 85 | 'Maatwebsite\Sidebar\Domain\DefaultBadge' 86 | ); 87 | 88 | // Bind Append 89 | $this->app->bind( 90 | 'Maatwebsite\Sidebar\Append', 91 | 'Maatwebsite\Sidebar\Domain\DefaultAppend' 92 | ); 93 | 94 | // Bind Renderer 95 | $this->app->bind( 96 | 'Maatwebsite\Sidebar\Presentation\SidebarRenderer', 97 | 'Maatwebsite\Sidebar\Presentation\Illuminate\IlluminateSidebarRenderer' 98 | ); 99 | } 100 | 101 | /** 102 | * Register views. 103 | * @return void 104 | */ 105 | protected function registerViews() 106 | { 107 | $view = match (config('sidebar.view')){ 108 | 'AdminLTE3' => 'adminlte-3', 109 | default => 'adminlte-2', 110 | }; 111 | 112 | $location = __DIR__ . "/../resources/views/{$view}"; 113 | 114 | $this->loadViewsFrom($location, $this->shortName); 115 | 116 | $this->publishes([ 117 | $location => base_path('resources/views/vendor/' . $this->shortName), 118 | ], 'sidebar-views'); 119 | } 120 | 121 | /** 122 | * Register config 123 | * @return void 124 | */ 125 | protected function registerConfig() 126 | { 127 | $location = __DIR__ . '/../config/' . $this->shortName . '.php'; 128 | 129 | $this->mergeConfigFrom( 130 | $location, $this->shortName 131 | ); 132 | 133 | $this->publishes([ 134 | $location => config_path($this->shortName . '.php'), 135 | ], 'sidebar-config'); 136 | } 137 | 138 | /** 139 | * Get the services provided by the provider. 140 | * @return array 141 | */ 142 | public function provides() 143 | { 144 | return [ 145 | 'Maatwebsite\Sidebar\Menu', 146 | 'Maatwebsite\Sidebar\Item', 147 | 'Maatwebsite\Sidebar\Group', 148 | 'Maatwebsite\Sidebar\Badge', 149 | 'Maatwebsite\Sidebar\Append', 150 | 'Maatwebsite\Sidebar\SidebarManager', 151 | 'Maatwebsite\Sidebar\Presentation\SidebarRenderer', 152 | 'Maatwebsite\Sidebar\Infrastructure\SidebarResolver' 153 | ]; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/Traits/AuthorizableTrait.php: -------------------------------------------------------------------------------- 1 | authorized; 19 | } 20 | 21 | /** 22 | * Authorize the group/item 23 | * 24 | * @param bool $state 25 | * 26 | * @return $this 27 | */ 28 | public function authorize($state = true) 29 | { 30 | $this->authorized = $state; 31 | 32 | return $this; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Traits/CacheableTrait.php: -------------------------------------------------------------------------------- 1 | getCacheables() as $cacheable) { 16 | $cacheables[$cacheable] = $this->{$cacheable}; 17 | } 18 | 19 | return serialize($cacheables); 20 | } 21 | 22 | /** 23 | * Constructs the object 24 | * @link http://php.net/manual/en/serializable.unserialize.php 25 | * 26 | * @param string $serialized The string representation of the object. 27 | * 28 | * @return void 29 | */ 30 | public function unserialize($serialized) 31 | { 32 | $data = unserialize($serialized); 33 | 34 | foreach ($data as $key => $value) { 35 | $this->{$key} = $value; 36 | } 37 | } 38 | 39 | /** 40 | * @return array 41 | */ 42 | public function getCacheables(): array 43 | { 44 | return $this->cacheables ?? ['menu']; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Traits/CallableTrait.php: -------------------------------------------------------------------------------- 1 | resolveMethodDependencies( 26 | [$caller], new ReflectionFunction($callback) 27 | ); 28 | call_user_func_array($callback, $parameters); 29 | } 30 | 31 | return $caller; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Traits/ItemableTrait.php: -------------------------------------------------------------------------------- 1 | items->has($name)) { 27 | $item = $this->items->get($name); 28 | } else { 29 | $item = $this->container->make('Maatwebsite\Sidebar\Item'); 30 | $item->name($name); 31 | } 32 | 33 | $this->call($callback, $item); 34 | 35 | $this->addItem($item); 36 | 37 | return $item; 38 | } 39 | 40 | /** 41 | * Add Item instance to Group 42 | * 43 | * @param Item $item 44 | * 45 | * @return Item 46 | */ 47 | public function addItem(Item $item) 48 | { 49 | $this->items->put($item->getName(), $item); 50 | 51 | return $this; 52 | } 53 | 54 | /** 55 | * @return Collection|Item[] 56 | */ 57 | public function getItems() 58 | { 59 | return $this->items->sortBy(function (Item $item) { 60 | return $item->getWeight(); 61 | }); 62 | } 63 | 64 | /** 65 | * Check if we have items 66 | * @return bool 67 | */ 68 | public function hasItems() 69 | { 70 | return count($this->items) > 0 ? true : false; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Traits/RouteableTrait.php: -------------------------------------------------------------------------------- 1 | url; 18 | } 19 | 20 | /** 21 | * @param string $url 22 | * 23 | * @return $this 24 | */ 25 | public function url($url) 26 | { 27 | $this->url = $url; 28 | 29 | return $this; 30 | } 31 | 32 | /** 33 | * @param $route 34 | * @param array $params 35 | * 36 | * @return $this 37 | */ 38 | public function route($route, $params = []) 39 | { 40 | $this->url( 41 | $this->container->make('url')->route($route, $params) 42 | ); 43 | 44 | return $this; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests/Domain/DefaultAppendTest.php: -------------------------------------------------------------------------------- 1 | container = m::mock('Illuminate\Contracts\Container\Container'); 25 | $this->append = new DefaultAppend($this->container); 26 | } 27 | 28 | public function test_can_instantiate_new_append() 29 | { 30 | $append = new DefaultAppend($this->container); 31 | 32 | $this->assertInstanceOf('Maatwebsite\Sidebar\Append', $append); 33 | } 34 | 35 | public function test_can_have_custom_appends() 36 | { 37 | $append = new StubAppend($this->container); 38 | 39 | $this->assertInstanceOf('Maatwebsite\Sidebar\Append', $append); 40 | } 41 | 42 | public function test_can_set_name() 43 | { 44 | $this->append->name('name'); 45 | $this->assertEquals('name', $this->append->getName()); 46 | } 47 | 48 | public function test_can_set_url() 49 | { 50 | $this->append->url('url'); 51 | $this->assertEquals('url', $this->append->getUrl()); 52 | } 53 | 54 | public function test_can_set_icon() 55 | { 56 | $this->append->icon('icon'); 57 | $this->assertEquals('icon', $this->append->getIcon()); 58 | } 59 | 60 | public function test_append_can_be_cached() 61 | { 62 | $this->append->name('name'); 63 | $this->append->url('url'); 64 | $this->append->icon('icon'); 65 | 66 | $serialized = serialize($this->append); 67 | $unserialized = unserialize($serialized); 68 | 69 | $this->assertInstanceOf('Maatwebsite\Sidebar\Append', $unserialized); 70 | $this->assertEquals('name', $unserialized->getName()); 71 | $this->assertEquals('url', $unserialized->getUrl()); 72 | $this->assertEquals('icon', $unserialized->getIcon()); 73 | } 74 | } 75 | 76 | class StubAppend extends DefaultAppend implements Append 77 | { 78 | } 79 | -------------------------------------------------------------------------------- /tests/Domain/DefaultBadgeTest.php: -------------------------------------------------------------------------------- 1 | container = m::mock('Illuminate\Contracts\Container\Container'); 25 | $this->badge = new DefaultBadge($this->container); 26 | } 27 | 28 | public function test_can_instantiate_new_badge() 29 | { 30 | $badge = new DefaultBadge($this->container); 31 | 32 | $this->assertInstanceOf('Maatwebsite\Sidebar\Badge', $badge); 33 | } 34 | 35 | public function test_can_have_custom_badges() 36 | { 37 | $badge = new StubBadge($this->container); 38 | 39 | $this->assertInstanceOf('Maatwebsite\Sidebar\Badge', $badge); 40 | } 41 | 42 | public function test_can_set_value() 43 | { 44 | $this->badge->setValue('value'); 45 | $this->assertEquals('value', $this->badge->getValue()); 46 | } 47 | 48 | public function test_can_set_class() 49 | { 50 | $this->badge->setClass('class'); 51 | $this->assertEquals('class', $this->badge->getClass()); 52 | } 53 | 54 | public function test_badge_can_be_cached() 55 | { 56 | $this->badge->setValue('value'); 57 | $this->badge->setClass('class'); 58 | 59 | $serialized = serialize($this->badge); 60 | $unserialized = unserialize($serialized); 61 | 62 | $this->assertInstanceOf('Maatwebsite\Sidebar\Badge', $unserialized); 63 | $this->assertEquals('value', $unserialized->getValue()); 64 | $this->assertEquals('class', $unserialized->getClass()); 65 | } 66 | } 67 | 68 | class StubBadge extends DefaultBadge implements Badge 69 | { 70 | } 71 | -------------------------------------------------------------------------------- /tests/Domain/DefaultGroupTest.php: -------------------------------------------------------------------------------- 1 | container = m::mock('Illuminate\Contracts\Container\Container'); 26 | $this->group = new DefaultGroup($this->container); 27 | } 28 | 29 | public function test_can_instantiate_new_group() 30 | { 31 | $group = new DefaultGroup($this->container); 32 | 33 | $this->assertInstanceOf('Maatwebsite\Sidebar\Group', $group); 34 | } 35 | 36 | public function test_can_have_custom_groups() 37 | { 38 | $group = new StubGroup($this->container); 39 | 40 | $this->assertInstanceOf('Maatwebsite\Sidebar\Group', $group); 41 | } 42 | 43 | public function test_group_can_be_cached() 44 | { 45 | $item = new DefaultItem($this->container); 46 | $this->group->addItem($item); 47 | 48 | $serialized = serialize($this->group); 49 | $unserialized = unserialize($serialized); 50 | 51 | $this->assertInstanceOf('Maatwebsite\Sidebar\Group', $unserialized); 52 | $this->assertInstanceOf('Illuminate\Support\Collection', $unserialized->getItems()); 53 | 54 | $this->assertCount(1, $unserialized->getItems()); 55 | } 56 | } 57 | 58 | class StubGroup extends DefaultGroup implements Group 59 | { 60 | } 61 | -------------------------------------------------------------------------------- /tests/Domain/DefaultItemTest.php: -------------------------------------------------------------------------------- 1 | container = m::mock('Illuminate\Contracts\Container\Container'); 27 | $this->item = new DefaultItem($this->container); 28 | } 29 | 30 | public function test_can_instantiate_new_item() 31 | { 32 | $item = new DefaultItem($this->container); 33 | 34 | $this->assertInstanceOf('Maatwebsite\Sidebar\Item', $item); 35 | } 36 | 37 | public function test_can_have_custom_items() 38 | { 39 | $item = new StubItem($this->container); 40 | 41 | $this->assertInstanceOf('Maatwebsite\Sidebar\Item', $item); 42 | } 43 | 44 | public function test_can_set_name() 45 | { 46 | $this->item->name('name'); 47 | $this->assertEquals('name', $this->item->getName()); 48 | } 49 | 50 | public function test_can_set_url() 51 | { 52 | $this->item->url('url'); 53 | $this->assertEquals('url', $this->item->getUrl()); 54 | } 55 | 56 | public function test_can_set_icon() 57 | { 58 | $this->item->icon('icon'); 59 | $this->assertEquals('icon', $this->item->getIcon()); 60 | } 61 | 62 | public function test_can_set_weight() 63 | { 64 | $this->item->weight(1); 65 | $this->assertEquals(1, $this->item->getWeight()); 66 | } 67 | 68 | public function test_item_can_be_cached() 69 | { 70 | $item = new DefaultItem($this->container); 71 | $this->item->addItem($item); 72 | 73 | $this->item->name('name'); 74 | $this->item->icon('icon'); 75 | $this->item->weight(1); 76 | $this->item->url('url'); 77 | 78 | $serialized = serialize($this->item); 79 | $unserialized = unserialize($serialized); 80 | 81 | $this->assertInstanceOf('Maatwebsite\Sidebar\Item', $unserialized); 82 | $this->assertInstanceOf('Illuminate\Support\Collection', $unserialized->getItems()); 83 | $this->assertCount(1, $unserialized->getItems()); 84 | $this->assertEquals('name', $unserialized->getName()); 85 | $this->assertEquals('icon', $unserialized->getIcon()); 86 | $this->assertEquals(1, $unserialized->getWeight()); 87 | $this->assertEquals('url', $unserialized->getUrl()); 88 | } 89 | 90 | public function test_can_add_a_badge_instance() 91 | { 92 | $badge = new DefaultBadge($this->container); 93 | $badge->setValue(1); 94 | $this->item->addBadge($badge); 95 | 96 | $this->assertInstanceOf('Illuminate\Support\Collection', $this->item->getBadges()); 97 | $this->assertCount(1, $this->item->getBadges()); 98 | $this->assertEquals('1', $this->item->getBadges()->first()->getValue()); 99 | } 100 | 101 | public function test_can_add_a_badge() 102 | { 103 | $mock = $this->mockContainerMakeForBadge(); 104 | $mock->shouldReceive('setValue'); 105 | $mock->shouldReceive('setClass'); 106 | $mock->shouldReceive('getValue')->andReturn(1); 107 | $mock->shouldReceive('getClass')->andReturn('className'); 108 | 109 | $this->item->badge(1, 'className'); 110 | 111 | $this->assertInstanceOf('Illuminate\Support\Collection', $this->item->getBadges()); 112 | $this->assertCount(1, $this->item->getBadges()); 113 | $this->assertEquals(1, $this->item->getBadges()->first()->getValue()); 114 | $this->assertEquals('className', $this->item->getBadges()->first()->getClass()); 115 | } 116 | 117 | public function test_can_add_a_append_instance() 118 | { 119 | $append = new DefaultAppend($this->container); 120 | $append->url('url'); 121 | $this->item->addAppend($append); 122 | 123 | $this->assertInstanceOf('Illuminate\Support\Collection', $this->item->getAppends()); 124 | $this->assertCount(1, $this->item->getAppends()); 125 | $this->assertEquals('url', $this->item->getAppends()->first()->getUrl()); 126 | } 127 | 128 | public function test_can_add_a_append() 129 | { 130 | $mock = $this->mockContainerMakeForAppend(); 131 | $mock->shouldReceive('route'); 132 | $mock->shouldReceive('icon'); 133 | $mock->shouldReceive('name'); 134 | $mock->shouldReceive('getUrl')->andReturn('url'); 135 | $mock->shouldReceive('getIcon')->andReturn('icon'); 136 | $mock->shouldReceive('getName')->andReturn('name'); 137 | 138 | $this->item->append('route', 'icon', 'name'); 139 | 140 | $this->assertInstanceOf('Illuminate\Support\Collection', $this->item->getAppends()); 141 | $this->assertCount(1, $this->item->getAppends()); 142 | $this->assertEquals('url', $this->item->getAppends()->first()->getUrl()); 143 | $this->assertEquals('icon', $this->item->getAppends()->first()->getIcon()); 144 | $this->assertEquals('name', $this->item->getAppends()->first()->getName()); 145 | } 146 | 147 | protected function mockContainerMakeForBadge() 148 | { 149 | $mock = m::mock('Maatwebsite\Sidebar\Badge'); 150 | 151 | $this->container->shouldReceive('make')->with('Maatwebsite\Sidebar\Badge')->andReturn( 152 | $mock 153 | ); 154 | 155 | return $mock; 156 | } 157 | 158 | protected function mockContainerMakeForAppend() 159 | { 160 | $mock = m::mock('Maatwebsite\Sidebar\Append'); 161 | 162 | $this->container->shouldReceive('make')->with('Maatwebsite\Sidebar\Append')->andReturn( 163 | $mock 164 | ); 165 | 166 | return $mock; 167 | } 168 | } 169 | 170 | class StubItem extends DefaultItem implements Item 171 | { 172 | } 173 | -------------------------------------------------------------------------------- /tests/Domain/DefaultMenuTest.php: -------------------------------------------------------------------------------- 1 | container = m::mock('Illuminate\Contracts\Container\Container'); 26 | $this->menu = new DefaultMenu($this->container); 27 | } 28 | 29 | public function test_can_instantiate_new_menu() 30 | { 31 | $menu = new DefaultMenu($this->container); 32 | 33 | $this->assertInstanceOf('Maatwebsite\Sidebar\Menu', $menu); 34 | } 35 | 36 | public function test_can_have_custom_menus() 37 | { 38 | $menu = new StubMenu($this->container); 39 | 40 | $this->assertInstanceOf('Maatwebsite\Sidebar\Menu', $menu); 41 | } 42 | 43 | public function test_menu_can_be_cached() 44 | { 45 | $this->markTestSkipped("'Exception: Serialization of 'ReflectionClass' is not allowed'"); 46 | $this->mockContainerMake(); 47 | $this->menu->group('test'); 48 | $this->menu->group('test2'); 49 | 50 | $serialized = serialize($this->menu); 51 | $unserialized = unserialize($serialized); 52 | 53 | $this->assertInstanceOf('Maatwebsite\Sidebar\Menu', $unserialized); 54 | $this->assertInstanceOf('Illuminate\Support\Collection', $unserialized->getGroups()); 55 | $this->assertCount(2, $unserialized->getGroups()); 56 | 57 | } 58 | 59 | public function test_can_add_group_instance_to_menu() 60 | { 61 | $group = new DefaultGroup($this->container); 62 | $group->name('test'); 63 | 64 | $this->menu->addGroup($group); 65 | 66 | $this->assertInstanceOf('Illuminate\Support\Collection', $this->menu->getGroups()); 67 | $this->assertCount(1, $this->menu->getGroups()); 68 | $this->assertEquals('test', $this->menu->getGroups()->first()->getName()); 69 | } 70 | 71 | public function test_can_add_group_to_menu() 72 | { 73 | $this->mockContainerMake(); 74 | 75 | $this->menu->group('test'); 76 | 77 | $this->assertInstanceOf('Illuminate\Support\Collection', $this->menu->getGroups()); 78 | $this->assertCount(1, $this->menu->getGroups()); 79 | } 80 | 81 | public function test_can_add_existing_group_to_menu_wont_duplicate() 82 | { 83 | $this->mockContainerMake('test'); 84 | 85 | $this->menu->group('test'); 86 | $this->menu->group('test'); 87 | $this->menu->group('test'); 88 | 89 | $this->assertInstanceOf('Illuminate\Support\Collection', $this->menu->getGroups()); 90 | $this->assertCount(1, $this->menu->getGroups()); 91 | } 92 | 93 | public function test_get_groups_returns_sorted_groups() 94 | { 95 | $group = new DefaultGroup($this->container); 96 | $group->name('secondItem'); 97 | $group->weight(2); 98 | 99 | $this->menu->addGroup($group); 100 | 101 | $group = new DefaultGroup($this->container); 102 | $group->name('firstItem'); 103 | $group->weight(1); 104 | 105 | $this->menu->addGroup($group); 106 | 107 | $this->assertInstanceOf('Illuminate\Support\Collection', $this->menu->getGroups()); 108 | $this->assertCount(2, $this->menu->getGroups()); 109 | 110 | $this->assertEquals('firstItem', $this->menu->getGroups()->first()->getName()); 111 | } 112 | 113 | public function test_can_combined_menu_instances() 114 | { 115 | // Add group to original menu 116 | $group = new DefaultGroup($this->container); 117 | $group->name('existing'); 118 | $group->weight(2); 119 | $this->menu->addGroup($group); 120 | 121 | // Init new menu 122 | $menu = new DefaultMenu($this->container); 123 | 124 | // Add a new one 125 | $group = new DefaultGroup($this->container); 126 | $group->name('new menu group'); 127 | $group->weight(1); 128 | $menu->addGroup($group); 129 | 130 | // Append to existing 131 | $group = new DefaultGroup($this->container); 132 | $group->name('existing'); 133 | $group->weight(2); 134 | $menu->addGroup($group); 135 | 136 | $this->menu->add($menu); 137 | 138 | $this->assertInstanceOf('Illuminate\Support\Collection', $this->menu->getGroups()); 139 | $this->assertCount(2, $this->menu->getGroups()); 140 | 141 | $this->assertEquals('new menu group', $this->menu->getGroups()->first()->getName()); 142 | } 143 | 144 | protected function mockContainerMake($name = null, $weight = null) 145 | { 146 | $mock = m::mock('Maatwebsite\Sidebar\Group'); 147 | $mock->shouldReceive('name'); 148 | $mock->shouldReceive('getName')->andReturn($name); 149 | $mock->shouldReceive('getWeight')->andReturn($weight); 150 | 151 | $this->container->shouldReceive('make')->with('Maatwebsite\Sidebar\Group')->andReturn( 152 | $mock 153 | ); 154 | 155 | return $mock; 156 | } 157 | } 158 | 159 | class StubMenu extends DefaultMenu implements Menu 160 | { 161 | } 162 | -------------------------------------------------------------------------------- /tests/SidebarExtenderTest.php: -------------------------------------------------------------------------------- 1 | container = m::mock('Illuminate\Contracts\Container\Container'); 27 | $this->menu = new DefaultMenu($this->container); 28 | } 29 | 30 | public function test_a_sidebar_can_be_extended_with_an_extender() 31 | { 32 | $group = new DefaultGroup($this->container); 33 | $group->name('original'); 34 | $this->menu->addGroup($group); 35 | 36 | $extender = new StubSidebarExtender(); 37 | $extender->extendWith($this->menu); 38 | 39 | $this->menu->add( 40 | $extender->extendWith($this->menu) 41 | ); 42 | 43 | $this->assertInstanceOf('Maatwebsite\Sidebar\Menu', $this->menu); 44 | $this->assertInstanceOf('Illuminate\Support\Collection', $this->menu->getGroups()); 45 | $this->assertCount(2, $this->menu->getGroups()); 46 | } 47 | } 48 | 49 | class StubSidebarExtender implements SidebarExtender 50 | { 51 | /** 52 | * @param Menu $menu 53 | * 54 | * @return Menu 55 | */ 56 | public function extendWith(Menu $menu) 57 | { 58 | $container = m::mock('Illuminate\Contracts\Container\Container'); 59 | 60 | $group = new DefaultGroup($container); 61 | $group->name('new from extender'); 62 | $menu->addGroup($group); 63 | 64 | $group = new DefaultGroup($container); 65 | $group->name('original'); 66 | $menu->addGroup($group); 67 | 68 | return $menu; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /tests/Traits/AuthorizableTraitTest.php: -------------------------------------------------------------------------------- 1 | routeable = new StubAuthorizableClass(); 18 | } 19 | 20 | public function test_can_authorize() 21 | { 22 | $this->routeable->authorize(true); 23 | $this->assertTrue($this->routeable->isAuthorized()); 24 | 25 | $this->routeable->authorize(false); 26 | $this->assertFalse($this->routeable->isAuthorized()); 27 | } 28 | } 29 | 30 | class StubAuthorizableClass 31 | { 32 | use AuthorizableTrait; 33 | } 34 | -------------------------------------------------------------------------------- /tests/Traits/ItemableTraitTest.php: -------------------------------------------------------------------------------- 1 | container = m::mock('Illuminate\Contracts\Container\Container'); 29 | $this->itemable = new StubItemableClass($this->container); 30 | } 31 | 32 | public function test_can_add_an_item_instance() 33 | { 34 | $item = new DefaultItem($this->container); 35 | $item->name('itemName'); 36 | $this->itemable->addItem($item); 37 | 38 | $this->assertInstanceOf('Illuminate\Support\Collection', $this->itemable->getItems()); 39 | $this->assertCount(1, $this->itemable->getItems()); 40 | $this->assertEquals('itemName', $this->itemable->getItems()->first()->getName()); 41 | } 42 | 43 | public function test_can_add_an_item() 44 | { 45 | $this->mockContainerMake('itemName'); 46 | $this->itemable->item('itemName'); 47 | 48 | $this->assertInstanceOf('Illuminate\Support\Collection', $this->itemable->getItems()); 49 | $this->assertCount(1, $this->itemable->getItems()); 50 | $this->assertEquals('itemName', $this->itemable->getItems()->first()->getName()); 51 | } 52 | 53 | public function test_can_check_if_has_items() 54 | { 55 | $this->assertFalse($this->itemable->hasItems()); 56 | 57 | $item = new DefaultItem($this->container); 58 | $this->itemable->addItem($item); 59 | 60 | $this->assertTrue($this->itemable->hasItems()); 61 | } 62 | 63 | public function test_get_items_sorts_items_by_weight() 64 | { 65 | $item = new DefaultItem($this->container); 66 | $item->name('second item'); 67 | $item->weight(2); 68 | $this->itemable->addItem($item); 69 | 70 | $item = new DefaultItem($this->container); 71 | $this->itemable->addItem($item); 72 | $item->name('first item'); 73 | $item->weight(1); 74 | 75 | $this->assertCount(2, $this->itemable->getItems()); 76 | $this->assertEquals('first item', $this->itemable->getItems()->first()->getName()); 77 | } 78 | 79 | protected function mockContainerMake($name = null, $weight = null) 80 | { 81 | $mock = m::mock('Maatwebsite\Sidebar\Item'); 82 | $mock->shouldReceive('name'); 83 | $mock->shouldReceive('getName')->andReturn($name); 84 | $mock->shouldReceive('getWeight')->andReturn($weight); 85 | 86 | $this->container->shouldReceive('make')->with('Maatwebsite\Sidebar\Item')->andReturn( 87 | $mock 88 | ); 89 | 90 | return $mock; 91 | } 92 | } 93 | 94 | class StubItemableClass implements Itemable 95 | { 96 | use ItemableTrait, CallableTrait; 97 | 98 | /** 99 | * @var Container 100 | */ 101 | private $container; 102 | 103 | /** 104 | * @param Container $container 105 | */ 106 | public function __construct(Container $container) 107 | { 108 | $this->container = $container; 109 | $this->items = new Collection(); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /tests/Traits/RouteableTraitTest.php: -------------------------------------------------------------------------------- 1 | container = m::mock('Illuminate\Contracts\Container\Container'); 26 | $this->routeable = new StubRouteableClass($this->container); 27 | } 28 | 29 | public function test_can_set_url() 30 | { 31 | $this->routeable->url('url'); 32 | 33 | $this->assertEquals('url', $this->routeable->getUrl()); 34 | } 35 | 36 | public function test_can_set_route() 37 | { 38 | $urlMock = m::mock('Illuminate\Contracts\Routing\UrlGenerator'); 39 | $urlMock->shouldReceive('route')->andReturn('url'); 40 | 41 | $this->container->shouldReceive('make')->andReturn($urlMock); 42 | 43 | $this->routeable->route('route'); 44 | 45 | $this->assertEquals('url', $this->routeable->getUrl()); 46 | } 47 | } 48 | 49 | class StubRouteableClass 50 | { 51 | use RouteableTrait; 52 | 53 | /** 54 | * @var Container 55 | */ 56 | private $container; 57 | 58 | /** 59 | * @param Container $container 60 | */ 61 | public function __construct(Container $container) 62 | { 63 | $this->container = $container; 64 | } 65 | } 66 | --------------------------------------------------------------------------------