├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml ├── src └── Coderabbi │ └── Virtuoso │ ├── Composer.php │ ├── ComposerServiceProvider.php │ └── CompositeComposer.php └── tests └── Coderabbi └── Virtuoso └── Tests ├── ComposerStub.php ├── CompositeComposerStub.php └── CompositeComposerTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !.travis.yml 4 | !composer.json 5 | !composer.lock 6 | !LICENSE 7 | !phpunit.xml 8 | !README.md 9 | !/src 10 | !/tests 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.4 5 | - 5.5 6 | - 5.6 7 | - hhvm 8 | 9 | before_script: 10 | - composer self-update 11 | - composer install --prefer-source --no-interaction --dev 12 | 13 | script: phpunit -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Yitzchok Willroth (@coderabbi) 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![image](https://dl.dropboxusercontent.com/s/em253abjckwr6k4/Virtuoso.png) 2 | 3 | # Laravel Virtuoso 4 | 5 | #### Laravel Composable View Composers Package 6 | 7 | Increase flexibility and reduce code duplication by easily composing complex View Composers from simple 8 | component Composers without unnecessary indirection or boilerplate code. 9 | 10 | ## Background 11 | 12 | In many of our projects, the same data is often repeated on multiple pages. This presents the challenge 13 | of preparing this data in our Controllers and providing it to our various Views without an undue amount 14 | of code repetition. Laravel provides us with the ability to limit this potential repetition through an 15 | abstraction known as the View Composer. A View Composer allows you to abstract this code to a single 16 | location and make it available to multiple Views. A View Composer is simply a piece of code which is 17 | bound to a View and executed whenever that View is requested. 18 | 19 | An example View Composer from the Laravel documentation: 20 | 21 | ``` php 22 | View::composer('profile', function($view) 23 | { 24 | $view->with('count', User::count()); 25 | } 26 | ``` 27 | 28 | A View Composer may also be created as a Class: 29 | 30 | ``` php 31 | with('count', User::count()); 39 | } 40 | 41 | } 42 | ``` 43 | 44 | Of course, when a View Composer is created as a Class, the association between the View Composer and the 45 | View must be registered, either using the following syntax: 46 | 47 | ``` php 48 | View::composer('profile', 'UserCountComposer'); 49 | ``` 50 | or via a Service Provider: 51 | 52 | ``` php 53 | app['view']->composer('profile', 'My\Project\Name\Space\UserCountComposer'); 64 | } 65 | 66 | } 67 | ``` 68 | 69 | Data provided to the View by a View Composer may be accessed as if it had been provided by the Controller: 70 | 71 | ``` php 72 | 77 | ``` 78 | 79 | #### Additional Resources 80 | 81 | * View Composers in the [Laravel Documentation](http://laravel.com/docs/responses#view-composers). 82 | * View Composers at [Laracasts](https://laracasts.com/lessons/view-composers). 83 | 84 | ## Application 85 | 86 | Unfortunately, the out-of-the-box functionality of Laravel View Composers can be somewhat cumbersome. 87 | 88 | If we choose to go with the ```View::composer()``` format, our bootstrap files will quickly become overblown 89 | and unwieldy. On the other hand, if we choose a Class based approach, in addition to creating the View Composer Classes, 90 | we need to register our Composer/View associations. This presents its own challenges. We might choose to create a 91 | Service Provider to register each of our Composer/View associations, resulting in repetitive boilerplate code as our 92 | Service Providers proliferate. Alternately, we might choose to create a single Service Provider to register all of our 93 | Composer/View associations, but this merely simplifies our bootstrap files at the expense of an unwieldy Service Provider. Perhaps 94 | the best choice is to create a Service Provider for each View and within it register its View Composer associations, but 95 | this requires a fair amount of boilerplate and dramatically increases the indirection which already exists with View Composers. 96 | 97 | This is the challenge that Virtuoso is intended to meet. Virtuoso allows you to easily create simple, single-focused 98 | View Composers for your data and leverage composition when providing data to your Views by associating one or more View 99 | Composers with a single View via a "Composite Composer" as needed _without any unnecessary indirection or repetitive 100 | boilerplate code_ - all of your Composer/View associations can be found in a single location and all without writing any 101 | new Service Providers! 102 | 103 | ## Requirements 104 | 105 | Virtuoso supports the following versions of PHP: 106 | 107 | * PHP 5.4.\* 108 | * PHP 5.5.\* 109 | * PHP 5.6.\* 110 | * HHVM 111 | 112 | and the following versions of Laravel: 113 | 114 | * Laravel 4.1.\* 115 | * Laravel 4.2.\* 116 | 117 | ## Installation 118 | 119 | First, install Virtuoso through Composer (Virtuoso on [Packagist](https://packagist.org/packages/coderabbi/virtuoso)), 120 | either by adding it to the Require Array of your `composer.json`: 121 | 122 | ```js 123 | "require": { 124 | "coderabbi/virtuoso": "0.*" 125 | } 126 | ``` 127 | 128 | or from the Command Line: 129 | 130 | ``` bash 131 | php composer.phar require coderabbi/virtuoso:0.* 132 | ``` 133 | 134 | Next, update `app/config/app.php` to include a reference to this package's Service Provider in the 135 | Providers Array: 136 | 137 | ``` php 138 | 'providers' => array( 139 | 'Coderabbi\Virtuoso\ComposerServiceProvider' 140 | ) 141 | ``` 142 | 143 | Finally, update `app\config\view.php` to include the Composers Array: 144 | 145 | ``` php 146 | 'composers' => array ( 147 | ) 148 | ``` 149 | 150 | ## Usage 151 | 152 | #### Simple View Composers 153 | 154 | First, create your View Composer as you normally would (make sure to implement the Composer Interface): 155 | 156 | ``` php 157 | with('myData', $this->getMyData()); 168 | } 169 | 170 | private function getMyData() 171 | { 172 | // do your thing here 173 | } 174 | 175 | } 176 | ``` 177 | 178 | > Ideally, you should limit the data provided by each Composer to it's simplest, most cohesive unit. This 179 | > will allow you to compose Composite View Composers for your Views more easily. 180 | 181 | Next, associate the View (full path within the View Directory specified in `app/config/view.php` 182 | using dot notation) with your Simple View Composer (fully qualified Class Name including Namespace) 183 | by adding it to the Composers Array in `app\config\view.php`: 184 | 185 | ``` php 186 | 'composers' => array ( 187 | 'partials.header' => 'My\Project\Name\Space\MyFirstSimpleComposer', 188 | ) 189 | ``` 190 | 191 | That's it! Virtuoso will take care of registering the View/Composer associations for you - no new Service Providers 192 | required! 193 | 194 | You may access data provided by the Simple View Composer from the View as you normally would. 195 | 196 | #### Composite View Composers 197 | 198 | First, create the simple View Composers which will together comprise the Composite View Composer as above (but do not 199 | associate them with your View in the Composer Array in `app\config\view.php`). 200 | 201 | Next, create your Composite View Composer (make sure to extend CompositeComposer) and add the component View 202 | Composers to its `$composers` array: 203 | 204 | ``` php 205 | array ( 228 | 'partials.header' => 'My\Project\Name\Space\MyFirstCompositeComposer', 229 | ) 230 | ``` 231 | 232 | That's it! Virtuoso will take care of registering the individual View/Composer associations for you - no new Service 233 | Providers Required! 234 | 235 | You may access data provided by the Composite View Composer from the View as you normally would. 236 | 237 | ## Roadmap 238 | 239 | The addition of tests will bring the package to v1.0. It's a very simple package designed to address a single 240 | limitation in the standard implementations of Laravel View Composers so at this time I have no further plans 241 | for the package beyond that version. You are welcome to submit Issues or Pull Requests if you are so inclined; 242 | I will give my full attention to each. 243 | 244 | ## License 245 | 246 | This package is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT). 247 | Further details may be found in the [LICENSE](https://github.com/coderabbi/virtuoso/blob/master/LICENSE) file. 248 | 249 | ## Author 250 | 251 | Follow [@coderabbi](http://twitter.com/coderabbi) on Twitter. -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coderabbi/virtuoso", 3 | "description": "Laravel Composable View Composers Package - Increase flexibility and reduce code duplication by easily composing complex View Composers from simple component Composers without unnecessary indirection or boilerplate code.", 4 | "keywords": ["laravel", "composer", "composers", "view", "views", "viewcomposer", "viewcomposers"], 5 | "license": "MIT", 6 | "authors": [{ 7 | "name": "Yitzchok Willroth (@coderabbi)", 8 | "email": "coderabbi@gmail.com" 9 | }], 10 | "require": { 11 | "php": ">=5.4.0", 12 | "laravel/framework": "4.*" 13 | }, 14 | "require-dev": { 15 | "phpunit/phpunit": "~4.2" 16 | }, 17 | "autoload": { 18 | "psr-0": { 19 | "Coderabbi\\Virtuoso": "src/" 20 | } 21 | }, 22 | "autoload-dev": { 23 | "psr-0": { 24 | "Coderabbi\\Virtuoso\\Tests": "tests/" 25 | } 26 | }, 27 | "minimum-stability": "stable" 28 | } 29 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Coderabbi/Virtuoso/Composer.php: -------------------------------------------------------------------------------- 1 | 4 | * @copyright Yitzchok Willroth (@coderabbi) 5 | * 6 | * @package Coderabbi\Virtuoso 7 | */ 8 | 9 | 10 | namespace Coderabbi\Virtuoso; 11 | 12 | 13 | /** 14 | * Interface Composer 15 | * 16 | * @package Coderabbi\Virtuoso 17 | */ 18 | interface Composer 19 | { 20 | 21 | /** 22 | * Compose View 23 | * 24 | * @access public 25 | * @param string $view 26 | */ 27 | public function compose($view); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/Coderabbi/Virtuoso/ComposerServiceProvider.php: -------------------------------------------------------------------------------- 1 | 4 | * @copyright Yitzchok Willroth (@coderabbi) 5 | * 6 | * @package Coderabbi\Virtuoso 7 | */ 8 | 9 | 10 | namespace Coderabbi\Virtuoso; 11 | 12 | 13 | use Illuminate\Support\ServiceProvider; 14 | 15 | 16 | /** 17 | * Class ComposerServiceProvider 18 | * 19 | * @package Coderabbi\Virtuoso 20 | * @final 21 | */ 22 | final class ComposerServiceProvider 23 | extends ServiceProvider 24 | { 25 | 26 | /** 27 | * Configuration String 28 | */ 29 | const CONFIG_STRING = 'view.composers'; 30 | 31 | 32 | /** 33 | * Register View Composer Collection 34 | * 35 | * @access public 36 | */ 37 | public function register() 38 | { 39 | $configs = $this->getComposerConfigs(); 40 | 41 | if (count($configs)) 42 | { 43 | $this->registerComposers($configs); 44 | } 45 | } 46 | 47 | 48 | /** 49 | * Get Composer Configs 50 | * 51 | * @access private 52 | * @return array 53 | */ 54 | private function getComposerConfigs() 55 | { 56 | return $this->app['config']->get(self::CONFIG_STRING); 57 | } 58 | 59 | 60 | /** 61 | * Register Individual Composers 62 | * 63 | * @access private 64 | * @param array $configs 65 | */ 66 | private function registerComposers(array $configs) 67 | { 68 | foreach ($configs as $view => $composer) 69 | { 70 | $this->app->view->composer($view, $composer); 71 | } 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/Coderabbi/Virtuoso/CompositeComposer.php: -------------------------------------------------------------------------------- 1 | 4 | * @copyright Yitzchok Willroth (@coderabbi) 5 | * 6 | * @package Coderabbi\Virtuoso 7 | */ 8 | 9 | 10 | namespace Coderabbi\Virtuoso; 11 | 12 | 13 | use Coderabbi\Virtuoso\Composer; 14 | use Illuminate\Foundation\Application; 15 | 16 | 17 | /** 18 | * Class CompositeComposer 19 | * 20 | * @package Coderabbi\Virtuoso 21 | * @abstract 22 | */ 23 | abstract class CompositeComposer 24 | implements Composer 25 | { 26 | 27 | /** 28 | * Application 29 | * 30 | * @access private 31 | * @var Application 32 | */ 33 | private $app; 34 | 35 | 36 | /** 37 | * Composers 38 | * 39 | * @access protected 40 | * @var array 41 | */ 42 | protected $composers = array(); 43 | 44 | 45 | /** 46 | * Constructor 47 | * 48 | * @access public 49 | * @return self 50 | */ 51 | public function __construct(Application $app) 52 | { 53 | $this->app = $app; 54 | } 55 | 56 | 57 | /** 58 | * Compose View 59 | * 60 | * @access public 61 | * @param string $view 62 | */ 63 | public function compose($view) 64 | { 65 | foreach ($this->composers as $composer) 66 | { 67 | $this->app->make($composer)->compose($view); 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /tests/Coderabbi/Virtuoso/Tests/ComposerStub.php: -------------------------------------------------------------------------------- 1 | 4 | * @copyright Yitzchok Willroth (@coderabbi) 5 | * 6 | * @package Coderabbi\Virtuoso 7 | */ 8 | 9 | 10 | namespace Coderabbi\Virtuoso\Tests; 11 | 12 | 13 | use Coderabbi\Virtuoso\Composer; 14 | 15 | 16 | /** 17 | * Composer Stub for testing 18 | * 19 | * @package Coderabbi\Virtuoso\Tests 20 | */ 21 | class ComposerStub implements Composer 22 | { 23 | 24 | /** 25 | * View that was used in compose() 26 | * 27 | * @access public 28 | * @var string 29 | */ 30 | public $composedView; 31 | 32 | 33 | /** 34 | * Compose view. 35 | * Tracks view used for composition. 36 | * 37 | * @access public 38 | */ 39 | public function compose($view) 40 | { 41 | $this->composedView = $view; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /tests/Coderabbi/Virtuoso/Tests/CompositeComposerStub.php: -------------------------------------------------------------------------------- 1 | 4 | * @copyright Yitzchok Willroth (@coderabbi) 5 | * 6 | * @package Coderabbi\Virtuoso 7 | */ 8 | 9 | 10 | namespace Coderabbi\Virtuoso\Tests; 11 | 12 | 13 | use Coderabbi\Virtuoso\CompositeComposer; 14 | 15 | 16 | /** 17 | * CompositeComposer Stub for testing 18 | * 19 | * @package Coderabbi\Virtuoso\Tests 20 | */ 21 | class CompositeComposerStub extends CompositeComposer 22 | { 23 | 24 | /** 25 | * Set array of composers 26 | * 27 | * @access public 28 | */ 29 | public function setComposers($newComposers) 30 | { 31 | $this->composers = $newComposers; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /tests/Coderabbi/Virtuoso/Tests/CompositeComposerTest.php: -------------------------------------------------------------------------------- 1 | 4 | * @copyright Yitzchok Willroth (@coderabbi) 5 | * 6 | * @package Coderabbi\Virtuoso 7 | */ 8 | 9 | 10 | namespace Coderabbi\Virtuoso\Tests; 11 | 12 | 13 | use PHPUnit_Framework_TestCase; 14 | use Coderabbi\Virtuoso\CompositeComposer; 15 | use Coderabbi\Virtuoso\Tests\ComposerStub; 16 | use Coderabbi\Virtuoso\Tests\CompositeComposerStub; 17 | use Illuminate\Foundation\Application; 18 | 19 | 20 | /** 21 | * Tests behavior of CompositeComposer Abstract Class. 22 | * 23 | * @package Coderabbi\Virtuoso\Tests 24 | */ 25 | class CompositeComposerTest extends PHPUnit_Framework_TestCase 26 | { 27 | 28 | /** 29 | * Application 30 | * 31 | * @access private 32 | * @var Application 33 | */ 34 | private $app; 35 | 36 | 37 | /** 38 | * View Composers resolved by $app 39 | * 40 | * @access private 41 | * @var array 42 | */ 43 | private $composers; 44 | 45 | 46 | /** 47 | * PHPUnit Test Set Up 48 | * 49 | * @access public 50 | */ 51 | public function setUp() 52 | { 53 | $this->app = new Application; 54 | $this->composers = []; 55 | } 56 | 57 | 58 | /** @test */ 59 | public function it_composes_a_view_using_each_view_composer() 60 | { 61 | $view = 'view.test'; 62 | 63 | $this->app->bind('Coderabbi\\Virtuoso\\Tests\\ComposerStub', function() 64 | { 65 | $composer = new ComposerStub; 66 | $this->composers[] = $composer; 67 | return $composer; 68 | }); 69 | 70 | $compositeComposer = new CompositeComposerStub($this->app); 71 | $compositeComposer->setComposers([ 72 | 'Coderabbi\\Virtuoso\\Tests\\ComposerStub', 73 | 'Coderabbi\\Virtuoso\\Tests\\ComposerStub', 74 | ]); 75 | 76 | $compositeComposer->compose($view); 77 | 78 | // Should create two composers 79 | $this->assertEquals(2, count($this->composers)); 80 | 81 | // Each composer should compose $view 82 | foreach ($this->composers as $composer) { 83 | $this->assertEquals($view, $composer->composedView); 84 | } 85 | } 86 | 87 | } 88 | --------------------------------------------------------------------------------