├── .styleci.yml ├── tests ├── assets │ ├── exampleConfig.yml │ ├── src │ │ ├── SingleComponent │ │ │ ├── index.html │ │ │ ├── index.php │ │ │ └── functions.php │ │ └── ComponentWithArea │ │ │ └── index.php │ ├── exampleConfigWithSingleComponent.json │ └── exampleConfig.json ├── bootstrap.php ├── TestCase.php ├── TestHelper.php ├── test-helpers.php ├── test-render.php ├── test-flynt.php ├── test-defaults.php ├── test-componentManager.php └── test-buildConstructionPlan.php ├── .gitignore ├── .coveralls.yml ├── .github ├── CODE_OF_CONDUCT.md └── CONTRIBUTING.md ├── humbug.json.dist ├── .distignore ├── package.json ├── .editorconfig ├── phpcs.ruleset.xml ├── phpunit.xml.dist ├── composer.json ├── flynt-core.php ├── .scrutinizer.yml ├── LICENSE.md ├── .travis.yml ├── lib ├── Flynt │ ├── Helpers.php │ ├── ComponentManager.php │ ├── Defaults.php │ ├── Render.php │ └── BuildConstructionPlan.php └── Flynt.php ├── README.md ├── CHANGELOG.md └── composer.lock /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: psr2 2 | -------------------------------------------------------------------------------- /tests/assets/exampleConfig.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/assets/src/SingleComponent/index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/assets/src/SingleComponent/index.php: -------------------------------------------------------------------------------- 1 |
SingleComponent
2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Thumbs.db 3 | wp-cli.local.yml 4 | node_modules/ 5 | vendor/ 6 | humbuglog.txt 7 | -------------------------------------------------------------------------------- /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | coverage_clover: logs/clover.xml 3 | json_path: logs/coveralls-upload.json 4 | -------------------------------------------------------------------------------- /tests/assets/src/ComponentWithArea/index.php: -------------------------------------------------------------------------------- 1 |
ComponentWithArea
2 | -------------------------------------------------------------------------------- /tests/assets/exampleConfigWithSingleComponent.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SingleComponent", 3 | "customData": { 4 | "test": "result" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | [You can read the Flynt Code of Conduct here](https://github.com/flyntwp/guidelines/blob/master/CODE_OF_CONDUCT.md). 4 | -------------------------------------------------------------------------------- /humbug.json.dist: -------------------------------------------------------------------------------- 1 | { 2 | "source": { 3 | "directories": [ 4 | "lib" 5 | ] 6 | }, 7 | "timeout": 10, 8 | "logs": { 9 | "text": "humbuglog.txt" 10 | } 11 | } -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Flynt Core 2 | 3 | Thank you for taking the time to contribute! Read the [Flynt Contributing Guidelines here](https://github.com/flyntwp/guidelines/blob/master/CONTRIBUTING.md). 4 | -------------------------------------------------------------------------------- /tests/assets/src/SingleComponent/functions.php: -------------------------------------------------------------------------------- 1 | ", 6 | "license": "MIT", 7 | "devDependencies": { 8 | "conventional-github-releaser": "^1.1.3", 9 | "standard-version": "^4.0.0" 10 | }, 11 | "scripts": { 12 | "release": "standard-version", 13 | "releaseGithub": "conventional-github-releaser -p angular" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | # WordPress Coding Standards 5 | # https://make.wordpress.org/core/handbook/coding-standards/ 6 | 7 | root = true 8 | 9 | [*] 10 | charset = utf-8 11 | end_of_line = lf 12 | insert_final_newline = true 13 | trim_trailing_whitespace = true 14 | indent_style = tab 15 | indent_size = 4 16 | 17 | [{.jshintrc,*.json,*.yml}] 18 | indent_style = space 19 | indent_size = 2 20 | 21 | [{*.txt,wp-config-sample.php}] 22 | end_of_line = crlf 23 | -------------------------------------------------------------------------------- /phpcs.ruleset.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Coding Standards for Flynt Core 4 | 5 | . 6 | 7 | 8 | 9 | */node_modules/* 10 | */vendor/* 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | ./tests/ 12 | 13 | 14 | 15 | 16 | ./lib/ 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flyntwp/flynt-core", 3 | "type": "wordpress-plugin", 4 | "description": "The Flynt Core Plugin provides a small public interface, combined with several WordPress hooks, to achieve the main principles of the Flynt Framework.", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "bleech", 9 | "email": "hello@bleech.de" 10 | } 11 | ], 12 | "homepage": "https://github.com/flyntwp/flynt-core", 13 | "require": { 14 | "composer/installers": "~1.0" 15 | }, 16 | "require-dev": { 17 | "phpunit/phpunit": "^5.6", 18 | "brain/monkey": "1.*", 19 | "squizlabs/php_codesniffer": "~2.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | andReturnUsing(['\\Flynt\\Tests\\TestHelper', 'getTemplateDirectory']); 19 | 20 | Functions::expect('trailingslashit') 21 | ->andReturnUsing(['\\Flynt\\Tests\\TestHelper', 'trailingSlashIt']); 22 | } 23 | 24 | protected function tearDown() 25 | { 26 | Monkey::tearDownWP(); 27 | parent::tearDown(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /flynt-core.php: -------------------------------------------------------------------------------- 1 | 1) { 30 | return self::extractNestedDataFromArray($args); 31 | } else { 32 | return $args[0]; 33 | } 34 | } 35 | 36 | protected static function accessArrayOrObject($key, $data) 37 | { 38 | $output = ''; 39 | if (is_array($key) || is_object($key)) { 40 | $output = $key; 41 | } elseif (is_array($data) && array_key_exists($key, $data)) { 42 | $output = $data[$key]; 43 | } elseif (is_object($data) && property_exists($data, $key)) { 44 | $output = $data->$key; 45 | } 46 | return $output; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/Flynt.php: -------------------------------------------------------------------------------- 1 | registerComponent($componentName, $componentPath); 40 | } 41 | 42 | function registerComponents($components = []) 43 | { 44 | $componentManager = ComponentManager::getInstance(); 45 | array_walk($components, function ($componentPath, $componentName) use ($componentManager) { 46 | if (is_int($componentName)) { 47 | $componentName = $componentPath; 48 | $componentPath = null; 49 | } else { 50 | $componentPath = (isset($componentPath)) ? $componentPath : null; 51 | } 52 | $componentManager->registerComponent($componentName, $componentPath); 53 | }); 54 | } 55 | -------------------------------------------------------------------------------- /tests/TestHelper.php: -------------------------------------------------------------------------------- 1 | $componentName, 13 | 'customData' => [ 14 | 'test0' => 0, 15 | 'test1' => 'string', 16 | 'test2' => [ 17 | 'something strange' 18 | ], 19 | 'duplicate' => 'newValue' 20 | ], 21 | 'areas' => [] 22 | ]; 23 | } 24 | 25 | // how to use: TestHelper::getCustomComponent('Component', ['name', 'dataFilter']) 26 | public static function getCustomComponent($componentName = 'Component', $config = []) 27 | { 28 | return array_filter(self::getCompleteComponent($componentName), function ($key) use ($config) { 29 | return in_array($key, $config); 30 | }, ARRAY_FILTER_USE_KEY); 31 | } 32 | 33 | public static function getComponentIndexPath($componentName) 34 | { 35 | return self::getComponentPath(null, $componentName) . '/index.php'; 36 | } 37 | 38 | public static function getConfigPath() 39 | { 40 | return __DIR__ . "/assets/"; 41 | } 42 | 43 | public static function getComponentsPath() 44 | { 45 | return __DIR__ . '/assets/src/'; 46 | } 47 | 48 | public static function getComponentPath($componentPath, $componentName) 49 | { 50 | if (is_null($componentPath)) { 51 | return __DIR__ . '/assets/src/' . $componentName; 52 | } 53 | return $componentPath; 54 | } 55 | 56 | public static function getTemplateDirectory() 57 | { 58 | return __DIR__ . "/assets"; 59 | } 60 | 61 | public static function trailingSlashIt($string) 62 | { 63 | return rtrim($string, '/\\') . '/'; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/test-helpers.php: -------------------------------------------------------------------------------- 1 | $bar 27 | ]; 28 | $arr = [ 29 | 'foo' => $foo 30 | ]; 31 | $fooObj = (object) $foo; 32 | $obj = (object) [ 33 | 'foo' => $fooObj 34 | ]; 35 | $value = Helpers::extractNestedDataFromArray([null]); 36 | $this->assertEquals($value, ''); 37 | $value = Helpers::extractNestedDataFromArray(['string']); 38 | $this->assertEquals($value, 'string'); 39 | $value = Helpers::extractNestedDataFromArray(['stringA', 'stringB']); 40 | $this->assertEquals($value, ''); 41 | $value = Helpers::extractNestedDataFromArray(['stringA', null, 'stringB']); 42 | $this->assertEquals($value, ''); 43 | $value = Helpers::extractNestedDataFromArray([$arr, 'boo']); 44 | $this->assertEquals($value, ''); 45 | $value = Helpers::extractNestedDataFromArray([$arr, 'foo']); 46 | $this->assertEquals($value, $foo); 47 | $value = Helpers::extractNestedDataFromArray([$arr, 'foo', 'bar']); 48 | $this->assertEquals($value, $bar); 49 | $value = Helpers::extractNestedDataFromArray([[], $arr, 'foo']); 50 | $this->assertEquals($value, $foo); 51 | $value = Helpers::extractNestedDataFromArray([$arr]); 52 | $this->assertEquals($value, $arr); 53 | $value = Helpers::extractNestedDataFromArray([$arr, $foo]); 54 | $this->assertEquals($value, $foo); 55 | $value = Helpers::extractNestedDataFromArray([$obj, 'foo']); 56 | $this->assertEquals($value, $fooObj); 57 | $value = Helpers::extractNestedDataFromArray([$obj, 'foo', 'bar']); 58 | $this->assertEquals($value, $bar); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/Flynt/ComponentManager.php: -------------------------------------------------------------------------------- 1 | isRegistered($componentName)) { 40 | trigger_error("Component {$componentName} is already registered!", E_USER_WARNING); 41 | return false; 42 | } 43 | 44 | // register component / require functions.php 45 | $componentPath = trailingslashit(apply_filters('Flynt/componentPath', $componentPath, $componentName)); 46 | 47 | // add component to internal list (array) 48 | $this->add($componentName, $componentPath); 49 | 50 | do_action('Flynt/registerComponent', $componentName); 51 | do_action("Flynt/registerComponent?name={$componentName}", $componentName); 52 | 53 | return true; 54 | } 55 | 56 | public function getComponentFilePath($componentName, $fileName = 'index.php') 57 | { 58 | $componentDir = $this->getComponentDirPath($componentName); 59 | 60 | if (false === $componentDir) { 61 | return false; 62 | } 63 | 64 | // dir path already has a trailing slash 65 | $filePath = $componentDir . $fileName; 66 | 67 | return is_file($filePath) ? $filePath : false; 68 | } 69 | 70 | public function getComponentDirPath($componentName) 71 | { 72 | $dirPath = $this->get($componentName); 73 | 74 | // check if dir exists 75 | if (!is_dir($dirPath)) { 76 | return false; 77 | } 78 | 79 | return $dirPath; 80 | } 81 | 82 | protected function add($name, $path) 83 | { 84 | $this->components[$name] = $path; 85 | return true; 86 | } 87 | 88 | public function get($componentName) 89 | { 90 | // check if component exists / is registered 91 | if (!$this->isRegistered($componentName)) { 92 | trigger_error("Cannot get component: Component '{$componentName}' is not registered!", E_USER_WARNING); 93 | return false; 94 | } 95 | 96 | return $this->components[$componentName]; 97 | } 98 | 99 | public function remove($componentName) 100 | { 101 | unset($this->components[$componentName]); 102 | } 103 | 104 | public function getAll() 105 | { 106 | return $this->components; 107 | } 108 | 109 | public function removeAll() 110 | { 111 | $this->components = []; 112 | } 113 | 114 | public function isRegistered($componentName) 115 | { 116 | return array_key_exists($componentName, $this->components); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /lib/Flynt/Defaults.php: -------------------------------------------------------------------------------- 1 | getComponentFilePath($componentName); 43 | $output = self::renderFile($componentData, $areaHtml, $filePath); 44 | } 45 | return $output; 46 | } 47 | 48 | public static function setComponentPath($componentPath, $componentName) 49 | { 50 | if (is_null($componentPath)) { 51 | $componentPath = self::getComponentsDirectory() . '/' . $componentName; 52 | } 53 | return $componentPath; 54 | } 55 | 56 | public static function getComponentsDirectory() 57 | { 58 | return get_template_directory() . '/' . self::COMPONENT_DIR; 59 | } 60 | 61 | // this action needs to be removed by the user if they want to overwrite this functionality 62 | public static function loadFunctionsFile($componentName) 63 | { 64 | $componentManager = ComponentManager::getInstance(); 65 | $filePath = $componentManager->getComponentFilePath($componentName, 'functions.php'); 66 | if (false !== $filePath) { 67 | require_once $filePath; 68 | } 69 | } 70 | 71 | protected static function renderFile($componentData, $areaHtml, $filePath) 72 | { 73 | if (!is_file($filePath)) { 74 | trigger_error("Template not found: {$filePath}", E_USER_WARNING); 75 | return ''; 76 | } 77 | 78 | $area = function ($areaName) use ($areaHtml) { 79 | if (array_key_exists($areaName, $areaHtml)) { 80 | return $areaHtml[$areaName]; 81 | } 82 | }; 83 | 84 | $data = function () use ($componentData) { 85 | $args = func_get_args(); 86 | array_unshift($args, $componentData); 87 | return Helpers::extractNestedDataFromArray($args); 88 | }; 89 | 90 | ob_start(); 91 | require $filePath; 92 | $output = ob_get_contents(); 93 | ob_get_clean(); 94 | 95 | return $output; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /lib/Flynt/Render.php: -------------------------------------------------------------------------------- 1 | 'test' 45 | ]], 46 | [[ 47 | 'data' => [] 48 | ]], 49 | [[ 50 | 'name' => 'test', 51 | 'data' => 'dataNotArray' 52 | ]], 53 | [[ 54 | 'name' => [], 55 | 'data' => 'dataNotArray' 56 | ]], 57 | [[ 58 | 'name' => 'test', 59 | 'data' => [], 60 | 'areas' => [ 61 | [] 62 | ] 63 | ]], 64 | [[ 65 | 'name' => 'test', 66 | 'data' => [], 67 | 'areas' => [ 68 | 'testArea' => [ 69 | 'test' 70 | ] 71 | ] 72 | ]], 73 | [[ 74 | 'name' => 'test', 75 | 'data' => [], 76 | 'areas' => [ 77 | 'testArea' => [ 78 | 'name' => 'test', 79 | 'data' => [] 80 | ] 81 | ] 82 | ]] 83 | ]; 84 | } 85 | 86 | /** 87 | * @dataProvider badValues 88 | */ 89 | public function testShowWarningWhenConstructionPlanIsInvalid($badValue) 90 | { 91 | $this->expectException('PHPUnit_Framework_Error_Warning'); 92 | $cp = Render::fromConstructionPlan($badValue); 93 | } 94 | 95 | /** 96 | * @dataProvider badValues 97 | */ 98 | public function testReturnsEmptyStringWhenConstructionPlanIsInvalid($badValue) 99 | { 100 | $cp = @Render::fromConstructionPlan($badValue); 101 | $this->assertEquals($cp, ''); 102 | } 103 | 104 | public function testAppliesCustomHtmlHook() 105 | { 106 | // test whether custom html can be used 107 | $componentName = 'SingleComponent'; 108 | $cp = [ 109 | 'name' => $componentName, 110 | 'data' => [] 111 | ]; 112 | 113 | $shouldBeHtml = "
{$componentName} After Filter Hook
\n"; 114 | 115 | Filters::expectApplied('Flynt/renderComponent') 116 | ->once() 117 | ->with(Mockery::mustBe(null), Mockery::type('string'), Mockery::type('array'), Mockery::type('array')) 118 | ->andReturn($shouldBeHtml); 119 | 120 | $html = Render::fromConstructionPlan($cp); 121 | $this->assertEquals($html, $shouldBeHtml); 122 | } 123 | 124 | public function testAppliesCustomHtmlHookToANestedComponent() 125 | { 126 | $parentComponentName = 'ComponentWithArea'; 127 | $childComponentName = 'SingleComponent'; 128 | 129 | // test whether custom html can be used 130 | $cp = [ 131 | 'name' => $parentComponentName, 132 | 'data' => [], 133 | 'areas' => [ 134 | 'area51' => [ 135 | [ 136 | 'name' => $childComponentName, 137 | 'data' => [] 138 | ] 139 | ] 140 | ] 141 | ]; 142 | 143 | $shouldBeChildOutput = "
{$childComponentName} After Filter Hook
\n"; 144 | $shouldBeHtml = "
{$parentComponentName} result" . $shouldBeChildOutput . "
\n"; 145 | 146 | Filters::expectApplied('Flynt/renderComponent') 147 | ->times(2) 148 | ->with(Mockery::mustBe(null), Mockery::type('string'), Mockery::type('array'), Mockery::type('array')) 149 | ->andReturn($shouldBeHtml); 150 | 151 | // Specific Filters renderComponent?name=SingleComponent for example 152 | Filters::expectApplied('Flynt/renderComponent?name=' . $childComponentName) 153 | ->once() 154 | ->with(Mockery::type('string'), Mockery::type('string'), Mockery::type('array'), Mockery::type('array')) 155 | ->andReturn($shouldBeChildOutput); 156 | 157 | $html = Render::fromConstructionPlan($cp); 158 | $this->assertEquals($html, $shouldBeHtml); 159 | } 160 | 161 | public function testDoesBeforeAndAfterActions() 162 | { 163 | $constructionPlan = [ 164 | 'name' => 'test' 165 | ]; 166 | 167 | Actions::expectFired('Flynt/beforeRenderConstructionPlan') 168 | ->once() 169 | ->with($constructionPlan); 170 | 171 | Actions::expectFired('Flynt/afterRenderConstructionPlan') 172 | ->once() 173 | ->with($constructionPlan); 174 | 175 | @Render::fromConstructionPlan($constructionPlan); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flynt-core 2 | 3 | [![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) 4 | [![Build Status](https://travis-ci.org/flyntwp/flynt-core.svg?branch=master)](https://travis-ci.org/flyntwp/flynt-core) 5 | [![Code Quality](https://img.shields.io/scrutinizer/g/flyntwp/flynt-core.svg)](https://scrutinizer-ci.com/g/flyntwp/flynt-core/?branch=master) 6 | [![Coverage Status](https://coveralls.io/repos/github/flyntwp/flynt-core/badge.svg)](https://coveralls.io/github/flyntwp/flynt-core) 7 | 8 | > The core building block of the [Flynt Framework](https://flyntwp.com). 9 | 10 | The Flynt Core WordPress plugin provides a small public interface, combined with several WordPress hooks, to achieve the main principles of the [Flynt Framework](https://flyntwp.com). 11 | 12 | **:warning: DEPRECATED. This repository is no longer in active development. For the latest version of Flynt please use the [new Flynt repository](https://github.com/flyntwp/flynt). :warning:** 13 | 14 | ## Table of Contents 15 | 16 | - [Background](#background) 17 | - [Install](#install) 18 | - [Usage](#usage) 19 | - [Maintainers](#maintainers) 20 | - [Contribute](#contribute) 21 | - [License](#license) 22 | 23 | ## Background 24 | 25 | This plugin essentially functions as a HTML generator with two key steps: 26 | 27 | 1. Given a minimal configuration, the Flynt Core plugin creates a hierarchical plan for how the site will be constructed (the **Construction Plan**). 28 | 2. The Construction Plan is parsed and rendered into HTML. 29 | 30 | Each configuration passed to the plugin represents a single component. This configuration can also contain additional, nested component configurations, which are contained within "areas". 31 | 32 | ## Install 33 | 34 | 35 | 36 | To install via composer, run: 37 | 38 | ```bash 39 | composer require flyntwp/flynt-core 40 | ``` 41 | 42 | Activate the plugin in the WordPress back-end and you're good to go. 43 | 44 | ## Usage 45 | 46 | ### Hello World 47 | To see the simplest way of using Flynt Core, add the following code to your theme's `functions.php`: 48 | 49 | ```php 50 | $componentManager = Flynt\ComponentManager::getInstance(); 51 | $componentManager->registerComponent('HelloWorld'); 52 | 53 | add_filter('Flynt/renderComponent?name=HelloWorld', function () { 54 | return 'Hello, world!'; 55 | }); 56 | ``` 57 | This defines a new component ('HelloWorld'), which when rendered, will output the text 'Hello, world!'. 58 | 59 | To render the component, add the following code to your theme's `index.php`: 60 | 61 | ```php 62 | Flynt\echoHtmlFromConfig([ 63 | 'name' => 'HelloWorld' 64 | ]); 65 | ``` 66 | 67 | ### Initialize Default Settings 68 | 69 | We recommend initializing the plugin's default settings. Do this by adding the following line of code to your theme's `functions.php`: 70 | 71 | ```php 72 | Flynt\initDefaults(); 73 | ``` 74 | 75 | This will: 76 | 77 | - Implement the component structure. 78 | - Load component scripts. 79 | - Enable PHP file rendering. 80 | 81 | This also adds the following hooks: 82 | 83 | ```php 84 | // Set the config path to './config'. 85 | add_filter('Flynt/configPath', ['Flynt\Defaults', 'setConfigPath'], 999, 2); 86 | 87 | // Parse `.json` config files. 88 | add_filter('Flynt/configFileLoader', ['Flynt\Defaults', 'loadConfigFile'], 999, 3); 89 | 90 | // Set the component path to `./Components`. 91 | add_filter('Flynt/componentPath', ['Flynt\Defaults', 'setComponentPath'], 999, 2); 92 | 93 | // Load ./Components/{$componentName}/functions.php from every registered component. 94 | add_action('Flynt/registerComponent', ['Flynt\Defaults', 'loadFunctionsFile']); 95 | 96 | // Render `./Components/{$componentName}/index.php` and make view helper functions `$data` and `$area` available (see explanation below). 97 | add_filter('Flynt/renderComponent', ['Flynt\Defaults', 'renderComponent'], 999, 4); 98 | ``` 99 | 100 | With the 'Flynt/renderComponent' filter added above you can now use the following helper functions in your template files: 101 | - `$data` is used to access the component's data in the view template. 102 | - `$area` is used to include the HTML of an area's components into the components template itself. 103 | 104 | [You can read the full documentation here.](https://docs.flyntwp.com/guide/core/) 105 | 106 | ## Maintainers 107 | 108 | This project is maintained by [bleech](https://github.com/bleech). 109 | 110 | The main people in charge of this repo are: 111 | 112 | - [Dominik Tränklein](https://github.com/domtra) 113 | - [Doğa Gürdal](https://github.com/Qakulukiam) 114 | 115 | ## Contribute 116 | 117 | To contribute, please use GitHub [issues](https://github.com/flyntwp/flynt-core/issues). Pull requests are accepted. Please also take a moment to read the [Contributing Guidelines](https://github.com/flyntwp/guidelines/blob/master/CONTRIBUTING.md) and [Code of Conduct](https://github.com/flyntwp/guidelines/blob/master/CODE_OF_CONDUCT.md). 118 | 119 | If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. 120 | 121 | ## License 122 | 123 | MIT © [bleech](https://www.bleech.de) 124 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | 6 | # 1.0.0 (2017-03-27) 7 | 8 | 9 | ### Bug Fixes 10 | 11 | * **BuildConstructionPlan:** always create valid construction plan ([55376f8](https://github.com/flyntwp/flynt-core/commit/55376f8)) 12 | * **constructionPlan:** changed exceptions to warnings ([e6c4542](https://github.com/flyntwp/flynt-core/commit/e6c4542)) 13 | * **constructionPlan:** do not require non-empty areas for dynamicSubmodules + refactor names ([af34a92](https://github.com/flyntwp/flynt-core/commit/af34a92)) 14 | * **defaultLoader:** corrected naming for registerModule hook, added correct exception tests for warn ([254b860](https://github.com/flyntwp/flynt-core/commit/254b860)) 15 | * **defaultLoader:** corrected use to be use function for the helper function ([d1f2a8c](https://github.com/flyntwp/flynt-core/commit/d1f2a8c)) 16 | * **defaults:** missing argument 4 areaHtml ([cf855a0](https://github.com/flyntwp/flynt-core/commit/cf855a0)) 17 | * **render:** changed exceptions to warnings ([c7230c8](https://github.com/flyntwp/flynt-core/commit/c7230c8)) 18 | * **Render:** Error messages ([697aca6](https://github.com/flyntwp/flynt-core/commit/697aca6)) 19 | * **renderer:** throw exception when template not found ([e940ff5](https://github.com/flyntwp/flynt-core/commit/e940ff5)) 20 | * **wpStarter:** register renamed to correct: registerModule ([8c329e0](https://github.com/flyntwp/flynt-core/commit/8c329e0)) 21 | 22 | 23 | ### Features 24 | 25 | * **buildConstructionPlan:** added initModuleConfig filter ([09717f9](https://github.com/flyntwp/flynt-core/commit/09717f9)) 26 | * **buildConstructionPlan:** added modifyModuleData filters ([369ba9b](https://github.com/flyntwp/flynt-core/commit/369ba9b)) 27 | * **buildConstructionPlan:** added parentData overwrite ([c3e5a46](https://github.com/flyntwp/flynt-core/commit/c3e5a46)) 28 | * **ComponentManager:** added isRegistered ([47a1c35](https://github.com/flyntwp/flynt-core/commit/47a1c35)) 29 | * **ComponentManager:** pass name as second parameter for component-specific registerComponent actio ([b7def8d](https://github.com/flyntwp/flynt-core/commit/b7def8d)) 30 | * **composer:** add composer installers and type wordpress plugin ([406fb71](https://github.com/flyntwp/flynt-core/commit/406fb71)) 31 | * **composer:** add composer package info ([b7f0707](https://github.com/flyntwp/flynt-core/commit/b7f0707)) 32 | * **composer:** autoload flynt-core-plugin.php ([c9ff920](https://github.com/flyntwp/flynt-core/commit/c9ff920)) 33 | * **constructionPlan:** added default path for config + adjusted tests, refactored getTemplateDirect ([5da250d](https://github.com/flyntwp/flynt-core/commit/5da250d)) 34 | * **constructionPlan:** added filter hook for fromConfigFile loading, added additional checks for co ([100b5bc](https://github.com/flyntwp/flynt-core/commit/100b5bc)) 35 | * **constructionPlan:** added load from config file (json) ([a08b028](https://github.com/flyntwp/flynt-core/commit/a08b028)) 36 | * **constructionPlan:** apply WPStarter/dynamicSubmodules filter ([1368641](https://github.com/flyntwp/flynt-core/commit/1368641)) 37 | * **constructionPlan:** nested dynamic submodules ([c30fa87](https://github.com/flyntwp/flynt-core/commit/c30fa87)) 38 | * **ConstructionPlan:** added first tests and basic functionality for single module config ([1995b79](https://github.com/flyntwp/flynt-core/commit/1995b79)) 39 | * **defaultLoader:** moved default functionality for config file loading and rendering to its own cl ([51f9ff8](https://github.com/flyntwp/flynt-core/commit/51f9ff8)) 40 | * **defaults:** added getModulesDirectory method for default modules path ([37af61d](https://github.com/flyntwp/flynt-core/commit/37af61d)) 41 | * **helpers:** add extractNestedDataFromArray helper function ([021dbe7](https://github.com/flyntwp/flynt-core/commit/021dbe7)) 42 | * **helpers:** extract data helper now also works with objects ([74d575a](https://github.com/flyntwp/flynt-core/commit/74d575a)) 43 | * **helpers:** extractData - added ability to use array further down the param line ([966cd77](https://github.com/flyntwp/flynt-core/commit/966cd77)) 44 | * **moduleManager:** added ModuleManager Class, refactored WPStarter Class into global namespaced fu ([23ba863](https://github.com/flyntwp/flynt-core/commit/23ba863)) 45 | * **render:** added correct params to renderModule filters and refactored class + tests ([4b07a64](https://github.com/flyntwp/flynt-core/commit/4b07a64)) 46 | * **render:** use null as default arg in renderModule filter ([3e80add](https://github.com/flyntwp/flynt-core/commit/3e80add)) 47 | * **renderer:** add basic render functionality for single and nested modules ([b8003f7](https://github.com/flyntwp/flynt-core/commit/b8003f7)) 48 | * **renderer:** added renderModule hook ([d071f48](https://github.com/flyntwp/flynt-core/commit/d071f48)) 49 | * **renderer:** added single module render hook ([f1edd70](https://github.com/flyntwp/flynt-core/commit/f1edd70)) 50 | * **wpStarter:** added get_template_directory to modulesPath filter and renamed defaultModulesPath t ([c37bb88](https://github.com/flyntwp/flynt-core/commit/c37bb88)) 51 | * **wpStarter:** added missing getModuleFilePath method ([be73b5d](https://github.com/flyntwp/flynt-core/commit/be73b5d)) 52 | * **wpStarter:** added registerModule actions ([741a667](https://github.com/flyntwp/flynt-core/commit/741a667)) 53 | * **wpStarter:** added registerModule functionality + shortcut methods for public API ([98fa7be](https://github.com/flyntwp/flynt-core/commit/98fa7be)) 54 | * **wpStarter:** added registerModules ([bec7863](https://github.com/flyntwp/flynt-core/commit/bec7863)) 55 | * **wpStarter:** registerModule optional argument for path ([d234e28](https://github.com/flyntwp/flynt-core/commit/d234e28)) 56 | -------------------------------------------------------------------------------- /lib/Flynt/BuildConstructionPlan.php: -------------------------------------------------------------------------------- 1 | isRegistered($config['name'])) { 71 | trigger_error( 72 | "Component '{$config['name']}' could not be found in component list. Did you forget to register the component?", 73 | E_USER_WARNING 74 | ); 75 | return false; 76 | } 77 | } 78 | 79 | protected static function overwriteParentData(&$config, $parentData) 80 | { 81 | if (array_key_exists('parentData', $config)) { 82 | if (is_array($config['parentData'])) { 83 | $parentData = $config['parentData']; 84 | } 85 | unset($config['parentData']); 86 | } 87 | return $parentData; 88 | } 89 | 90 | protected static function addCustomData($config) 91 | { 92 | if (array_key_exists('customData', $config)) { 93 | if (is_array($config['customData'])) { 94 | // custom data overwrites original data 95 | $config['data'] = array_merge($config['data'], $config['customData']); 96 | } 97 | unset($config['customData']); 98 | } 99 | return $config; 100 | } 101 | 102 | protected static function applyDataModifications($config, $parentData) 103 | { 104 | $config['data'] = apply_filters( 105 | 'Flynt/addComponentData', 106 | $config['data'], 107 | $parentData, 108 | $config 109 | ); 110 | $config['data'] = apply_filters( 111 | "Flynt/addComponentData?name={$config['name']}", 112 | $config['data'], 113 | $parentData, 114 | $config 115 | ); 116 | return $config; 117 | } 118 | 119 | protected static function addSubcomponents($config, $parentData) 120 | { 121 | // add dynamic subcomponents to areas 122 | $areas = array_key_exists('areas', $config) ? $config['areas'] : []; 123 | $config['areas'] = apply_filters( 124 | "Flynt/dynamicSubcomponents?name={$config['name']}", 125 | $areas, 126 | $config['data'], 127 | $parentData 128 | ); 129 | 130 | // iterate areas and recursively map child component construction plan 131 | if (!empty($config['areas'])) { 132 | $areaNames = array_keys($config['areas']); 133 | $config['areas'] = array_reduce($areaNames, function ($output, $areaName) use ($config, $parentData) { 134 | $components = $config['areas'][$areaName]; 135 | $output[$areaName] = array_filter(self::mapAreaComponents($components, $config, $areaName, $parentData)); 136 | return $output; 137 | }, []); 138 | } 139 | 140 | // remove empty 'areas' key from config 141 | // this can happen if there were no areas defined to begin with 142 | if (empty($config['areas'])) { 143 | unset($config['areas']); 144 | } 145 | 146 | return $config; 147 | } 148 | 149 | protected static function mapAreaComponents($components, $config, $areaName, $parentData) 150 | { 151 | return array_map(function ($component) use ($config, $areaName, $parentData) { 152 | $data = empty($config['data']) ? $parentData : $config['data']; 153 | return self::fromConfigRecursive($component, $data); 154 | }, $components); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /tests/test-flynt.php: -------------------------------------------------------------------------------- 1 | shouldReceive('getInstance') 54 | ->once() 55 | ->andReturn($componentManagerMock); 56 | 57 | $componentManagerMock 58 | ->shouldReceive('registerComponent') 59 | ->with($componentName, $componentPath) 60 | ->once(); 61 | 62 | registerComponent($componentName, $componentPath); 63 | } 64 | 65 | /** 66 | * @runInSeparateProcess 67 | * @preserveGlobalState disabled 68 | */ 69 | public function testRegistersComponentsFromArray() 70 | { 71 | $componentManagerMock = Mockery::mock('ComponentManager'); 72 | 73 | Mockery::mock('alias:Flynt\ComponentManager') 74 | ->shouldReceive('getInstance') 75 | ->times(3) 76 | ->andReturn($componentManagerMock); 77 | 78 | $componentManagerMock 79 | ->shouldReceive('registerComponent') 80 | ->with('ComponentA', null) 81 | ->ordered() 82 | ->once(); 83 | 84 | $componentManagerMock 85 | ->shouldReceive('registerComponent') 86 | ->with('ComponentB', 'some/path') 87 | ->ordered() 88 | ->once(); 89 | 90 | $componentManagerMock 91 | ->shouldReceive('registerComponent') 92 | ->with('ComponentC', null) 93 | ->ordered() 94 | ->once(); 95 | 96 | $componentsWithPaths = [ 97 | 'ComponentA' => null, 98 | 'ComponentB' => 'some/path', 99 | 'ComponentC' => null 100 | ]; 101 | 102 | registerComponents($componentsWithPaths); 103 | 104 | $componentManagerMock 105 | ->shouldReceive('registerComponent') 106 | ->with('ComponentD', null) 107 | ->ordered() 108 | ->once(); 109 | 110 | $componentManagerMock 111 | ->shouldReceive('registerComponent') 112 | ->with('ComponentE', null) 113 | ->ordered() 114 | ->once(); 115 | 116 | $componentManagerMock 117 | ->shouldReceive('registerComponent') 118 | ->with('ComponentF', null) 119 | ->ordered() 120 | ->once(); 121 | 122 | $componentsWithoutPaths = [ 123 | 'ComponentD', 124 | 'ComponentE', 125 | 'ComponentF' 126 | ]; 127 | 128 | registerComponents($componentsWithoutPaths); 129 | 130 | $componentManagerMock 131 | ->shouldReceive('registerComponent') 132 | ->with('ComponentG', null) 133 | ->ordered() 134 | ->once(); 135 | 136 | $componentManagerMock 137 | ->shouldReceive('registerComponent') 138 | ->with('ComponentH', null) 139 | ->ordered() 140 | ->once(); 141 | 142 | $componentManagerMock 143 | ->shouldReceive('registerComponent') 144 | ->with('ComponentI', 'some/path') 145 | ->ordered() 146 | ->once(); 147 | 148 | $componentsMixed = [ 149 | 'ComponentG', 150 | 'ComponentH' => null, 151 | 'ComponentI' => 'some/path' 152 | ]; 153 | 154 | registerComponents($componentsMixed); 155 | } 156 | 157 | /** 158 | * @runInSeparateProcess 159 | * @preserveGlobalState disabled 160 | */ 161 | public function testEchoesHtmlFromConfiguration() 162 | { 163 | $config = [ 164 | 'name' => 'SingleComponent', 165 | 'customData' => [ 166 | 'test' => 'result' 167 | ] 168 | ]; 169 | 170 | $constructionPlan = [ 171 | 'name' => 'SingleComponent', 172 | 'data' => [ 173 | 'test' => 'result' 174 | ] 175 | ]; 176 | 177 | Mockery::mock('alias:Flynt\BuildConstructionPlan') 178 | ->shouldReceive('fromConfig') 179 | ->once() 180 | ->with($config) 181 | ->andReturn($constructionPlan); 182 | 183 | Mockery::mock('alias:Flynt\Render') 184 | ->shouldReceive('fromConstructionPlan') 185 | ->once() 186 | ->with($constructionPlan) 187 | ->andReturn('test'); 188 | 189 | $this->expectOutputString('test'); 190 | echoHtmlFromConfig($config); 191 | } 192 | 193 | /** 194 | * @runInSeparateProcess 195 | * @preserveGlobalState disabled 196 | */ 197 | public function testEchoesHtmlFromConfigurationFile() 198 | { 199 | $configFileName = 'exampleConfigWithSingleComponent.json'; 200 | 201 | $constructionPlan = [ 202 | 'name' => 'SingleComponent', 203 | 'data' => [ 204 | 'test' => 'result' 205 | ] 206 | ]; 207 | 208 | Mockery::mock('alias:Flynt\BuildConstructionPlan') 209 | ->shouldReceive('fromConfigFile') 210 | ->once() 211 | ->with($configFileName) 212 | ->andReturn($constructionPlan); 213 | 214 | Mockery::mock('alias:Flynt\Render') 215 | ->shouldReceive('fromConstructionPlan') 216 | ->once() 217 | ->with($constructionPlan) 218 | ->andReturn('test'); 219 | 220 | $this->expectOutputString('test'); 221 | echoHtmlFromConfigFile($configFileName); 222 | } 223 | 224 | /** 225 | * @runInSeparateProcess 226 | * @preserveGlobalState disabled 227 | */ 228 | public function testCallsDefaultsInitFunction() 229 | { 230 | Mockery::mock('alias:Flynt\Defaults') 231 | ->shouldReceive('init') 232 | ->once(); 233 | 234 | initDefaults(); 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /tests/test-defaults.php: -------------------------------------------------------------------------------- 1 | once() 40 | ->with(['Flynt\Defaults', 'setConfigPath'], 999, 2); 41 | 42 | Defaults::init(); 43 | } 44 | 45 | public function testAddsFilterForConfigFileLoader() 46 | { 47 | Filters::expectAdded('Flynt/configFileLoader') 48 | ->once() 49 | ->with(['Flynt\Defaults', 'loadConfigFile'], 999, 3); 50 | 51 | Defaults::init(); 52 | } 53 | 54 | public function testAddsFilterForRenderComponent() 55 | { 56 | Filters::expectAdded('Flynt/renderComponent') 57 | ->once() 58 | ->with(['Flynt\Defaults', 'renderComponent'], 999, 4); 59 | 60 | Defaults::init(); 61 | } 62 | 63 | public function testAddsFilterForComponentPath() 64 | { 65 | Filters::expectAdded('Flynt/componentPath') 66 | ->once() 67 | ->with(['Flynt\Defaults', 'setComponentPath'], 999, 2); 68 | 69 | Defaults::init(); 70 | } 71 | 72 | public function testAddsActionForRegisterComponent() 73 | { 74 | Actions::expectAdded('Flynt/registerComponent') 75 | ->once() 76 | ->with(['Flynt\Defaults', 'loadFunctionsFile']); 77 | 78 | Defaults::init(); 79 | } 80 | 81 | public function testReturnsAConfigPath() 82 | { 83 | $configPath = Defaults::setConfigPath(null, 'config.json'); 84 | $this->assertEquals($configPath, TestHelper::getTemplateDirectory() . '/config/config.json'); 85 | } 86 | 87 | public function testLoadsAndDecodesJsonFile() 88 | { 89 | $configPath = TestHelper::getConfigPath() . 'exampleConfigWithSingleComponent.json'; 90 | $config = Defaults::loadConfigFile(null, '', $configPath); 91 | $this->assertEquals($config, [ 92 | 'name' => 'SingleComponent', 93 | 'customData' => [ 94 | 'test' => 'result' 95 | ] 96 | ]); 97 | } 98 | 99 | /** 100 | * @runInSeparateProcess 101 | * @preserveGlobalState disabled 102 | */ 103 | public function testRenderShowsWarningIfComponentFileIsADirectory() 104 | { 105 | $componentName = 'SingleComponent'; 106 | $componentData = []; 107 | $areaHtml = []; 108 | 109 | $this->expectException('PHPUnit_Framework_Error_Warning'); 110 | 111 | $this->mockComponentManager() 112 | ->shouldReceive('getComponentFilePath') 113 | ->once() 114 | ->with($componentName) 115 | ->andReturn(TestHelper::getComponentsPath() . $componentName); 116 | 117 | $output = Defaults::renderComponent(null, $componentName, $componentData, $areaHtml); 118 | $this->assertEquals($output, ''); 119 | } 120 | 121 | /** 122 | * @runInSeparateProcess 123 | * @preserveGlobalState disabled 124 | */ 125 | public function testRenderShowsWarningIfComponentFileDoesntExist() 126 | { 127 | $componentName = 'SomeComponentThatDoesntExist'; 128 | $componentData = []; 129 | $areaHtml = []; 130 | 131 | $this->expectException('PHPUnit_Framework_Error_Warning'); 132 | 133 | $this->mockComponentManager() 134 | ->shouldReceive('getComponentFilePath') 135 | ->once() 136 | ->with($componentName) 137 | ->andReturn('not/a/real/file.php'); 138 | 139 | $output = Defaults::renderComponent(null, $componentName, $componentData, $areaHtml); 140 | } 141 | 142 | /** 143 | * @runInSeparateProcess 144 | * @preserveGlobalState disabled 145 | */ 146 | public function testRenderReturnsEmptyStringOnError() 147 | { 148 | $componentName = 'SomeComponentThatDoesntExist'; 149 | $componentData = []; 150 | $areaHtml = []; 151 | 152 | $this->mockComponentManager() 153 | ->shouldReceive('getComponentFilePath') 154 | ->once() 155 | ->with($componentName) 156 | ->andReturn('not/a/real/file.php'); 157 | 158 | // suppress exception to get an output 159 | $output = @Defaults::renderComponent(null, $componentName, $componentData, $areaHtml); 160 | $this->assertEquals($output, ''); 161 | } 162 | 163 | /** 164 | * @runInSeparateProcess 165 | * @preserveGlobalState disabled 166 | */ 167 | public function testRendersFileCorrectly() 168 | { 169 | $componentName = 'SingleComponent'; 170 | $componentData = [ 171 | 'test' => 'result' 172 | ]; 173 | $areaHtml = []; 174 | 175 | $this->mockComponentManager() 176 | ->shouldReceive('getComponentFilePath') 177 | ->once() 178 | ->with($componentName) 179 | ->andReturn(TestHelper::getComponentsPath() . $componentName . '/index.php'); 180 | 181 | Mockery::mock('alias:Flynt\Helpers') 182 | ->shouldReceive('extractNestedDataFromArray') 183 | ->andReturn('result'); 184 | 185 | $output = Defaults::renderComponent(null, $componentName, $componentData, $areaHtml); 186 | 187 | $expectedHTML = "
SingleComponent result
\n"; 188 | 189 | $this->assertEquals($output, $expectedHTML); 190 | } 191 | 192 | /** 193 | * @runInSeparateProcess 194 | * @preserveGlobalState disabled 195 | */ 196 | public function testRendersNestedComponentsCorrectly() 197 | { 198 | $parentComponentName = 'ComponentWithArea'; 199 | $childComponentName = 'SingleComponent'; 200 | $componentData = [ 201 | 'test' => 'result' 202 | ]; 203 | 204 | $this->mockComponentManager() 205 | ->shouldReceive('getComponentFilePath') 206 | ->times(2) 207 | ->with(Mockery::type('string')) 208 | ->andReturnUsing(['\\Flynt\\Tests\\TestHelper', 'getComponentIndexPath']); 209 | 210 | Mockery::mock('alias:Flynt\Helpers') 211 | ->shouldReceive('extractNestedDataFromArray') 212 | ->andReturn('result'); 213 | 214 | $areaHtml = [ 215 | 'area51' => Defaults::renderComponent(null, $childComponentName, $componentData, []) 216 | ]; 217 | $output = Defaults::renderComponent(null, $parentComponentName, $componentData, $areaHtml); 218 | 219 | $this->assertEquals($output, "
{$parentComponentName} result
{$childComponentName} result
\n
\n"); 220 | } 221 | 222 | /** 223 | * @runInSeparateProcess 224 | * @preserveGlobalState disabled 225 | */ 226 | public function testLoadsFunctionsPhpOnRegisterComponent() 227 | { 228 | $componentName = 'SingleComponent'; 229 | $componentPath = TestHelper::getComponentPath(null, $componentName); 230 | 231 | $this->mockComponentManager() 232 | ->shouldReceive('getComponentFilePath') 233 | ->with($componentName, 'functions.php') 234 | ->andReturn($componentPath . '/functions.php'); 235 | 236 | // checking if filter in required component file is added 237 | Filters::expectAdded("Flynt/DataFilters/{$componentName}/foo") 238 | ->once(); 239 | 240 | Defaults::loadFunctionsFile($componentName); 241 | } 242 | 243 | /** 244 | * @runInSeparateProcess 245 | * @preserveGlobalState disabled 246 | */ 247 | public function testDoesNotLoadFunctionsPhpOnRegisterComponentIfItDoesntExist() 248 | { 249 | // running this test separately to be able to see the error message 250 | $componentName = 'ComponentWithoutFunctionsPhp'; 251 | 252 | $this->mockComponentManager() 253 | ->shouldReceive('getComponentFilePath') 254 | ->with($componentName, 'functions.php') 255 | ->andReturn(false); 256 | 257 | // this will throw an error if a file is required that doesn't exist 258 | Defaults::loadFunctionsFile($componentName); 259 | } 260 | 261 | public function testIsGettingDefaultComponentsDirectory() 262 | { 263 | $dir = Defaults::getComponentsDirectory(); 264 | $this->assertEquals($dir, TestHelper::getTemplateDirectory() . '/Components'); 265 | } 266 | 267 | // Helpers 268 | public function mockComponentManager() 269 | { 270 | $componentManagerMock = Mockery::mock('ComponentManager'); 271 | 272 | Mockery::mock('alias:Flynt\ComponentManager') 273 | ->shouldReceive('getInstance') 274 | ->andReturn($componentManagerMock); 275 | 276 | return $componentManagerMock; 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /tests/test-componentManager.php: -------------------------------------------------------------------------------- 1 | componentManager = ComponentManager::getInstance(); 30 | $this->componentManager->removeAll(); 31 | } 32 | 33 | public function testGetsInstance() 34 | { 35 | $this->assertInstanceOf(ComponentManager::class, ComponentManager::getInstance()); 36 | } 37 | 38 | 39 | public function testPreventsCloning() 40 | { 41 | $reflection = new \ReflectionClass('\Flynt\ComponentManager'); 42 | $cloneFn = $reflection->getMethod('__clone'); 43 | $this->assertFalse($cloneFn->isPublic()); 44 | } 45 | 46 | 47 | public function testPreventsManualInstantiation() 48 | { 49 | $reflection = new \ReflectionClass('\Flynt\ComponentManager'); 50 | $constructor = $reflection->getConstructor(); 51 | $this->assertFalse($constructor->isPublic()); 52 | } 53 | 54 | public function testRegisterComponentUsesOptionalPathParameter() 55 | { 56 | $componentName = 'ComponentWithArea'; 57 | $componentPath = TestHelper::getComponentsPath() . 'SingleComponent'; 58 | 59 | Filters::expectApplied('Flynt/componentPath') 60 | ->with($componentPath, $componentName) 61 | ->once(); 62 | 63 | $success = $this->componentManager->registerComponent($componentName, $componentPath); 64 | $this->assertTrue($success); 65 | } 66 | 67 | public function testComponentIsAddedToArray() 68 | { 69 | $componentName = 'SingleComponent'; 70 | 71 | Filters::expectApplied('Flynt/componentPath') 72 | ->andReturnUsing(['\\Flynt\\Tests\\TestHelper', 'getComponentPath']); 73 | 74 | $this->componentManager->registerComponent($componentName); 75 | $components = $this->componentManager->getAll(); 76 | $this->assertEquals($components, [$componentName => TestHelper::getComponentsPath() . $componentName . '/']); 77 | } 78 | 79 | public function testShowsWarningWhenComponentIsAddedMoreThanOnce() 80 | { 81 | $componentName = 'SingleComponent'; 82 | $this->componentManager->registerComponent($componentName); 83 | 84 | $this->expectException('PHPUnit_Framework_Error_Warning'); 85 | 86 | $this->componentManager->registerComponent($componentName); 87 | } 88 | 89 | public function testComponentIsOnlyAddedToArrayOnce() 90 | { 91 | $componentName = 'SingleComponent'; 92 | $this->componentManager->registerComponent($componentName); 93 | 94 | Filters::expectApplied('Flynt/componentPath') 95 | ->never(); 96 | 97 | $result = @$this->componentManager->registerComponent($componentName); 98 | $this->assertFalse($result); 99 | } 100 | 101 | public function testDoesRegisterComponentAction() 102 | { 103 | $componentName = 'SingleComponent'; 104 | $componentPath = TestHelper::getComponentsPath() . $componentName . '/'; 105 | 106 | Filters::expectApplied('Flynt/componentPath') 107 | ->andReturnUsing(['\\Flynt\\Tests\\TestHelper', 'getComponentPath']); 108 | 109 | Actions::expectFired('Flynt/registerComponent') 110 | ->with($componentName); 111 | 112 | Actions::expectFired("Flynt/registerComponent?name={$componentName}") 113 | ->with($componentName); 114 | 115 | $result = $this->componentManager->registerComponent($componentName); 116 | $this->assertTrue($result); 117 | } 118 | 119 | public function testGetsComponentFilePath() 120 | { 121 | $componentName = 'SingleComponent'; 122 | 123 | // mock default functionality for path on registerComponent 124 | Filters::expectApplied('Flynt/componentPath') 125 | ->andReturnUsing(['\\Flynt\\Tests\\TestHelper', 'getComponentPath']); 126 | 127 | $this->componentManager->registerComponent($componentName); 128 | 129 | // test default 130 | $path = $this->componentManager->getComponentFilePath($componentName); 131 | $this->assertEquals($path, TestHelper::getComponentPath(null, $componentName) . '/index.php'); 132 | 133 | // test second parameter 134 | $fileName = 'index.html'; 135 | $path = $this->componentManager->getComponentFilePath($componentName, $fileName); 136 | $this->assertEquals($path, TestHelper::getComponentPath(null, $componentName) . '/' . $fileName); 137 | } 138 | 139 | public function testGetReturnsComponentPath() 140 | { 141 | $this->componentManager->registerComponent('SingleComponent', 'path'); 142 | $path = $this->componentManager->get('SingleComponent'); 143 | $this->assertEquals($path, 'path/'); 144 | } 145 | 146 | public function testGetShowsWarningOnUnregisteredComponentParam() 147 | { 148 | $this->expectException('PHPUnit_Framework_Error_Warning'); 149 | $path = $this->componentManager->get('SomeComponentName'); 150 | } 151 | 152 | public function testGetReturnsFalseOnUnregisteredComponentParam() 153 | { 154 | $path = @$this->componentManager->get('SomeComponentName'); 155 | $this->assertFalse($path); 156 | } 157 | 158 | public function testGetComponentFilePathReturnsFalseOnIncorrectFileName() 159 | { 160 | $componentName = 'SingleComponent'; 161 | 162 | Filters::expectApplied('Flynt/componentPath') 163 | ->andReturnUsing(['\\Flynt\\Tests\\TestHelper', 'getComponentPath']); 164 | 165 | $this->componentManager->registerComponent($componentName); 166 | 167 | $path = @$this->componentManager->getComponentFilePath($componentName, 'doesNotExist.something'); 168 | $this->assertFalse($path); 169 | } 170 | 171 | public function testGetComponentDirPathReturnsCorrectPath() 172 | { 173 | // mock default functionality for path on registerComponent 174 | Filters::expectApplied('Flynt/componentPath') 175 | ->andReturnUsing(['\\Flynt\\Tests\\TestHelper', 'getComponentPath']); 176 | 177 | $this->componentManager->registerComponent('SingleComponent'); 178 | $path = $this->componentManager->getComponentDirPath('SingleComponent'); 179 | 180 | // Could also check the string to be the same, but this is nice and short 181 | $this->assertFileExists($path); 182 | } 183 | 184 | public function testGetComponentDirPathReturnsFalseForIncorrectDir() 185 | { 186 | $this->componentManager->registerComponent('SingleComponent', 'path'); 187 | $result = $this->componentManager->getComponentDirPath('SingleComponent'); 188 | $this->assertFalse($result); 189 | } 190 | 191 | public function testReturnsComponentList() 192 | { 193 | $componentA = 'SingleComponent'; 194 | $componentB = 'ComponentWithArea'; 195 | 196 | Filters::expectApplied('Flynt/componentPath') 197 | ->andReturnUsing(['\\Flynt\\Tests\\TestHelper', 'getComponentPath']); 198 | 199 | $this->componentManager->registerComponent($componentA); 200 | $this->assertEquals($this->componentManager->getAll(), [ 201 | 'SingleComponent' => TestHelper::getComponentsPath() . $componentA . '/' 202 | ]); 203 | 204 | $this->componentManager->registerComponent($componentB); 205 | $this->assertEquals($this->componentManager->getAll(), [ 206 | 'SingleComponent' => TestHelper::getComponentsPath() . $componentA . '/', 207 | 'ComponentWithArea' => TestHelper::getComponentsPath() . $componentB . '/' 208 | ]); 209 | } 210 | 211 | public function testRemovesComponent() 212 | { 213 | $component = 'SingleComponent'; 214 | $anotherComponent = 'AnotherComponent'; 215 | 216 | Filters::expectApplied('Flynt/componentPath') 217 | ->andReturnUsing(['\\Flynt\\Tests\\TestHelper', 'getComponentPath']); 218 | 219 | $this->componentManager->registerComponent($component); 220 | $this->componentManager->registerComponent($anotherComponent); 221 | 222 | $this->componentManager->remove($component); 223 | 224 | $this->assertFalse(@$this->componentManager->get($component)); 225 | $this->assertArrayHasKey($anotherComponent, $this->componentManager->getAll()); 226 | } 227 | 228 | public function testClearsComponentList() 229 | { 230 | $component = 'SingleComponent'; 231 | 232 | Filters::expectApplied('Flynt/componentPath') 233 | ->andReturnUsing(['\\Flynt\\Tests\\TestHelper', 'getComponentPath']); 234 | 235 | $this->componentManager->registerComponent($component); 236 | $this->assertEquals($this->componentManager->getAll(), [ 237 | 'SingleComponent' => TestHelper::getComponentsPath() . $component . '/' 238 | ]); 239 | 240 | $this->componentManager->removeAll(); 241 | $this->assertEquals($this->componentManager->getAll(), []); 242 | } 243 | 244 | public function testComponentIsRegistered() 245 | { 246 | $component = 'SingleComponent'; 247 | 248 | Filters::expectApplied('Flynt/componentPath') 249 | ->andReturnUsing(['\\Flynt\\Tests\\TestHelper', 'getComponentPath']); 250 | 251 | $this->componentManager->registerComponent($component); 252 | 253 | $this->assertTrue($this->componentManager->isRegistered($component)); 254 | $this->assertFalse($this->componentManager->isRegistered('test')); 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /tests/test-buildConstructionPlan.php: -------------------------------------------------------------------------------- 1 | componentList = [ 31 | 'DynamicComponent' => '', 32 | 'SingleComponent' => '', 33 | 'ComponentWithArea' => '', 34 | 'NestedComponentWithArea' => '', 35 | 'ComponentInConfigFile' => '', 36 | 'ChildComponentInConfigFile' => '', 37 | 'GrandChildA' => '', 38 | 'GrandChildB' => '', 39 | 'GrandChildC' => '' 40 | ]; 41 | } 42 | 43 | public function badValues() 44 | { 45 | return [ 46 | [[]], 47 | [[ 48 | 'customData' => [ 49 | 'whatever' 50 | ] 51 | ]], 52 | [new StdClass()], 53 | ['string'], 54 | [0] 55 | ]; 56 | } 57 | 58 | public function badValuesComponentManager() 59 | { 60 | return [ 61 | [[ 62 | 'name' => 'ThisComponentIsNotRegistered' 63 | ]], 64 | [[ 65 | 'name' => '' 66 | ]], 67 | [[ 68 | 'name' => [] 69 | ]] 70 | ]; 71 | } 72 | 73 | /** 74 | * @dataProvider badValues 75 | */ 76 | public function testShowWarningOnInvalidConfig($badValue) 77 | { 78 | $this->expectException('PHPUnit_Framework_Error_Warning'); 79 | $cp = BuildConstructionPlan::fromConfig($badValue); 80 | } 81 | 82 | /** 83 | * @dataProvider badValues 84 | */ 85 | public function testReturnsEmptyConstructionPlanOnInvalidConfig($badValue) 86 | { 87 | $cp = @BuildConstructionPlan::fromConfig($badValue); 88 | $this->assertEquals($cp, []); 89 | } 90 | 91 | /** 92 | * @dataProvider badValuesComponentManager 93 | * @runInSeparateProcess 94 | * @preserveGlobalState disabled 95 | */ 96 | public function testShowWarningOnInvalidConfigWithComponentManager($badValue) 97 | { 98 | $this->expectException('PHPUnit_Framework_Error_Warning'); 99 | $this->mockComponentManager(); 100 | BuildConstructionPlan::fromConfig($badValue); 101 | } 102 | 103 | /** 104 | * @dataProvider badValuesComponentManager 105 | * @runInSeparateProcess 106 | * @preserveGlobalState disabled 107 | */ 108 | public function testReturnsEmptyConstructionPlanOnInvalidConfigWithComponentManager($badValue) 109 | { 110 | $this->mockComponentManager(); 111 | $cp = @BuildConstructionPlan::fromConfig($badValue); 112 | $this->assertEquals($cp, []); 113 | } 114 | 115 | /** 116 | * @runInSeparateProcess 117 | * @preserveGlobalState disabled 118 | */ 119 | public function testInvalidCustomDataIsIgnored() 120 | { 121 | $config = [ 122 | 'name' => 'SingleComponent', 123 | 'customData' => 'string' 124 | ]; 125 | $this->mockComponentManager(); 126 | $cp = BuildConstructionPlan::fromConfig($config, $this->componentList); 127 | $this->assertEquals($cp, [ 128 | 'name' => 'SingleComponent', 129 | 'data' => [] 130 | ]); 131 | } 132 | 133 | /** 134 | * @runInSeparateProcess 135 | * @preserveGlobalState disabled 136 | */ 137 | public function testInvalidParentDataIsIgnored() 138 | { 139 | $parentData = 'string'; 140 | $config = [ 141 | 'name' => 'SingleComponent', 142 | 'parentData' => $parentData 143 | ]; 144 | $this->mockComponentManager(); 145 | Filters::expectApplied('Flynt/addComponentData') 146 | ->with([], [], [ 147 | 'name' => 'SingleComponent', 148 | 'data' => [] 149 | ]) 150 | ->once() 151 | ->andReturn([]); 152 | $cp = BuildConstructionPlan::fromConfig($config, $this->componentList); 153 | $this->assertEquals($cp, [ 154 | 'name' => 'SingleComponent', 155 | 'data' => [] 156 | ]); 157 | } 158 | 159 | /** 160 | * @runInSeparateProcess 161 | * @preserveGlobalState disabled 162 | */ 163 | public function testConfigCanBeLoadedFromFile() 164 | { 165 | $fileName = 'exampleConfig.json'; 166 | $filePath = TestHelper::getConfigPath() . $fileName; 167 | 168 | Filters::expectApplied('Flynt/configPath') 169 | ->andReturn($filePath); 170 | 171 | Filters::expectApplied('Flynt/configFileLoader') 172 | ->once() 173 | ->with(null, $fileName, $filePath) 174 | ->andReturn([ 175 | 'name' => 'SingleComponent' 176 | ]); 177 | 178 | $this->mockComponentManager(); 179 | 180 | $cp = BuildConstructionPlan::fromConfigFile($fileName); 181 | $this->assertEquals($cp, [ 182 | 'name' => 'SingleComponent', 183 | 'data' => [] 184 | ]); 185 | } 186 | 187 | public function testShowWarningWhenConfigFileDoesntExist() 188 | { 189 | $fileName = 'exceptionTest.json'; 190 | 191 | Filters::expectApplied('Flynt/configPath') 192 | ->once() 193 | ->with(null, $fileName) 194 | ->andReturn('/not/a/real/config/file.json'); 195 | 196 | $this->expectException('PHPUnit_Framework_Error_Warning'); 197 | 198 | $cp = BuildConstructionPlan::fromConfigFile($fileName); 199 | } 200 | 201 | public function testReturnsEmptyConstructionPlanWhenConfigFileDoesntExist() 202 | { 203 | $fileName = 'exceptionTest.json'; 204 | 205 | Filters::expectApplied('Flynt/configPath') 206 | ->once() 207 | ->with(null, $fileName) 208 | ->andReturn('/not/a/real/config/file.json'); 209 | 210 | $cp = @BuildConstructionPlan::fromConfigFile($fileName); 211 | $this->assertEquals($cp, []); 212 | } 213 | 214 | /** 215 | * @runInSeparateProcess 216 | * @preserveGlobalState disabled 217 | */ 218 | public function testComponentWithoutDataIsValid() 219 | { 220 | $component = TestHelper::getCustomComponent('SingleComponent', ['name', 'areas']); 221 | 222 | $this->mockComponentManager(); 223 | 224 | $cp = BuildConstructionPlan::fromConfig($component, $this->componentList); 225 | 226 | $this->assertEquals($cp, [ 227 | 'name' => 'SingleComponent', 228 | 'data' => [] 229 | ]); 230 | } 231 | 232 | /** 233 | * @runInSeparateProcess 234 | * @preserveGlobalState disabled 235 | */ 236 | public function testCustomDataIsAddedToComponent() 237 | { 238 | $componentName = 'SingleComponent'; 239 | 240 | // this simulates add_filter with return data: 241 | $component = TestHelper::getCustomComponent($componentName, ['name', 'customData', 'areas']); 242 | 243 | $this->mockComponentManager(); 244 | 245 | $cp = BuildConstructionPlan::fromConfig($component, $this->componentList); 246 | 247 | $this->assertEquals($cp, [ 248 | 'name' => $componentName, 249 | 'data' => [ 250 | 'test0' => 0, 251 | 'test1' => 'string', 252 | 'test2' => [ 253 | 'something strange' 254 | ], 255 | 'duplicate' => 'newValue' 256 | ] 257 | ]); 258 | } 259 | 260 | /** 261 | * @runInSeparateProcess 262 | * @preserveGlobalState disabled 263 | */ 264 | public function testaddComponentDataFiltersAreApplied() 265 | { 266 | // Made this more complex than necessary to also test parentData being passed 267 | $parentComponentName = 'ComponentWithArea'; 268 | $childComponentName = 'SingleComponent'; 269 | 270 | $parentComponent = TestHelper::getCustomComponent($parentComponentName, ['name', 'areas']); 271 | $childComponent = TestHelper::getCompleteComponent($childComponentName); 272 | 273 | $parentComponent['areas'] = [ 274 | 'Area51' => [ 275 | $childComponent 276 | ] 277 | ]; 278 | 279 | $this->mockComponentManager(); 280 | 281 | $parentData = []; 282 | 283 | $childData = [ 284 | 'test0' => 0, 285 | 'test1' => 'string', 286 | 'test2' => [ 287 | 'something strange' 288 | ], 289 | 'duplicate' => 'newValue' 290 | ]; 291 | 292 | $newChildData = array_merge($childData, [ 293 | 'test' => 'fromAddData', 294 | 'something' => 'else' 295 | ]); 296 | 297 | $parentComponentAsArg = array_merge($parentComponent, [ 298 | 'data' => $parentData 299 | ]); 300 | unset($parentComponentAsArg['customData']); 301 | 302 | $childComponentAsArg = array_merge($childComponent, [ 303 | 'data' => $childData 304 | ]); 305 | unset($childComponentAsArg['customData']); 306 | 307 | Filters::expectApplied('Flynt/addComponentData') 308 | ->with($parentData, [], $parentComponentAsArg) 309 | ->ordered() 310 | ->once() 311 | ->andReturn($parentData); 312 | 313 | Filters::expectApplied('Flynt/addComponentData') 314 | ->with($childData, $parentData, $childComponentAsArg) 315 | ->ordered() 316 | ->once() 317 | ->andReturn($childData); 318 | 319 | Filters::expectApplied("Flynt/addComponentData?name={$childComponentName}") 320 | ->with($childData, $parentData, $childComponentAsArg) 321 | ->once() 322 | ->andReturn($newChildData); 323 | 324 | $cp = BuildConstructionPlan::fromConfig($parentComponent, $this->componentList); 325 | 326 | $this->assertEquals($cp, [ 327 | 'name' => $parentComponentName, 328 | 'data' => [], 329 | 'areas' => [ 330 | 'Area51' => [ 331 | [ 332 | 'name' => $childComponentName, 333 | 'data' => [ 334 | 'test' => 'fromAddData', 335 | 'something' => 'else', 336 | 'test0' => 0, 337 | 'test1' => 'string', 338 | 'test2' => [ 339 | 'something strange' 340 | ], 341 | 'duplicate' => 'newValue' 342 | ] 343 | ] 344 | ] 345 | ] 346 | ]); 347 | } 348 | 349 | /** 350 | * @runInSeparateProcess 351 | * @preserveGlobalState disabled 352 | */ 353 | public function testNestedComponentIsAddedToArea() 354 | { 355 | $parentComponentName = 'ComponentWithArea'; 356 | $childComponentName = 'SingleComponent'; 357 | 358 | $component = TestHelper::getCustomComponent($parentComponentName, ['name', 'areas']); 359 | 360 | $component['areas'] = [ 361 | 'Area51' => [ 362 | TestHelper::getCompleteComponent($childComponentName) 363 | ] 364 | ]; 365 | 366 | $this->mockComponentManager(); 367 | 368 | $cp = BuildConstructionPlan::fromConfig($component, $this->componentList); 369 | 370 | $this->assertEquals($cp, [ 371 | 'name' => $parentComponentName, 372 | 'data' => [], 373 | 'areas' => [ 374 | 'Area51' => [ 375 | [ 376 | 'name' => $childComponentName, 377 | 'data' => [ 378 | 'test0' => 0, 379 | 'test1' => 'string', 380 | 'test2' => [ 381 | 'something strange' 382 | ], 383 | 'duplicate' => 'newValue' 384 | ] 385 | ] 386 | ] 387 | ] 388 | ]); 389 | } 390 | 391 | /** 392 | * @runInSeparateProcess 393 | * @preserveGlobalState disabled 394 | */ 395 | public function testParentComponentDataIsNotAddedToChildComponent() 396 | { 397 | $parentComponentName = 'ComponentWithArea'; 398 | $childComponentName = 'SingleComponent'; 399 | 400 | $component = TestHelper::getCustomComponent($parentComponentName, ['name', 'areas']); 401 | $component['customData'] = [ 402 | 'testParentData' => true 403 | ]; 404 | 405 | $component['areas'] = [ 406 | 'area51' => [ 407 | TestHelper::getCustomComponent($childComponentName, ['name']) 408 | ] 409 | ]; 410 | 411 | $this->mockComponentManager(); 412 | 413 | $cp = BuildConstructionPlan::fromConfig($component, $this->componentList); 414 | 415 | $this->assertEquals($cp, [ 416 | 'name' => $parentComponentName, 417 | 'data' => [ 418 | 'testParentData' => true 419 | ], 420 | 'areas' => [ 421 | 'area51' => [ 422 | [ 423 | 'name' => $childComponentName, 424 | 'data' => [] 425 | ] 426 | ] 427 | ] 428 | ]); 429 | } 430 | 431 | /** 432 | * @runInSeparateProcess 433 | * @preserveGlobalState disabled 434 | */ 435 | public function testParentDataIsOverwritten() 436 | { 437 | $parentComponentName = 'ComponentWithArea'; 438 | $childComponentName = 'SingleComponent'; 439 | 440 | $newParentData = [ 441 | 'custom' => 'parentData' 442 | ]; 443 | 444 | $component = TestHelper::getCustomComponent($parentComponentName, ['name', 'areas']); 445 | $childComponent = TestHelper::getCustomComponent($childComponentName, ['name']); 446 | $childComponent['parentData'] = $newParentData; 447 | 448 | $component['customData'] = [ 449 | 'testParentData' => true 450 | ]; 451 | 452 | $component['areas'] = [ 453 | 'area51' => [ 454 | $childComponent 455 | ] 456 | ]; 457 | 458 | $this->mockComponentManager(); 459 | 460 | Filters::expectApplied('Flynt/addComponentData') 461 | ->with(['testParentData' => true], [], Mockery::type('array')) 462 | ->ordered() 463 | ->once() 464 | ->andReturn(['testParentData' => true]); 465 | 466 | Filters::expectApplied('Flynt/addComponentData') 467 | ->with([], $newParentData, Mockery::type('array')) 468 | ->ordered() 469 | ->once() 470 | ->andReturn($newParentData); 471 | 472 | $cp = BuildConstructionPlan::fromConfig($component, $this->componentList); 473 | 474 | $this->assertEquals($cp, [ 475 | 'name' => $parentComponentName, 476 | 'data' => [ 477 | 'testParentData' => true 478 | ], 479 | 'areas' => [ 480 | 'area51' => [ 481 | [ 482 | 'name' => $childComponentName, 483 | 'data' => [ 484 | 'custom' => 'parentData' 485 | ] 486 | ] 487 | ] 488 | ] 489 | ]); 490 | } 491 | 492 | /** 493 | * @runInSeparateProcess 494 | * @preserveGlobalState disabled 495 | */ 496 | public function testDeeplyNestedComponentsCreateValidConstructionPlan() 497 | { 498 | $parentComponentName = 'ComponentWithArea'; 499 | $childComponentName = 'NestedComponentWithArea'; 500 | $grandChildComponentNameA = 'GrandChildA'; 501 | $grandChildComponentNameB = 'GrandChildB'; 502 | $grandChildComponentNameC = 'GrandChildC'; 503 | 504 | $component = TestHelper::getCustomComponent($parentComponentName, ['name', 'areas']); 505 | 506 | $component['areas'] = [ 507 | 'area51' => [ 508 | TestHelper::getCustomComponent($childComponentName, ['name', 'areas']) 509 | ] 510 | ]; 511 | 512 | $component['areas']['area51'][0]['areas'] = [ 513 | 'district9' => [ 514 | TestHelper::getCustomComponent($grandChildComponentNameA, ['name']) 515 | ], 516 | 'alderaan' => [ 517 | TestHelper::getCustomComponent($grandChildComponentNameB, ['name']), 518 | TestHelper::getCustomComponent($grandChildComponentNameC, ['name']) 519 | ] 520 | ]; 521 | 522 | $this->mockComponentManager(); 523 | 524 | $cp = BuildConstructionPlan::fromConfig($component, $this->componentList); 525 | 526 | $this->assertEquals($cp, [ 527 | 'name' => $parentComponentName, 528 | 'data' => [], 529 | 'areas' => [ 530 | 'area51' => [ 531 | [ 532 | 'name' => $childComponentName, 533 | 'data' => [], 534 | 'areas' => [ 535 | 'district9' => [ 536 | [ 537 | 'name' => $grandChildComponentNameA, 538 | 'data' => [] 539 | ] 540 | ], 541 | 'alderaan' => [ 542 | [ 543 | 'name' => $grandChildComponentNameB, 544 | 'data' => [] 545 | ], 546 | [ 547 | 'name' => $grandChildComponentNameC, 548 | 'data' => [] 549 | ] 550 | ] 551 | ] 552 | ] 553 | ] 554 | ] 555 | ]); 556 | } 557 | 558 | /** 559 | * @runInSeparateProcess 560 | * @preserveGlobalState disabled 561 | */ 562 | public function testDynamicSubcomponentsCanBeAddedWithAFilter() 563 | { 564 | $componentName = 'ComponentWithArea'; 565 | $dynamicComponentName = 'SingleComponent'; 566 | 567 | $component = TestHelper::getCustomComponent($componentName, ['name', 'areas']); 568 | $dynamicComponent = TestHelper::getCustomComponent($dynamicComponentName, ['name']); 569 | 570 | Filters::expectApplied("Flynt/dynamicSubcomponents?name={$componentName}") 571 | ->with([], [], []) 572 | ->once() 573 | ->andReturn(['area51' => [ $dynamicComponent ]]); 574 | 575 | $this->mockComponentManager(); 576 | 577 | $cp = BuildConstructionPlan::fromConfig($component, $this->componentList); 578 | 579 | $this->assertEquals($cp, [ 580 | 'name' => $componentName, 581 | 'data' => [], 582 | 'areas' => [ 583 | 'area51' => [ 584 | [ 585 | 'name' => $dynamicComponentName, 586 | 'data' => [] 587 | ] 588 | ] 589 | ] 590 | ]); 591 | } 592 | 593 | /** 594 | * @runInSeparateProcess 595 | * @preserveGlobalState disabled 596 | */ 597 | public function testDynamicSubcomponentsReceiveParentData() 598 | { 599 | $parentComponentName = 'ComponentWithArea'; 600 | $childComponentName = 'NestedComponentWithArea'; 601 | $childSubcomponentName = 'SingleComponent'; 602 | $dynamicComponentName = 'DynamicComponent'; 603 | 604 | $parentComponent = TestHelper::getCustomComponent($parentComponentName, ['name', 'areas']); 605 | $childComponent = TestHelper::getCustomComponent($childComponentName, ['name']); 606 | $childSubcomponent = TestHelper::getCustomComponent($childSubcomponentName, ['name']); 607 | $dynamicComponent = TestHelper::getCustomComponent($dynamicComponentName, ['name']); 608 | 609 | $childComponent['areas'] = [ 610 | 'childArea' => [ $childSubcomponent ] 611 | ]; 612 | $parentComponent['areas'] = [ 613 | 'parentArea' => [ $childComponent ] 614 | ]; 615 | 616 | $parentComponent['customData'] = [ 617 | 'testParentData' => true 618 | ]; 619 | 620 | Filters::expectApplied("Flynt/dynamicSubcomponents?name={$childSubcomponentName}") 621 | ->with([], [], ['testParentData' => true]) 622 | ->once() 623 | ->andReturn(['area51' => [ $dynamicComponent ]]); 624 | 625 | $this->mockComponentManager(); 626 | 627 | $cp = BuildConstructionPlan::fromConfig($parentComponent, $this->componentList); 628 | 629 | $this->assertEquals($cp, [ 630 | 'name' => $parentComponentName, 631 | 'data' => [ 632 | 'testParentData' => true 633 | ], 634 | 'areas' => [ 635 | 'parentArea' => [ 636 | [ 637 | 'name' => $childComponentName, 638 | 'data' => [], 639 | 'areas' => [ 640 | 'childArea' => [ 641 | [ 642 | 'name' => $childSubcomponentName, 643 | 'data' => [], 644 | 'areas' => [ 645 | 'area51' => [ 646 | [ 647 | 'name' => $dynamicComponentName, 648 | 'data' => [] 649 | ] 650 | ] 651 | ] 652 | ] 653 | ] 654 | ] 655 | ] 656 | ] 657 | ] 658 | ]); 659 | } 660 | 661 | /** 662 | * @runInSeparateProcess 663 | * @preserveGlobalState disabled 664 | */ 665 | public function testInvalidComponentsInAreasAreRemoved() 666 | { 667 | $parentComponentName = 'ComponentWithArea'; 668 | $childComponentName = 'DoesNotExist'; 669 | 670 | $component = TestHelper::getCustomComponent($parentComponentName, ['name', 'areas']); 671 | 672 | $component['areas'] = [ 673 | 'area51' => [ 674 | TestHelper::getCustomComponent($childComponentName, ['name']) 675 | ] 676 | ]; 677 | 678 | $this->mockComponentManager(); 679 | 680 | $cp = @BuildConstructionPlan::fromConfig($component, $this->componentList); 681 | $this->assertEquals($cp, [ 682 | 'name' => $parentComponentName, 683 | 'data' => [], 684 | 'areas' => [ 685 | 'area51' => [] 686 | ] 687 | ]); 688 | } 689 | 690 | public function testDoesBeforeAndAfterActions() 691 | { 692 | $config = [ 693 | 'name' => 'test' 694 | ]; 695 | 696 | $expectedConstructionPlan = []; 697 | 698 | Actions::expectFired('Flynt/beforeBuildConstructionPlan') 699 | ->once() 700 | ->with($config); 701 | 702 | Actions::expectFired('Flynt/afterBuildConstructionPlan') 703 | ->once() 704 | ->with($expectedConstructionPlan); 705 | 706 | $cp = @BuildConstructionPlan::fromConfig($config); 707 | } 708 | 709 | // Helpers 710 | public function mockComponentManager() 711 | { 712 | $componentManagerMock = Mockery::mock('ComponentManager'); 713 | 714 | Mockery::mock('alias:Flynt\ComponentManager') 715 | ->shouldReceive('getInstance') 716 | ->andReturn($componentManagerMock); 717 | 718 | $componentManagerMock 719 | ->shouldReceive('isRegistered') 720 | ->andReturnUsing([$this, 'componentIsInList']); 721 | } 722 | 723 | public function componentIsInList($componentName) 724 | { 725 | return array_key_exists($componentName, $this->componentList); 726 | } 727 | } 728 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "593faa4aa9af9e84a5cf6b5027e03c20", 8 | "packages": [ 9 | { 10 | "name": "composer/installers", 11 | "version": "v1.2.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/composer/installers.git", 15 | "reference": "d78064c68299743e0161004f2de3a0204e33b804" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/composer/installers/zipball/d78064c68299743e0161004f2de3a0204e33b804", 20 | "reference": "d78064c68299743e0161004f2de3a0204e33b804", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "composer-plugin-api": "^1.0" 25 | }, 26 | "replace": { 27 | "roundcube/plugin-installer": "*", 28 | "shama/baton": "*" 29 | }, 30 | "require-dev": { 31 | "composer/composer": "1.0.*@dev", 32 | "phpunit/phpunit": "4.1.*" 33 | }, 34 | "type": "composer-plugin", 35 | "extra": { 36 | "class": "Composer\\Installers\\Plugin", 37 | "branch-alias": { 38 | "dev-master": "1.0-dev" 39 | } 40 | }, 41 | "autoload": { 42 | "psr-4": { 43 | "Composer\\Installers\\": "src/Composer/Installers" 44 | } 45 | }, 46 | "notification-url": "https://packagist.org/downloads/", 47 | "license": [ 48 | "MIT" 49 | ], 50 | "authors": [ 51 | { 52 | "name": "Kyle Robinson Young", 53 | "email": "kyle@dontkry.com", 54 | "homepage": "https://github.com/shama" 55 | } 56 | ], 57 | "description": "A multi-framework Composer library installer", 58 | "homepage": "https://composer.github.io/installers/", 59 | "keywords": [ 60 | "Craft", 61 | "Dolibarr", 62 | "Hurad", 63 | "ImageCMS", 64 | "MODX Evo", 65 | "Mautic", 66 | "OXID", 67 | "Plentymarkets", 68 | "RadPHP", 69 | "SMF", 70 | "Thelia", 71 | "WolfCMS", 72 | "agl", 73 | "aimeos", 74 | "annotatecms", 75 | "attogram", 76 | "bitrix", 77 | "cakephp", 78 | "chef", 79 | "cockpit", 80 | "codeigniter", 81 | "concrete5", 82 | "croogo", 83 | "dokuwiki", 84 | "drupal", 85 | "elgg", 86 | "expressionengine", 87 | "fuelphp", 88 | "grav", 89 | "installer", 90 | "joomla", 91 | "kohana", 92 | "laravel", 93 | "lithium", 94 | "magento", 95 | "mako", 96 | "mediawiki", 97 | "modulework", 98 | "moodle", 99 | "phpbb", 100 | "piwik", 101 | "ppi", 102 | "puppet", 103 | "reindex", 104 | "roundcube", 105 | "shopware", 106 | "silverstripe", 107 | "symfony", 108 | "typo3", 109 | "wordpress", 110 | "yawik", 111 | "zend", 112 | "zikula" 113 | ], 114 | "time": "2016-08-13T20:53:52+00:00" 115 | } 116 | ], 117 | "packages-dev": [ 118 | { 119 | "name": "antecedent/patchwork", 120 | "version": "1.3.5", 121 | "source": { 122 | "type": "git", 123 | "url": "https://github.com/antecedent/patchwork.git", 124 | "reference": "908a233f8a374f02b02ff5e3d6ba687ca506d57d" 125 | }, 126 | "dist": { 127 | "type": "zip", 128 | "url": "https://api.github.com/repos/antecedent/patchwork/zipball/908a233f8a374f02b02ff5e3d6ba687ca506d57d", 129 | "reference": "908a233f8a374f02b02ff5e3d6ba687ca506d57d", 130 | "shasum": "" 131 | }, 132 | "require": { 133 | "php": ">=5.3.0" 134 | }, 135 | "type": "library", 136 | "notification-url": "https://packagist.org/downloads/", 137 | "license": [ 138 | "MIT" 139 | ], 140 | "authors": [ 141 | { 142 | "name": "Ignas Rudaitis", 143 | "email": "ignas.rudaitis@gmail.com" 144 | } 145 | ], 146 | "description": "A pure PHP library that lets you redefine user-defined functions at runtime.", 147 | "homepage": "http://antecedent.github.io/patchwork/", 148 | "keywords": [ 149 | "aop", 150 | "aspect", 151 | "interception", 152 | "monkeypatching", 153 | "redefinition", 154 | "runkit", 155 | "testing" 156 | ], 157 | "time": "2015-10-09T18:20:06+00:00" 158 | }, 159 | { 160 | "name": "brain/monkey", 161 | "version": "1.4.1", 162 | "source": { 163 | "type": "git", 164 | "url": "https://github.com/Brain-WP/BrainMonkey.git", 165 | "reference": "83664e72cb126c5e1edfbffb52a9f06fc6ef0fd5" 166 | }, 167 | "dist": { 168 | "type": "zip", 169 | "url": "https://api.github.com/repos/Brain-WP/BrainMonkey/zipball/83664e72cb126c5e1edfbffb52a9f06fc6ef0fd5", 170 | "reference": "83664e72cb126c5e1edfbffb52a9f06fc6ef0fd5", 171 | "shasum": "" 172 | }, 173 | "require": { 174 | "antecedent/patchwork": "1.3.*", 175 | "mockery/mockery": "*", 176 | "php": ">=5.4.0" 177 | }, 178 | "require-dev": { 179 | "mockery/mockery": "0.9.3", 180 | "phpunit/phpunit": "~4.8" 181 | }, 182 | "type": "library", 183 | "extra": { 184 | "branch-alias": { 185 | "dev-master": "1.0.x-dev" 186 | } 187 | }, 188 | "autoload": { 189 | "psr-4": { 190 | "Brain\\": "src/" 191 | } 192 | }, 193 | "notification-url": "https://packagist.org/downloads/", 194 | "license": [ 195 | "MIT" 196 | ], 197 | "authors": [ 198 | { 199 | "name": "Giuseppe Mazzapica", 200 | "email": "giuseppe.mazzapica@gmail.com", 201 | "homepage": "http://gm.zoomlab.it", 202 | "role": "Developer" 203 | } 204 | ], 205 | "description": "Mocking utility for PHP functions and WordPress plugin API", 206 | "keywords": [ 207 | "Monkey Patching", 208 | "interception", 209 | "mock", 210 | "mock functions", 211 | "mockery", 212 | "patchwork", 213 | "redefinition", 214 | "runkit", 215 | "test", 216 | "testing" 217 | ], 218 | "time": "2016-10-14T15:21:25+00:00" 219 | }, 220 | { 221 | "name": "doctrine/instantiator", 222 | "version": "1.0.5", 223 | "source": { 224 | "type": "git", 225 | "url": "https://github.com/doctrine/instantiator.git", 226 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" 227 | }, 228 | "dist": { 229 | "type": "zip", 230 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", 231 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", 232 | "shasum": "" 233 | }, 234 | "require": { 235 | "php": ">=5.3,<8.0-DEV" 236 | }, 237 | "require-dev": { 238 | "athletic/athletic": "~0.1.8", 239 | "ext-pdo": "*", 240 | "ext-phar": "*", 241 | "phpunit/phpunit": "~4.0", 242 | "squizlabs/php_codesniffer": "~2.0" 243 | }, 244 | "type": "library", 245 | "extra": { 246 | "branch-alias": { 247 | "dev-master": "1.0.x-dev" 248 | } 249 | }, 250 | "autoload": { 251 | "psr-4": { 252 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 253 | } 254 | }, 255 | "notification-url": "https://packagist.org/downloads/", 256 | "license": [ 257 | "MIT" 258 | ], 259 | "authors": [ 260 | { 261 | "name": "Marco Pivetta", 262 | "email": "ocramius@gmail.com", 263 | "homepage": "http://ocramius.github.com/" 264 | } 265 | ], 266 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 267 | "homepage": "https://github.com/doctrine/instantiator", 268 | "keywords": [ 269 | "constructor", 270 | "instantiate" 271 | ], 272 | "time": "2015-06-14T21:17:01+00:00" 273 | }, 274 | { 275 | "name": "hamcrest/hamcrest-php", 276 | "version": "v1.2.2", 277 | "source": { 278 | "type": "git", 279 | "url": "https://github.com/hamcrest/hamcrest-php.git", 280 | "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c" 281 | }, 282 | "dist": { 283 | "type": "zip", 284 | "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/b37020aa976fa52d3de9aa904aa2522dc518f79c", 285 | "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c", 286 | "shasum": "" 287 | }, 288 | "require": { 289 | "php": ">=5.3.2" 290 | }, 291 | "replace": { 292 | "cordoval/hamcrest-php": "*", 293 | "davedevelopment/hamcrest-php": "*", 294 | "kodova/hamcrest-php": "*" 295 | }, 296 | "require-dev": { 297 | "phpunit/php-file-iterator": "1.3.3", 298 | "satooshi/php-coveralls": "dev-master" 299 | }, 300 | "type": "library", 301 | "autoload": { 302 | "classmap": [ 303 | "hamcrest" 304 | ], 305 | "files": [ 306 | "hamcrest/Hamcrest.php" 307 | ] 308 | }, 309 | "notification-url": "https://packagist.org/downloads/", 310 | "license": [ 311 | "BSD" 312 | ], 313 | "description": "This is the PHP port of Hamcrest Matchers", 314 | "keywords": [ 315 | "test" 316 | ], 317 | "time": "2015-05-11T14:41:42+00:00" 318 | }, 319 | { 320 | "name": "mockery/mockery", 321 | "version": "0.9.5", 322 | "source": { 323 | "type": "git", 324 | "url": "https://github.com/padraic/mockery.git", 325 | "reference": "4db079511a283e5aba1b3c2fb19037c645e70fc2" 326 | }, 327 | "dist": { 328 | "type": "zip", 329 | "url": "https://api.github.com/repos/padraic/mockery/zipball/4db079511a283e5aba1b3c2fb19037c645e70fc2", 330 | "reference": "4db079511a283e5aba1b3c2fb19037c645e70fc2", 331 | "shasum": "" 332 | }, 333 | "require": { 334 | "hamcrest/hamcrest-php": "~1.1", 335 | "lib-pcre": ">=7.0", 336 | "php": ">=5.3.2" 337 | }, 338 | "require-dev": { 339 | "phpunit/phpunit": "~4.0" 340 | }, 341 | "type": "library", 342 | "extra": { 343 | "branch-alias": { 344 | "dev-master": "0.9.x-dev" 345 | } 346 | }, 347 | "autoload": { 348 | "psr-0": { 349 | "Mockery": "library/" 350 | } 351 | }, 352 | "notification-url": "https://packagist.org/downloads/", 353 | "license": [ 354 | "BSD-3-Clause" 355 | ], 356 | "authors": [ 357 | { 358 | "name": "Pádraic Brady", 359 | "email": "padraic.brady@gmail.com", 360 | "homepage": "http://blog.astrumfutura.com" 361 | }, 362 | { 363 | "name": "Dave Marshall", 364 | "email": "dave.marshall@atstsolutions.co.uk", 365 | "homepage": "http://davedevelopment.co.uk" 366 | } 367 | ], 368 | "description": "Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending.", 369 | "homepage": "http://github.com/padraic/mockery", 370 | "keywords": [ 371 | "BDD", 372 | "TDD", 373 | "library", 374 | "mock", 375 | "mock objects", 376 | "mockery", 377 | "stub", 378 | "test", 379 | "test double", 380 | "testing" 381 | ], 382 | "time": "2016-05-22T21:52:33+00:00" 383 | }, 384 | { 385 | "name": "myclabs/deep-copy", 386 | "version": "1.5.5", 387 | "source": { 388 | "type": "git", 389 | "url": "https://github.com/myclabs/DeepCopy.git", 390 | "reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108" 391 | }, 392 | "dist": { 393 | "type": "zip", 394 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/399c1f9781e222f6eb6cc238796f5200d1b7f108", 395 | "reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108", 396 | "shasum": "" 397 | }, 398 | "require": { 399 | "php": ">=5.4.0" 400 | }, 401 | "require-dev": { 402 | "doctrine/collections": "1.*", 403 | "phpunit/phpunit": "~4.1" 404 | }, 405 | "type": "library", 406 | "autoload": { 407 | "psr-4": { 408 | "DeepCopy\\": "src/DeepCopy/" 409 | } 410 | }, 411 | "notification-url": "https://packagist.org/downloads/", 412 | "license": [ 413 | "MIT" 414 | ], 415 | "description": "Create deep copies (clones) of your objects", 416 | "homepage": "https://github.com/myclabs/DeepCopy", 417 | "keywords": [ 418 | "clone", 419 | "copy", 420 | "duplicate", 421 | "object", 422 | "object graph" 423 | ], 424 | "time": "2016-10-31T17:19:45+00:00" 425 | }, 426 | { 427 | "name": "phpdocumentor/reflection-common", 428 | "version": "1.0", 429 | "source": { 430 | "type": "git", 431 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 432 | "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" 433 | }, 434 | "dist": { 435 | "type": "zip", 436 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", 437 | "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", 438 | "shasum": "" 439 | }, 440 | "require": { 441 | "php": ">=5.5" 442 | }, 443 | "require-dev": { 444 | "phpunit/phpunit": "^4.6" 445 | }, 446 | "type": "library", 447 | "extra": { 448 | "branch-alias": { 449 | "dev-master": "1.0.x-dev" 450 | } 451 | }, 452 | "autoload": { 453 | "psr-4": { 454 | "phpDocumentor\\Reflection\\": [ 455 | "src" 456 | ] 457 | } 458 | }, 459 | "notification-url": "https://packagist.org/downloads/", 460 | "license": [ 461 | "MIT" 462 | ], 463 | "authors": [ 464 | { 465 | "name": "Jaap van Otterdijk", 466 | "email": "opensource@ijaap.nl" 467 | } 468 | ], 469 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 470 | "homepage": "http://www.phpdoc.org", 471 | "keywords": [ 472 | "FQSEN", 473 | "phpDocumentor", 474 | "phpdoc", 475 | "reflection", 476 | "static analysis" 477 | ], 478 | "time": "2015-12-27T11:43:31+00:00" 479 | }, 480 | { 481 | "name": "phpdocumentor/reflection-docblock", 482 | "version": "3.1.1", 483 | "source": { 484 | "type": "git", 485 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 486 | "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" 487 | }, 488 | "dist": { 489 | "type": "zip", 490 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", 491 | "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", 492 | "shasum": "" 493 | }, 494 | "require": { 495 | "php": ">=5.5", 496 | "phpdocumentor/reflection-common": "^1.0@dev", 497 | "phpdocumentor/type-resolver": "^0.2.0", 498 | "webmozart/assert": "^1.0" 499 | }, 500 | "require-dev": { 501 | "mockery/mockery": "^0.9.4", 502 | "phpunit/phpunit": "^4.4" 503 | }, 504 | "type": "library", 505 | "autoload": { 506 | "psr-4": { 507 | "phpDocumentor\\Reflection\\": [ 508 | "src/" 509 | ] 510 | } 511 | }, 512 | "notification-url": "https://packagist.org/downloads/", 513 | "license": [ 514 | "MIT" 515 | ], 516 | "authors": [ 517 | { 518 | "name": "Mike van Riel", 519 | "email": "me@mikevanriel.com" 520 | } 521 | ], 522 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 523 | "time": "2016-09-30T07:12:33+00:00" 524 | }, 525 | { 526 | "name": "phpdocumentor/type-resolver", 527 | "version": "0.2", 528 | "source": { 529 | "type": "git", 530 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 531 | "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443" 532 | }, 533 | "dist": { 534 | "type": "zip", 535 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443", 536 | "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443", 537 | "shasum": "" 538 | }, 539 | "require": { 540 | "php": ">=5.5", 541 | "phpdocumentor/reflection-common": "^1.0" 542 | }, 543 | "require-dev": { 544 | "mockery/mockery": "^0.9.4", 545 | "phpunit/phpunit": "^5.2||^4.8.24" 546 | }, 547 | "type": "library", 548 | "extra": { 549 | "branch-alias": { 550 | "dev-master": "1.0.x-dev" 551 | } 552 | }, 553 | "autoload": { 554 | "psr-4": { 555 | "phpDocumentor\\Reflection\\": [ 556 | "src/" 557 | ] 558 | } 559 | }, 560 | "notification-url": "https://packagist.org/downloads/", 561 | "license": [ 562 | "MIT" 563 | ], 564 | "authors": [ 565 | { 566 | "name": "Mike van Riel", 567 | "email": "me@mikevanriel.com" 568 | } 569 | ], 570 | "time": "2016-06-10T07:14:17+00:00" 571 | }, 572 | { 573 | "name": "phpspec/prophecy", 574 | "version": "v1.6.1", 575 | "source": { 576 | "type": "git", 577 | "url": "https://github.com/phpspec/prophecy.git", 578 | "reference": "58a8137754bc24b25740d4281399a4a3596058e0" 579 | }, 580 | "dist": { 581 | "type": "zip", 582 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", 583 | "reference": "58a8137754bc24b25740d4281399a4a3596058e0", 584 | "shasum": "" 585 | }, 586 | "require": { 587 | "doctrine/instantiator": "^1.0.2", 588 | "php": "^5.3|^7.0", 589 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", 590 | "sebastian/comparator": "^1.1", 591 | "sebastian/recursion-context": "^1.0" 592 | }, 593 | "require-dev": { 594 | "phpspec/phpspec": "^2.0" 595 | }, 596 | "type": "library", 597 | "extra": { 598 | "branch-alias": { 599 | "dev-master": "1.6.x-dev" 600 | } 601 | }, 602 | "autoload": { 603 | "psr-0": { 604 | "Prophecy\\": "src/" 605 | } 606 | }, 607 | "notification-url": "https://packagist.org/downloads/", 608 | "license": [ 609 | "MIT" 610 | ], 611 | "authors": [ 612 | { 613 | "name": "Konstantin Kudryashov", 614 | "email": "ever.zet@gmail.com", 615 | "homepage": "http://everzet.com" 616 | }, 617 | { 618 | "name": "Marcello Duarte", 619 | "email": "marcello.duarte@gmail.com" 620 | } 621 | ], 622 | "description": "Highly opinionated mocking framework for PHP 5.3+", 623 | "homepage": "https://github.com/phpspec/prophecy", 624 | "keywords": [ 625 | "Double", 626 | "Dummy", 627 | "fake", 628 | "mock", 629 | "spy", 630 | "stub" 631 | ], 632 | "time": "2016-06-07T08:13:47+00:00" 633 | }, 634 | { 635 | "name": "phpunit/php-code-coverage", 636 | "version": "4.0.2", 637 | "source": { 638 | "type": "git", 639 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 640 | "reference": "6cba06ff75a1a63a71033e1a01b89056f3af1e8d" 641 | }, 642 | "dist": { 643 | "type": "zip", 644 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6cba06ff75a1a63a71033e1a01b89056f3af1e8d", 645 | "reference": "6cba06ff75a1a63a71033e1a01b89056f3af1e8d", 646 | "shasum": "" 647 | }, 648 | "require": { 649 | "php": "^5.6 || ^7.0", 650 | "phpunit/php-file-iterator": "~1.3", 651 | "phpunit/php-text-template": "~1.2", 652 | "phpunit/php-token-stream": "^1.4.2", 653 | "sebastian/code-unit-reverse-lookup": "~1.0", 654 | "sebastian/environment": "^1.3.2 || ^2.0", 655 | "sebastian/version": "~1.0|~2.0" 656 | }, 657 | "require-dev": { 658 | "ext-xdebug": ">=2.1.4", 659 | "phpunit/phpunit": "^5.4" 660 | }, 661 | "suggest": { 662 | "ext-dom": "*", 663 | "ext-xdebug": ">=2.4.0", 664 | "ext-xmlwriter": "*" 665 | }, 666 | "type": "library", 667 | "extra": { 668 | "branch-alias": { 669 | "dev-master": "4.0.x-dev" 670 | } 671 | }, 672 | "autoload": { 673 | "classmap": [ 674 | "src/" 675 | ] 676 | }, 677 | "notification-url": "https://packagist.org/downloads/", 678 | "license": [ 679 | "BSD-3-Clause" 680 | ], 681 | "authors": [ 682 | { 683 | "name": "Sebastian Bergmann", 684 | "email": "sb@sebastian-bergmann.de", 685 | "role": "lead" 686 | } 687 | ], 688 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 689 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 690 | "keywords": [ 691 | "coverage", 692 | "testing", 693 | "xunit" 694 | ], 695 | "time": "2016-11-01T05:06:24+00:00" 696 | }, 697 | { 698 | "name": "phpunit/php-file-iterator", 699 | "version": "1.4.1", 700 | "source": { 701 | "type": "git", 702 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 703 | "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" 704 | }, 705 | "dist": { 706 | "type": "zip", 707 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", 708 | "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", 709 | "shasum": "" 710 | }, 711 | "require": { 712 | "php": ">=5.3.3" 713 | }, 714 | "type": "library", 715 | "extra": { 716 | "branch-alias": { 717 | "dev-master": "1.4.x-dev" 718 | } 719 | }, 720 | "autoload": { 721 | "classmap": [ 722 | "src/" 723 | ] 724 | }, 725 | "notification-url": "https://packagist.org/downloads/", 726 | "license": [ 727 | "BSD-3-Clause" 728 | ], 729 | "authors": [ 730 | { 731 | "name": "Sebastian Bergmann", 732 | "email": "sb@sebastian-bergmann.de", 733 | "role": "lead" 734 | } 735 | ], 736 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 737 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 738 | "keywords": [ 739 | "filesystem", 740 | "iterator" 741 | ], 742 | "time": "2015-06-21T13:08:43+00:00" 743 | }, 744 | { 745 | "name": "phpunit/php-text-template", 746 | "version": "1.2.1", 747 | "source": { 748 | "type": "git", 749 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 750 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 751 | }, 752 | "dist": { 753 | "type": "zip", 754 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 755 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 756 | "shasum": "" 757 | }, 758 | "require": { 759 | "php": ">=5.3.3" 760 | }, 761 | "type": "library", 762 | "autoload": { 763 | "classmap": [ 764 | "src/" 765 | ] 766 | }, 767 | "notification-url": "https://packagist.org/downloads/", 768 | "license": [ 769 | "BSD-3-Clause" 770 | ], 771 | "authors": [ 772 | { 773 | "name": "Sebastian Bergmann", 774 | "email": "sebastian@phpunit.de", 775 | "role": "lead" 776 | } 777 | ], 778 | "description": "Simple template engine.", 779 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 780 | "keywords": [ 781 | "template" 782 | ], 783 | "time": "2015-06-21T13:50:34+00:00" 784 | }, 785 | { 786 | "name": "phpunit/php-timer", 787 | "version": "1.0.8", 788 | "source": { 789 | "type": "git", 790 | "url": "https://github.com/sebastianbergmann/php-timer.git", 791 | "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" 792 | }, 793 | "dist": { 794 | "type": "zip", 795 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", 796 | "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", 797 | "shasum": "" 798 | }, 799 | "require": { 800 | "php": ">=5.3.3" 801 | }, 802 | "require-dev": { 803 | "phpunit/phpunit": "~4|~5" 804 | }, 805 | "type": "library", 806 | "autoload": { 807 | "classmap": [ 808 | "src/" 809 | ] 810 | }, 811 | "notification-url": "https://packagist.org/downloads/", 812 | "license": [ 813 | "BSD-3-Clause" 814 | ], 815 | "authors": [ 816 | { 817 | "name": "Sebastian Bergmann", 818 | "email": "sb@sebastian-bergmann.de", 819 | "role": "lead" 820 | } 821 | ], 822 | "description": "Utility class for timing", 823 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 824 | "keywords": [ 825 | "timer" 826 | ], 827 | "time": "2016-05-12T18:03:57+00:00" 828 | }, 829 | { 830 | "name": "phpunit/php-token-stream", 831 | "version": "1.4.8", 832 | "source": { 833 | "type": "git", 834 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 835 | "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" 836 | }, 837 | "dist": { 838 | "type": "zip", 839 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", 840 | "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", 841 | "shasum": "" 842 | }, 843 | "require": { 844 | "ext-tokenizer": "*", 845 | "php": ">=5.3.3" 846 | }, 847 | "require-dev": { 848 | "phpunit/phpunit": "~4.2" 849 | }, 850 | "type": "library", 851 | "extra": { 852 | "branch-alias": { 853 | "dev-master": "1.4-dev" 854 | } 855 | }, 856 | "autoload": { 857 | "classmap": [ 858 | "src/" 859 | ] 860 | }, 861 | "notification-url": "https://packagist.org/downloads/", 862 | "license": [ 863 | "BSD-3-Clause" 864 | ], 865 | "authors": [ 866 | { 867 | "name": "Sebastian Bergmann", 868 | "email": "sebastian@phpunit.de" 869 | } 870 | ], 871 | "description": "Wrapper around PHP's tokenizer extension.", 872 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 873 | "keywords": [ 874 | "tokenizer" 875 | ], 876 | "time": "2015-09-15T10:49:45+00:00" 877 | }, 878 | { 879 | "name": "phpunit/phpunit", 880 | "version": "5.6.2", 881 | "source": { 882 | "type": "git", 883 | "url": "https://github.com/sebastianbergmann/phpunit.git", 884 | "reference": "cd13b23ac5a519a4708e00736c26ee0bb28b2e01" 885 | }, 886 | "dist": { 887 | "type": "zip", 888 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/cd13b23ac5a519a4708e00736c26ee0bb28b2e01", 889 | "reference": "cd13b23ac5a519a4708e00736c26ee0bb28b2e01", 890 | "shasum": "" 891 | }, 892 | "require": { 893 | "ext-dom": "*", 894 | "ext-json": "*", 895 | "ext-libxml": "*", 896 | "ext-mbstring": "*", 897 | "ext-xml": "*", 898 | "myclabs/deep-copy": "~1.3", 899 | "php": "^5.6 || ^7.0", 900 | "phpspec/prophecy": "^1.3.1", 901 | "phpunit/php-code-coverage": "^4.0.1", 902 | "phpunit/php-file-iterator": "~1.4", 903 | "phpunit/php-text-template": "~1.2", 904 | "phpunit/php-timer": "^1.0.6", 905 | "phpunit/phpunit-mock-objects": "^3.2", 906 | "sebastian/comparator": "~1.1", 907 | "sebastian/diff": "~1.2", 908 | "sebastian/environment": "^1.3 || ^2.0", 909 | "sebastian/exporter": "~1.2", 910 | "sebastian/global-state": "~1.0", 911 | "sebastian/object-enumerator": "~1.0", 912 | "sebastian/resource-operations": "~1.0", 913 | "sebastian/version": "~1.0|~2.0", 914 | "symfony/yaml": "~2.1|~3.0" 915 | }, 916 | "conflict": { 917 | "phpdocumentor/reflection-docblock": "3.0.2" 918 | }, 919 | "require-dev": { 920 | "ext-pdo": "*" 921 | }, 922 | "suggest": { 923 | "ext-xdebug": "*", 924 | "phpunit/php-invoker": "~1.1" 925 | }, 926 | "bin": [ 927 | "phpunit" 928 | ], 929 | "type": "library", 930 | "extra": { 931 | "branch-alias": { 932 | "dev-master": "5.6.x-dev" 933 | } 934 | }, 935 | "autoload": { 936 | "classmap": [ 937 | "src/" 938 | ] 939 | }, 940 | "notification-url": "https://packagist.org/downloads/", 941 | "license": [ 942 | "BSD-3-Clause" 943 | ], 944 | "authors": [ 945 | { 946 | "name": "Sebastian Bergmann", 947 | "email": "sebastian@phpunit.de", 948 | "role": "lead" 949 | } 950 | ], 951 | "description": "The PHP Unit Testing framework.", 952 | "homepage": "https://phpunit.de/", 953 | "keywords": [ 954 | "phpunit", 955 | "testing", 956 | "xunit" 957 | ], 958 | "time": "2016-10-25T07:40:25+00:00" 959 | }, 960 | { 961 | "name": "phpunit/phpunit-mock-objects", 962 | "version": "3.4.0", 963 | "source": { 964 | "type": "git", 965 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 966 | "reference": "238d7a2723bce689c79eeac9c7d5e1d623bb9dc2" 967 | }, 968 | "dist": { 969 | "type": "zip", 970 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/238d7a2723bce689c79eeac9c7d5e1d623bb9dc2", 971 | "reference": "238d7a2723bce689c79eeac9c7d5e1d623bb9dc2", 972 | "shasum": "" 973 | }, 974 | "require": { 975 | "doctrine/instantiator": "^1.0.2", 976 | "php": "^5.6 || ^7.0", 977 | "phpunit/php-text-template": "^1.2", 978 | "sebastian/exporter": "^1.2" 979 | }, 980 | "conflict": { 981 | "phpunit/phpunit": "<5.4.0" 982 | }, 983 | "require-dev": { 984 | "phpunit/phpunit": "^5.4" 985 | }, 986 | "suggest": { 987 | "ext-soap": "*" 988 | }, 989 | "type": "library", 990 | "extra": { 991 | "branch-alias": { 992 | "dev-master": "3.2.x-dev" 993 | } 994 | }, 995 | "autoload": { 996 | "classmap": [ 997 | "src/" 998 | ] 999 | }, 1000 | "notification-url": "https://packagist.org/downloads/", 1001 | "license": [ 1002 | "BSD-3-Clause" 1003 | ], 1004 | "authors": [ 1005 | { 1006 | "name": "Sebastian Bergmann", 1007 | "email": "sb@sebastian-bergmann.de", 1008 | "role": "lead" 1009 | } 1010 | ], 1011 | "description": "Mock Object library for PHPUnit", 1012 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 1013 | "keywords": [ 1014 | "mock", 1015 | "xunit" 1016 | ], 1017 | "time": "2016-10-09T07:01:45+00:00" 1018 | }, 1019 | { 1020 | "name": "sebastian/code-unit-reverse-lookup", 1021 | "version": "1.0.0", 1022 | "source": { 1023 | "type": "git", 1024 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 1025 | "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe" 1026 | }, 1027 | "dist": { 1028 | "type": "zip", 1029 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/c36f5e7cfce482fde5bf8d10d41a53591e0198fe", 1030 | "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe", 1031 | "shasum": "" 1032 | }, 1033 | "require": { 1034 | "php": ">=5.6" 1035 | }, 1036 | "require-dev": { 1037 | "phpunit/phpunit": "~5" 1038 | }, 1039 | "type": "library", 1040 | "extra": { 1041 | "branch-alias": { 1042 | "dev-master": "1.0.x-dev" 1043 | } 1044 | }, 1045 | "autoload": { 1046 | "classmap": [ 1047 | "src/" 1048 | ] 1049 | }, 1050 | "notification-url": "https://packagist.org/downloads/", 1051 | "license": [ 1052 | "BSD-3-Clause" 1053 | ], 1054 | "authors": [ 1055 | { 1056 | "name": "Sebastian Bergmann", 1057 | "email": "sebastian@phpunit.de" 1058 | } 1059 | ], 1060 | "description": "Looks up which function or method a line of code belongs to", 1061 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 1062 | "time": "2016-02-13T06:45:14+00:00" 1063 | }, 1064 | { 1065 | "name": "sebastian/comparator", 1066 | "version": "1.2.0", 1067 | "source": { 1068 | "type": "git", 1069 | "url": "https://github.com/sebastianbergmann/comparator.git", 1070 | "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" 1071 | }, 1072 | "dist": { 1073 | "type": "zip", 1074 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", 1075 | "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", 1076 | "shasum": "" 1077 | }, 1078 | "require": { 1079 | "php": ">=5.3.3", 1080 | "sebastian/diff": "~1.2", 1081 | "sebastian/exporter": "~1.2" 1082 | }, 1083 | "require-dev": { 1084 | "phpunit/phpunit": "~4.4" 1085 | }, 1086 | "type": "library", 1087 | "extra": { 1088 | "branch-alias": { 1089 | "dev-master": "1.2.x-dev" 1090 | } 1091 | }, 1092 | "autoload": { 1093 | "classmap": [ 1094 | "src/" 1095 | ] 1096 | }, 1097 | "notification-url": "https://packagist.org/downloads/", 1098 | "license": [ 1099 | "BSD-3-Clause" 1100 | ], 1101 | "authors": [ 1102 | { 1103 | "name": "Jeff Welch", 1104 | "email": "whatthejeff@gmail.com" 1105 | }, 1106 | { 1107 | "name": "Volker Dusch", 1108 | "email": "github@wallbash.com" 1109 | }, 1110 | { 1111 | "name": "Bernhard Schussek", 1112 | "email": "bschussek@2bepublished.at" 1113 | }, 1114 | { 1115 | "name": "Sebastian Bergmann", 1116 | "email": "sebastian@phpunit.de" 1117 | } 1118 | ], 1119 | "description": "Provides the functionality to compare PHP values for equality", 1120 | "homepage": "http://www.github.com/sebastianbergmann/comparator", 1121 | "keywords": [ 1122 | "comparator", 1123 | "compare", 1124 | "equality" 1125 | ], 1126 | "time": "2015-07-26T15:48:44+00:00" 1127 | }, 1128 | { 1129 | "name": "sebastian/diff", 1130 | "version": "1.4.1", 1131 | "source": { 1132 | "type": "git", 1133 | "url": "https://github.com/sebastianbergmann/diff.git", 1134 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" 1135 | }, 1136 | "dist": { 1137 | "type": "zip", 1138 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", 1139 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", 1140 | "shasum": "" 1141 | }, 1142 | "require": { 1143 | "php": ">=5.3.3" 1144 | }, 1145 | "require-dev": { 1146 | "phpunit/phpunit": "~4.8" 1147 | }, 1148 | "type": "library", 1149 | "extra": { 1150 | "branch-alias": { 1151 | "dev-master": "1.4-dev" 1152 | } 1153 | }, 1154 | "autoload": { 1155 | "classmap": [ 1156 | "src/" 1157 | ] 1158 | }, 1159 | "notification-url": "https://packagist.org/downloads/", 1160 | "license": [ 1161 | "BSD-3-Clause" 1162 | ], 1163 | "authors": [ 1164 | { 1165 | "name": "Kore Nordmann", 1166 | "email": "mail@kore-nordmann.de" 1167 | }, 1168 | { 1169 | "name": "Sebastian Bergmann", 1170 | "email": "sebastian@phpunit.de" 1171 | } 1172 | ], 1173 | "description": "Diff implementation", 1174 | "homepage": "https://github.com/sebastianbergmann/diff", 1175 | "keywords": [ 1176 | "diff" 1177 | ], 1178 | "time": "2015-12-08T07:14:41+00:00" 1179 | }, 1180 | { 1181 | "name": "sebastian/environment", 1182 | "version": "1.3.8", 1183 | "source": { 1184 | "type": "git", 1185 | "url": "https://github.com/sebastianbergmann/environment.git", 1186 | "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" 1187 | }, 1188 | "dist": { 1189 | "type": "zip", 1190 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", 1191 | "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", 1192 | "shasum": "" 1193 | }, 1194 | "require": { 1195 | "php": "^5.3.3 || ^7.0" 1196 | }, 1197 | "require-dev": { 1198 | "phpunit/phpunit": "^4.8 || ^5.0" 1199 | }, 1200 | "type": "library", 1201 | "extra": { 1202 | "branch-alias": { 1203 | "dev-master": "1.3.x-dev" 1204 | } 1205 | }, 1206 | "autoload": { 1207 | "classmap": [ 1208 | "src/" 1209 | ] 1210 | }, 1211 | "notification-url": "https://packagist.org/downloads/", 1212 | "license": [ 1213 | "BSD-3-Clause" 1214 | ], 1215 | "authors": [ 1216 | { 1217 | "name": "Sebastian Bergmann", 1218 | "email": "sebastian@phpunit.de" 1219 | } 1220 | ], 1221 | "description": "Provides functionality to handle HHVM/PHP environments", 1222 | "homepage": "http://www.github.com/sebastianbergmann/environment", 1223 | "keywords": [ 1224 | "Xdebug", 1225 | "environment", 1226 | "hhvm" 1227 | ], 1228 | "time": "2016-08-18T05:49:44+00:00" 1229 | }, 1230 | { 1231 | "name": "sebastian/exporter", 1232 | "version": "1.2.2", 1233 | "source": { 1234 | "type": "git", 1235 | "url": "https://github.com/sebastianbergmann/exporter.git", 1236 | "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" 1237 | }, 1238 | "dist": { 1239 | "type": "zip", 1240 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", 1241 | "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", 1242 | "shasum": "" 1243 | }, 1244 | "require": { 1245 | "php": ">=5.3.3", 1246 | "sebastian/recursion-context": "~1.0" 1247 | }, 1248 | "require-dev": { 1249 | "ext-mbstring": "*", 1250 | "phpunit/phpunit": "~4.4" 1251 | }, 1252 | "type": "library", 1253 | "extra": { 1254 | "branch-alias": { 1255 | "dev-master": "1.3.x-dev" 1256 | } 1257 | }, 1258 | "autoload": { 1259 | "classmap": [ 1260 | "src/" 1261 | ] 1262 | }, 1263 | "notification-url": "https://packagist.org/downloads/", 1264 | "license": [ 1265 | "BSD-3-Clause" 1266 | ], 1267 | "authors": [ 1268 | { 1269 | "name": "Jeff Welch", 1270 | "email": "whatthejeff@gmail.com" 1271 | }, 1272 | { 1273 | "name": "Volker Dusch", 1274 | "email": "github@wallbash.com" 1275 | }, 1276 | { 1277 | "name": "Bernhard Schussek", 1278 | "email": "bschussek@2bepublished.at" 1279 | }, 1280 | { 1281 | "name": "Sebastian Bergmann", 1282 | "email": "sebastian@phpunit.de" 1283 | }, 1284 | { 1285 | "name": "Adam Harvey", 1286 | "email": "aharvey@php.net" 1287 | } 1288 | ], 1289 | "description": "Provides the functionality to export PHP variables for visualization", 1290 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 1291 | "keywords": [ 1292 | "export", 1293 | "exporter" 1294 | ], 1295 | "time": "2016-06-17T09:04:28+00:00" 1296 | }, 1297 | { 1298 | "name": "sebastian/global-state", 1299 | "version": "1.1.1", 1300 | "source": { 1301 | "type": "git", 1302 | "url": "https://github.com/sebastianbergmann/global-state.git", 1303 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" 1304 | }, 1305 | "dist": { 1306 | "type": "zip", 1307 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", 1308 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", 1309 | "shasum": "" 1310 | }, 1311 | "require": { 1312 | "php": ">=5.3.3" 1313 | }, 1314 | "require-dev": { 1315 | "phpunit/phpunit": "~4.2" 1316 | }, 1317 | "suggest": { 1318 | "ext-uopz": "*" 1319 | }, 1320 | "type": "library", 1321 | "extra": { 1322 | "branch-alias": { 1323 | "dev-master": "1.0-dev" 1324 | } 1325 | }, 1326 | "autoload": { 1327 | "classmap": [ 1328 | "src/" 1329 | ] 1330 | }, 1331 | "notification-url": "https://packagist.org/downloads/", 1332 | "license": [ 1333 | "BSD-3-Clause" 1334 | ], 1335 | "authors": [ 1336 | { 1337 | "name": "Sebastian Bergmann", 1338 | "email": "sebastian@phpunit.de" 1339 | } 1340 | ], 1341 | "description": "Snapshotting of global state", 1342 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1343 | "keywords": [ 1344 | "global state" 1345 | ], 1346 | "time": "2015-10-12T03:26:01+00:00" 1347 | }, 1348 | { 1349 | "name": "sebastian/object-enumerator", 1350 | "version": "1.0.0", 1351 | "source": { 1352 | "type": "git", 1353 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1354 | "reference": "d4ca2fb70344987502567bc50081c03e6192fb26" 1355 | }, 1356 | "dist": { 1357 | "type": "zip", 1358 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26", 1359 | "reference": "d4ca2fb70344987502567bc50081c03e6192fb26", 1360 | "shasum": "" 1361 | }, 1362 | "require": { 1363 | "php": ">=5.6", 1364 | "sebastian/recursion-context": "~1.0" 1365 | }, 1366 | "require-dev": { 1367 | "phpunit/phpunit": "~5" 1368 | }, 1369 | "type": "library", 1370 | "extra": { 1371 | "branch-alias": { 1372 | "dev-master": "1.0.x-dev" 1373 | } 1374 | }, 1375 | "autoload": { 1376 | "classmap": [ 1377 | "src/" 1378 | ] 1379 | }, 1380 | "notification-url": "https://packagist.org/downloads/", 1381 | "license": [ 1382 | "BSD-3-Clause" 1383 | ], 1384 | "authors": [ 1385 | { 1386 | "name": "Sebastian Bergmann", 1387 | "email": "sebastian@phpunit.de" 1388 | } 1389 | ], 1390 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1391 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1392 | "time": "2016-01-28T13:25:10+00:00" 1393 | }, 1394 | { 1395 | "name": "sebastian/recursion-context", 1396 | "version": "1.0.2", 1397 | "source": { 1398 | "type": "git", 1399 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1400 | "reference": "913401df809e99e4f47b27cdd781f4a258d58791" 1401 | }, 1402 | "dist": { 1403 | "type": "zip", 1404 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", 1405 | "reference": "913401df809e99e4f47b27cdd781f4a258d58791", 1406 | "shasum": "" 1407 | }, 1408 | "require": { 1409 | "php": ">=5.3.3" 1410 | }, 1411 | "require-dev": { 1412 | "phpunit/phpunit": "~4.4" 1413 | }, 1414 | "type": "library", 1415 | "extra": { 1416 | "branch-alias": { 1417 | "dev-master": "1.0.x-dev" 1418 | } 1419 | }, 1420 | "autoload": { 1421 | "classmap": [ 1422 | "src/" 1423 | ] 1424 | }, 1425 | "notification-url": "https://packagist.org/downloads/", 1426 | "license": [ 1427 | "BSD-3-Clause" 1428 | ], 1429 | "authors": [ 1430 | { 1431 | "name": "Jeff Welch", 1432 | "email": "whatthejeff@gmail.com" 1433 | }, 1434 | { 1435 | "name": "Sebastian Bergmann", 1436 | "email": "sebastian@phpunit.de" 1437 | }, 1438 | { 1439 | "name": "Adam Harvey", 1440 | "email": "aharvey@php.net" 1441 | } 1442 | ], 1443 | "description": "Provides functionality to recursively process PHP variables", 1444 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 1445 | "time": "2015-11-11T19:50:13+00:00" 1446 | }, 1447 | { 1448 | "name": "sebastian/resource-operations", 1449 | "version": "1.0.0", 1450 | "source": { 1451 | "type": "git", 1452 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 1453 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" 1454 | }, 1455 | "dist": { 1456 | "type": "zip", 1457 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1458 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1459 | "shasum": "" 1460 | }, 1461 | "require": { 1462 | "php": ">=5.6.0" 1463 | }, 1464 | "type": "library", 1465 | "extra": { 1466 | "branch-alias": { 1467 | "dev-master": "1.0.x-dev" 1468 | } 1469 | }, 1470 | "autoload": { 1471 | "classmap": [ 1472 | "src/" 1473 | ] 1474 | }, 1475 | "notification-url": "https://packagist.org/downloads/", 1476 | "license": [ 1477 | "BSD-3-Clause" 1478 | ], 1479 | "authors": [ 1480 | { 1481 | "name": "Sebastian Bergmann", 1482 | "email": "sebastian@phpunit.de" 1483 | } 1484 | ], 1485 | "description": "Provides a list of PHP built-in functions that operate on resources", 1486 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 1487 | "time": "2015-07-28T20:34:47+00:00" 1488 | }, 1489 | { 1490 | "name": "sebastian/version", 1491 | "version": "2.0.0", 1492 | "source": { 1493 | "type": "git", 1494 | "url": "https://github.com/sebastianbergmann/version.git", 1495 | "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5" 1496 | }, 1497 | "dist": { 1498 | "type": "zip", 1499 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5", 1500 | "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5", 1501 | "shasum": "" 1502 | }, 1503 | "require": { 1504 | "php": ">=5.6" 1505 | }, 1506 | "type": "library", 1507 | "extra": { 1508 | "branch-alias": { 1509 | "dev-master": "2.0.x-dev" 1510 | } 1511 | }, 1512 | "autoload": { 1513 | "classmap": [ 1514 | "src/" 1515 | ] 1516 | }, 1517 | "notification-url": "https://packagist.org/downloads/", 1518 | "license": [ 1519 | "BSD-3-Clause" 1520 | ], 1521 | "authors": [ 1522 | { 1523 | "name": "Sebastian Bergmann", 1524 | "email": "sebastian@phpunit.de", 1525 | "role": "lead" 1526 | } 1527 | ], 1528 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1529 | "homepage": "https://github.com/sebastianbergmann/version", 1530 | "time": "2016-02-04T12:56:52+00:00" 1531 | }, 1532 | { 1533 | "name": "squizlabs/php_codesniffer", 1534 | "version": "2.7.0", 1535 | "source": { 1536 | "type": "git", 1537 | "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", 1538 | "reference": "571e27b6348e5b3a637b2abc82ac0d01e6d7bbed" 1539 | }, 1540 | "dist": { 1541 | "type": "zip", 1542 | "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/571e27b6348e5b3a637b2abc82ac0d01e6d7bbed", 1543 | "reference": "571e27b6348e5b3a637b2abc82ac0d01e6d7bbed", 1544 | "shasum": "" 1545 | }, 1546 | "require": { 1547 | "ext-simplexml": "*", 1548 | "ext-tokenizer": "*", 1549 | "ext-xmlwriter": "*", 1550 | "php": ">=5.1.2" 1551 | }, 1552 | "require-dev": { 1553 | "phpunit/phpunit": "~4.0" 1554 | }, 1555 | "bin": [ 1556 | "scripts/phpcs", 1557 | "scripts/phpcbf" 1558 | ], 1559 | "type": "library", 1560 | "extra": { 1561 | "branch-alias": { 1562 | "dev-master": "2.x-dev" 1563 | } 1564 | }, 1565 | "autoload": { 1566 | "classmap": [ 1567 | "CodeSniffer.php", 1568 | "CodeSniffer/CLI.php", 1569 | "CodeSniffer/Exception.php", 1570 | "CodeSniffer/File.php", 1571 | "CodeSniffer/Fixer.php", 1572 | "CodeSniffer/Report.php", 1573 | "CodeSniffer/Reporting.php", 1574 | "CodeSniffer/Sniff.php", 1575 | "CodeSniffer/Tokens.php", 1576 | "CodeSniffer/Reports/", 1577 | "CodeSniffer/Tokenizers/", 1578 | "CodeSniffer/DocGenerators/", 1579 | "CodeSniffer/Standards/AbstractPatternSniff.php", 1580 | "CodeSniffer/Standards/AbstractScopeSniff.php", 1581 | "CodeSniffer/Standards/AbstractVariableSniff.php", 1582 | "CodeSniffer/Standards/IncorrectPatternException.php", 1583 | "CodeSniffer/Standards/Generic/Sniffs/", 1584 | "CodeSniffer/Standards/MySource/Sniffs/", 1585 | "CodeSniffer/Standards/PEAR/Sniffs/", 1586 | "CodeSniffer/Standards/PSR1/Sniffs/", 1587 | "CodeSniffer/Standards/PSR2/Sniffs/", 1588 | "CodeSniffer/Standards/Squiz/Sniffs/", 1589 | "CodeSniffer/Standards/Zend/Sniffs/" 1590 | ] 1591 | }, 1592 | "notification-url": "https://packagist.org/downloads/", 1593 | "license": [ 1594 | "BSD-3-Clause" 1595 | ], 1596 | "authors": [ 1597 | { 1598 | "name": "Greg Sherwood", 1599 | "role": "lead" 1600 | } 1601 | ], 1602 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", 1603 | "homepage": "http://www.squizlabs.com/php-codesniffer", 1604 | "keywords": [ 1605 | "phpcs", 1606 | "standards" 1607 | ], 1608 | "time": "2016-09-01T23:53:02+00:00" 1609 | }, 1610 | { 1611 | "name": "symfony/yaml", 1612 | "version": "v3.1.6", 1613 | "source": { 1614 | "type": "git", 1615 | "url": "https://github.com/symfony/yaml.git", 1616 | "reference": "7ff51b06c6c3d5cc6686df69004a42c69df09e27" 1617 | }, 1618 | "dist": { 1619 | "type": "zip", 1620 | "url": "https://api.github.com/repos/symfony/yaml/zipball/7ff51b06c6c3d5cc6686df69004a42c69df09e27", 1621 | "reference": "7ff51b06c6c3d5cc6686df69004a42c69df09e27", 1622 | "shasum": "" 1623 | }, 1624 | "require": { 1625 | "php": ">=5.5.9" 1626 | }, 1627 | "type": "library", 1628 | "extra": { 1629 | "branch-alias": { 1630 | "dev-master": "3.1-dev" 1631 | } 1632 | }, 1633 | "autoload": { 1634 | "psr-4": { 1635 | "Symfony\\Component\\Yaml\\": "" 1636 | }, 1637 | "exclude-from-classmap": [ 1638 | "/Tests/" 1639 | ] 1640 | }, 1641 | "notification-url": "https://packagist.org/downloads/", 1642 | "license": [ 1643 | "MIT" 1644 | ], 1645 | "authors": [ 1646 | { 1647 | "name": "Fabien Potencier", 1648 | "email": "fabien@symfony.com" 1649 | }, 1650 | { 1651 | "name": "Symfony Community", 1652 | "homepage": "https://symfony.com/contributors" 1653 | } 1654 | ], 1655 | "description": "Symfony Yaml Component", 1656 | "homepage": "https://symfony.com", 1657 | "time": "2016-10-24T18:41:13+00:00" 1658 | }, 1659 | { 1660 | "name": "webmozart/assert", 1661 | "version": "1.1.0", 1662 | "source": { 1663 | "type": "git", 1664 | "url": "https://github.com/webmozart/assert.git", 1665 | "reference": "bb2d123231c095735130cc8f6d31385a44c7b308" 1666 | }, 1667 | "dist": { 1668 | "type": "zip", 1669 | "url": "https://api.github.com/repos/webmozart/assert/zipball/bb2d123231c095735130cc8f6d31385a44c7b308", 1670 | "reference": "bb2d123231c095735130cc8f6d31385a44c7b308", 1671 | "shasum": "" 1672 | }, 1673 | "require": { 1674 | "php": "^5.3.3|^7.0" 1675 | }, 1676 | "require-dev": { 1677 | "phpunit/phpunit": "^4.6", 1678 | "sebastian/version": "^1.0.1" 1679 | }, 1680 | "type": "library", 1681 | "extra": { 1682 | "branch-alias": { 1683 | "dev-master": "1.2-dev" 1684 | } 1685 | }, 1686 | "autoload": { 1687 | "psr-4": { 1688 | "Webmozart\\Assert\\": "src/" 1689 | } 1690 | }, 1691 | "notification-url": "https://packagist.org/downloads/", 1692 | "license": [ 1693 | "MIT" 1694 | ], 1695 | "authors": [ 1696 | { 1697 | "name": "Bernhard Schussek", 1698 | "email": "bschussek@gmail.com" 1699 | } 1700 | ], 1701 | "description": "Assertions to validate method input/output with nice error messages.", 1702 | "keywords": [ 1703 | "assert", 1704 | "check", 1705 | "validate" 1706 | ], 1707 | "time": "2016-08-09T15:02:57+00:00" 1708 | } 1709 | ], 1710 | "aliases": [], 1711 | "minimum-stability": "stable", 1712 | "stability-flags": [], 1713 | "prefer-stable": false, 1714 | "prefer-lowest": false, 1715 | "platform": [], 1716 | "platform-dev": [] 1717 | } 1718 | --------------------------------------------------------------------------------