├── CHANGELOG.md ├── CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── composer.json ├── composer.lock ├── doc └── book │ ├── examples.md │ ├── index.html │ ├── index.md │ ├── intro.md │ ├── methods.md │ └── migration │ └── to-v3-0.md ├── mkdocs.yml ├── phpcs.xml └── src ├── Assertion └── CallbackAssertion.php ├── AssertionInterface.php ├── Exception ├── CircularReferenceException.php ├── ExceptionInterface.php ├── InvalidArgumentException.php └── RuntimeException.php ├── Rbac.php ├── Role.php └── RoleInterface.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file, in reverse chronological order by release. 4 | 5 | ## 3.0.3 - TBD 6 | 7 | ### Added 8 | 9 | - Nothing. 10 | 11 | ### Changed 12 | 13 | - Nothing. 14 | 15 | ### Deprecated 16 | 17 | - Nothing. 18 | 19 | ### Removed 20 | 21 | - Nothing. 22 | 23 | ### Fixed 24 | 25 | - Nothing. 26 | 27 | ## 3.0.2 - 2019-06-25 28 | 29 | ### Added 30 | 31 | - [#43](https://github.com/zendframework/zend-permissions-rbac/pull/43) adds support for PHP 7.3. 32 | 33 | ### Changed 34 | 35 | - Nothing. 36 | 37 | ### Deprecated 38 | 39 | - Nothing. 40 | 41 | ### Removed 42 | 43 | - Nothing. 44 | 45 | ### Fixed 46 | 47 | - Nothing. 48 | 49 | ## 3.0.1 - 2018-08-20 50 | 51 | ### Added 52 | 53 | - Nothing. 54 | 55 | ### Changed 56 | 57 | - [#37](https://github.com/zendframework/zend-permissions-rbac/pull/37) changes 58 | the return type hints of `RoleInterface::getChildren()` and `RoleInterface::getParents()` 59 | from `array` to `iterable`. This is not a BC break thanks to [Iterable Type Variance](http://php.net/manual/en/language.types.iterable.php#language.types.iterable.variance) 60 | 61 | ### Deprecated 62 | 63 | - Nothing. 64 | 65 | ### Removed 66 | 67 | - Nothing. 68 | 69 | ### Fixed 70 | 71 | - [#39](https://github.com/zendframework/zend-permissions-rbac/pull/39) fixes 72 | `Role::getPermissions()` to return all the permissions, if more than one. 73 | 74 | ## 3.0.0 - 2018-03-22 75 | 76 | ### Added 77 | 78 | - [#34](https://github.com/zendframework/zend-permissions-rbac/pull/34) adds 79 | checks for circular references in the role hierarchy when using the 80 | `Role::addChild()` and `Role::addParent()` methods. 81 | 82 | - [#35](https://github.com/zendframework/zend-permissions-rbac/pull/35) adds 83 | the method `Role::getPermissions(bool $children = true)` for retrieving all 84 | permissions to the related role, including all child permissions when 85 | `$children` is boolean `true`. 86 | 87 | - [#35](https://github.com/zendframework/zend-permissions-rbac/pull/35) adds 88 | the method `Rbac::getRoles()`, which returns all roles registered with the 89 | instance as a flat array of instances. 90 | 91 | ### Changed 92 | 93 | - [#34](https://github.com/zendframework/zend-permissions-rbac/pull/34) updates 94 | the `Role::addChild(RoleInterface $child)` method to accept only a `RoleInterface` parameter; 95 | strings are no longer accepted. 96 | 97 | - [#34](https://github.com/zendframework/zend-permissions-rbac/pull/34) updates 98 | the `Zend\Permissions\Rbac\AssertionInterface`, adding two parameters to the 99 | `assert()` definition and defining a return type, so that it now reads as 100 | follows: 101 | 102 | ```php 103 | public function assert( 104 | Rbac $rbac, 105 | RoleInterface $role, 106 | string $permission 107 | ) : bool 108 | ``` 109 | 110 | ### Deprecated 111 | 112 | - Nothing. 113 | 114 | ### Removed 115 | 116 | - [#34](https://github.com/zendframework/zend-permissions-rbac/pull/34) removes 117 | support for PHP versions prior to 7.1. 118 | 119 | - [#34](https://github.com/zendframework/zend-permissions-rbac/pull/34) removes 120 | the [AbstractIterator](https://github.com/zendframework/zend-permissions-rbac/blob/release-2.6.0/src/AbstractIterator.php) 121 | class. The role hierarchy no longer relies on a `RecursiveIterator`. 122 | 123 | - [#34](https://github.com/zendframework/zend-permissions-rbac/pull/34) removes 124 | the [AbstractRole](https://github.com/zendframework/zend-permissions-rbac/blob/release-2.6.0/src/AbstractRole.php) 125 | class. All its functions have been merged to the `Zend\Permissions\Rbac\Role` 126 | class. 127 | 128 | - [#34](https://github.com/zendframework/zend-permissions-rbac/pull/34) removes 129 | the method `Role::setParent()`; use `Role::addParent()` instead. 130 | 131 | ### Fixed 132 | 133 | - [#30](https://github.com/zendframework/zend-permissions-rbac/issues/30) fixes 134 | circular references within the `Role::addChild()` and `Role::addParent()` 135 | algorithms. 136 | 137 | ## 2.6.0 - 2018-02-01 138 | 139 | ### Added 140 | 141 | - [#12](https://github.com/zendframework/zend-permissions-rbac/pull/12) adds 142 | and publishes the documentation to https://zendframework.github.io/zend-permissions-rbac/ 143 | 144 | - [#23](https://github.com/zendframework/zend-permissions-rbac/pull/23) adds 145 | support for multiple parent roles, fixing an issue with reverse traversal of 146 | the inheritance tree. To accomplish this, the method `addParent($parent)` was 147 | added, and the method `getParent()` now can also return an array of roles. 148 | 149 | - [#31](https://github.com/zendframework/zend-permissions-rbac/pull/31) adds 150 | support for PHP 7.2. 151 | 152 | ### Changed 153 | 154 | - Nothing. 155 | 156 | ### Deprecated 157 | 158 | - [#23](https://github.com/zendframework/zend-permissions-rbac/pull/23) 159 | deprecates the method `setParent()`. Use `addParent()` instead. 160 | 161 | ### Removed 162 | 163 | - [#29](https://github.com/zendframework/zend-permissions-rbac/pull/29) removes 164 | support for PHP 5.5. 165 | 166 | - [#29](https://github.com/zendframework/zend-permissions-rbac/pull/29) removes 167 | support for HHVM. 168 | 169 | ### Fixed 170 | 171 | - [#21](https://github.com/zendframework/zend-permissions-rbac/pull/21) fixes 172 | dynamic assertion checking, adding the AND with permission. 173 | -------------------------------------------------------------------------------- /CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | The Zend Framework project adheres to [The Code Manifesto](http://codemanifesto.com) 4 | as its guidelines for contributor interactions. 5 | 6 | ## The Code Manifesto 7 | 8 | We want to work in an ecosystem that empowers developers to reach their 9 | potential — one that encourages growth and effective collaboration. A space that 10 | is safe for all. 11 | 12 | A space such as this benefits everyone that participates in it. It encourages 13 | new developers to enter our field. It is through discussion and collaboration 14 | that we grow, and through growth that we improve. 15 | 16 | In the effort to create such a place, we hold to these values: 17 | 18 | 1. **Discrimination limits us.** This includes discrimination on the basis of 19 | race, gender, sexual orientation, gender identity, age, nationality, technology 20 | and any other arbitrary exclusion of a group of people. 21 | 2. **Boundaries honor us.** Your comfort levels are not everyone’s comfort 22 | levels. Remember that, and if brought to your attention, heed it. 23 | 3. **We are our biggest assets.** None of us were born masters of our trade. 24 | Each of us has been helped along the way. Return that favor, when and where 25 | you can. 26 | 4. **We are resources for the future.** As an extension of #3, share what you 27 | know. Make yourself a resource to help those that come after you. 28 | 5. **Respect defines us.** Treat others as you wish to be treated. Make your 29 | discussions, criticisms and debates from a position of respectfulness. Ask 30 | yourself, is it true? Is it necessary? Is it constructive? Anything less is 31 | unacceptable. 32 | 6. **Reactions require grace.** Angry responses are valid, but abusive language 33 | and vindictive actions are toxic. When something happens that offends you, 34 | handle it assertively, but be respectful. Escalate reasonably, and try to 35 | allow the offender an opportunity to explain themselves, and possibly correct 36 | the issue. 37 | 7. **Opinions are just that: opinions.** Each and every one of us, due to our 38 | background and upbringing, have varying opinions. The fact of the matter, is 39 | that is perfectly acceptable. Remember this: if you respect your own 40 | opinions, you should respect the opinions of others. 41 | 8. **To err is human.** You might not intend it, but mistakes do happen and 42 | contribute to build experience. Tolerate honest mistakes, and don't hesitate 43 | to apologize if you make one yourself. 44 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING 2 | 3 | ## RESOURCES 4 | 5 | If you wish to contribute to Zend Framework, please be sure to 6 | read/subscribe to the following resources: 7 | 8 | - [Coding Standards](https://github.com/zendframework/zf2/wiki/Coding-Standards) 9 | - [Contributor's Guide](http://framework.zend.com/participate/contributor-guide) 10 | - ZF Contributor's mailing list: 11 | Archives: http://zend-framework-community.634137.n4.nabble.com/ZF-Contributor-f680267.html 12 | Subscribe: zf-contributors-subscribe@lists.zend.com 13 | - ZF Contributor's IRC channel: 14 | #zftalk.dev on Freenode.net 15 | 16 | If you are working on new features or refactoring [create a proposal](https://github.com/zendframework/zend-permissions-rbac/issues/new). 17 | 18 | ## Reporting Potential Security Issues 19 | 20 | If you have encountered a potential security vulnerability, please **DO NOT** report it on the public 21 | issue tracker: send it to us at [zf-security@zend.com](mailto:zf-security@zend.com) instead. 22 | We will work with you to verify the vulnerability and patch it as soon as possible. 23 | 24 | When reporting issues, please provide the following information: 25 | 26 | - Component(s) affected 27 | - A description indicating how to reproduce the issue 28 | - A summary of the security vulnerability and impact 29 | 30 | We request that you contact us via the email address above and give the project 31 | contributors a chance to resolve the vulnerability and issue a new release prior 32 | to any public exposure; this helps protect users and provides them with a chance 33 | to upgrade and/or update in order to protect their applications. 34 | 35 | For sensitive email communications, please use [our PGP key](http://framework.zend.com/zf-security-pgp-key.asc). 36 | 37 | ## RUNNING TESTS 38 | 39 | > ### Note: testing versions prior to 2.4 40 | > 41 | > This component originates with Zend Framework 2. During the lifetime of ZF2, 42 | > testing infrastructure migrated from PHPUnit 3 to PHPUnit 4. In most cases, no 43 | > changes were necessary. However, due to the migration, tests may not run on 44 | > versions < 2.4. As such, you may need to change the PHPUnit dependency if 45 | > attempting a fix on such a version. 46 | 47 | To run tests: 48 | 49 | - Clone the repository: 50 | 51 | ```console 52 | $ git clone git@github.com:zendframework/zend-permissions-rbac.git 53 | $ cd 54 | ``` 55 | 56 | - Install dependencies via composer: 57 | 58 | ```console 59 | $ curl -sS https://getcomposer.org/installer | php -- 60 | $ ./composer.phar install 61 | ``` 62 | 63 | If you don't have `curl` installed, you can also download `composer.phar` from https://getcomposer.org/ 64 | 65 | - Run the tests via `phpunit` and the provided PHPUnit config, like in this example: 66 | 67 | ```console 68 | $ ./vendor/bin/phpunit 69 | ``` 70 | 71 | You can turn on conditional tests with the phpunit.xml file. 72 | To do so: 73 | 74 | - Copy `phpunit.xml.dist` file to `phpunit.xml` 75 | - Edit `phpunit.xml` to enable any specific functionality you 76 | want to test, as well as to provide test values to utilize. 77 | 78 | ## Running Coding Standards Checks 79 | 80 | This component uses [phpcs](https://github.com/squizlabs/PHP_CodeSniffer) for coding 81 | standards checks, and provides configuration for our selected checks. 82 | `phpcs` is installed by default via Composer. 83 | 84 | To run checks only: 85 | 86 | ```console 87 | $ composer cs-check 88 | ``` 89 | 90 | `phpcs` also includes a tool for fixing most CS violations, `phpcbf`: 91 | 92 | 93 | ```console 94 | $ composer cs-fix 95 | ``` 96 | 97 | If you allow `phpcbf` to fix CS issues, please re-run the tests to ensure 98 | they pass, and make sure you add and commit the changes after verification. 99 | 100 | ## Recommended Workflow for Contributions 101 | 102 | Your first step is to establish a public repository from which we can 103 | pull your work into the master repository. We recommend using 104 | [GitHub](https://github.com), as that is where the component is already hosted. 105 | 106 | 1. Setup a [GitHub account](http://github.com/), if you haven't yet 107 | 2. Fork the repository (http://github.com/zendframework/zend-permissions-rbac) 108 | 3. Clone the canonical repository locally and enter it. 109 | 110 | ```console 111 | $ git clone git://github.com:zendframework/zend-permissions-rbac.git 112 | $ cd zend-permissions-rbac 113 | ``` 114 | 115 | 4. Add a remote to your fork; substitute your GitHub username in the command 116 | below. 117 | 118 | ```console 119 | $ git remote add {username} git@github.com:{username}/zend-permissions-rbac.git 120 | $ git fetch {username} 121 | ``` 122 | 123 | ### Keeping Up-to-Date 124 | 125 | Periodically, you should update your fork or personal repository to 126 | match the canonical ZF repository. Assuming you have setup your local repository 127 | per the instructions above, you can do the following: 128 | 129 | 130 | ```console 131 | $ git checkout master 132 | $ git fetch origin 133 | $ git rebase origin/master 134 | # OPTIONALLY, to keep your remote up-to-date - 135 | $ git push {username} master:master 136 | ``` 137 | 138 | If you're tracking other branches -- for example, the "develop" branch, where 139 | new feature development occurs -- you'll want to do the same operations for that 140 | branch; simply substitute "develop" for "master". 141 | 142 | ### Working on a patch 143 | 144 | We recommend you do each new feature or bugfix in a new branch. This simplifies 145 | the task of code review as well as the task of merging your changes into the 146 | canonical repository. 147 | 148 | A typical workflow will then consist of the following: 149 | 150 | 1. Create a new local branch based off either your master or develop branch. 151 | 2. Switch to your new local branch. (This step can be combined with the 152 | previous step with the use of `git checkout -b`.) 153 | 3. Do some work, commit, repeat as necessary. 154 | 4. Push the local branch to your remote repository. 155 | 5. Send a pull request. 156 | 157 | The mechanics of this process are actually quite trivial. Below, we will 158 | create a branch for fixing an issue in the tracker. 159 | 160 | ```console 161 | $ git checkout -b hotfix/9295 162 | Switched to a new branch 'hotfix/9295' 163 | ``` 164 | 165 | ... do some work ... 166 | 167 | 168 | ```console 169 | $ git commit 170 | ``` 171 | 172 | ... write your log message ... 173 | 174 | 175 | ```console 176 | $ git push {username} hotfix/9295:hotfix/9295 177 | Counting objects: 38, done. 178 | Delta compression using up to 2 threads. 179 | Compression objects: 100% (18/18), done. 180 | Writing objects: 100% (20/20), 8.19KiB, done. 181 | Total 20 (delta 12), reused 0 (delta 0) 182 | To ssh://git@github.com/{username}/zend-permissions-rbac.git 183 | b5583aa..4f51698 HEAD -> master 184 | ``` 185 | 186 | To send a pull request, you have two options. 187 | 188 | If using GitHub, you can do the pull request from there. Navigate to 189 | your repository, select the branch you just created, and then select the 190 | "Pull Request" button in the upper right. Select the user/organization 191 | "zendframework" as the recipient. 192 | 193 | If using your own repository - or even if using GitHub - you can use `git 194 | format-patch` to create a patchset for us to apply; in fact, this is 195 | **recommended** for security-related patches. If you use `format-patch`, please 196 | send the patches as attachments to: 197 | 198 | - zf-devteam@zend.com for patches without security implications 199 | - zf-security@zend.com for security patches 200 | 201 | #### What branch to issue the pull request against? 202 | 203 | Which branch should you issue a pull request against? 204 | 205 | - For fixes against the stable release, issue the pull request against the 206 | "master" branch. 207 | - For new features, or fixes that introduce new elements to the public API (such 208 | as new public methods or properties), issue the pull request against the 209 | "develop" branch. 210 | 211 | ### Branch Cleanup 212 | 213 | As you might imagine, if you are a frequent contributor, you'll start to 214 | get a ton of branches both locally and on your remote. 215 | 216 | Once you know that your changes have been accepted to the master 217 | repository, we suggest doing some cleanup of these branches. 218 | 219 | - Local branch cleanup 220 | 221 | ```console 222 | $ git branch -d 223 | ``` 224 | 225 | - Remote branch removal 226 | 227 | ```console 228 | $ git push {username} : 229 | ``` 230 | 231 | 232 | ## Conduct 233 | 234 | Please see our [CONDUCT.md](CONDUCT.md) to understand expected behavior when interacting with others in the project. 235 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2005-2018, Zend Technologies USA, Inc. 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | - Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | 11 | - Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | - Neither the name of Zend Technologies USA, Inc. nor the names of its 16 | contributors may be used to endorse or promote products derived from this 17 | software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zend-permissions-rbac 2 | 3 | > ## Repository abandoned 2019-12-31 4 | > 5 | > This repository has moved to [laminas/laminas-permissions-rbac](https://github.com/laminas/laminas-permissions-rbac). 6 | 7 | [![Build Status](https://secure.travis-ci.org/zendframework/zend-permissions-rbac.svg?branch=master)](https://secure.travis-ci.org/zendframework/zend-permissions-rbac) 8 | [![Coverage Status](https://coveralls.io/repos/zendframework/zend-permissions-rbac/badge.svg?branch=master)](https://coveralls.io/r/zendframework/zend-permissions-rbac?branch=master) 9 | 10 | Provides [Role-Based Access Control](https://it.wikipedia.org/wiki/Role-based_access_control) 11 | (RBAC) permissions management. 12 | 13 | - File issues at https://github.com/zendframework/zend-permissions-rbac/issues 14 | - Documentation is at https://docs.zendframework.com/zend-permissions-rbac/ 15 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zendframework/zend-permissions-rbac", 3 | "description": "Provides a role-based access control management", 4 | "license": "BSD-3-Clause", 5 | "keywords": [ 6 | "zendframework", 7 | "zend-permssions-rbac", 8 | "rbac", 9 | "authorization" 10 | ], 11 | "homepage": "https://github.com/zendframework/zend-permissions-rbac", 12 | "autoload": { 13 | "psr-4": { 14 | "Zend\\Permissions\\Rbac\\": "src/" 15 | } 16 | }, 17 | "require": { 18 | "php": "^7.1" 19 | }, 20 | "minimum-stability": "dev", 21 | "prefer-stable": true, 22 | "extra": { 23 | "branch-alias": { 24 | "dev-master": "3.0.x-dev", 25 | "dev-develop": "3.1.x-dev" 26 | } 27 | }, 28 | "autoload-dev": { 29 | "psr-4": { 30 | "ZendTest\\Permissions\\Rbac\\": "test/" 31 | } 32 | }, 33 | "require-dev": { 34 | "phpunit/phpunit": "^7.0.1", 35 | "zendframework/zend-coding-standard": "~1.0.0" 36 | }, 37 | "scripts": { 38 | "check": [ 39 | "@cs-check", 40 | "@test" 41 | ], 42 | "cs-check": "phpcs", 43 | "cs-fix": "phpcbf", 44 | "test": "phpunit --colors=always", 45 | "test-coverage": "phpunit --colors=always --coverage-clover clover.xml" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /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": "60dda7c6ebcec6ecc57fe765479fd341", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "doctrine/instantiator", 12 | "version": "1.1.0", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/doctrine/instantiator.git", 16 | "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", 21 | "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "php": "^7.1" 26 | }, 27 | "require-dev": { 28 | "athletic/athletic": "~0.1.8", 29 | "ext-pdo": "*", 30 | "ext-phar": "*", 31 | "phpunit/phpunit": "^6.2.3", 32 | "squizlabs/php_codesniffer": "^3.0.2" 33 | }, 34 | "type": "library", 35 | "extra": { 36 | "branch-alias": { 37 | "dev-master": "1.2.x-dev" 38 | } 39 | }, 40 | "autoload": { 41 | "psr-4": { 42 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 43 | } 44 | }, 45 | "notification-url": "https://packagist.org/downloads/", 46 | "license": [ 47 | "MIT" 48 | ], 49 | "authors": [ 50 | { 51 | "name": "Marco Pivetta", 52 | "email": "ocramius@gmail.com", 53 | "homepage": "http://ocramius.github.com/" 54 | } 55 | ], 56 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 57 | "homepage": "https://github.com/doctrine/instantiator", 58 | "keywords": [ 59 | "constructor", 60 | "instantiate" 61 | ], 62 | "time": "2017-07-22T11:58:36+00:00" 63 | }, 64 | { 65 | "name": "myclabs/deep-copy", 66 | "version": "1.7.0", 67 | "source": { 68 | "type": "git", 69 | "url": "https://github.com/myclabs/DeepCopy.git", 70 | "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" 71 | }, 72 | "dist": { 73 | "type": "zip", 74 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", 75 | "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", 76 | "shasum": "" 77 | }, 78 | "require": { 79 | "php": "^5.6 || ^7.0" 80 | }, 81 | "require-dev": { 82 | "doctrine/collections": "^1.0", 83 | "doctrine/common": "^2.6", 84 | "phpunit/phpunit": "^4.1" 85 | }, 86 | "type": "library", 87 | "autoload": { 88 | "psr-4": { 89 | "DeepCopy\\": "src/DeepCopy/" 90 | }, 91 | "files": [ 92 | "src/DeepCopy/deep_copy.php" 93 | ] 94 | }, 95 | "notification-url": "https://packagist.org/downloads/", 96 | "license": [ 97 | "MIT" 98 | ], 99 | "description": "Create deep copies (clones) of your objects", 100 | "keywords": [ 101 | "clone", 102 | "copy", 103 | "duplicate", 104 | "object", 105 | "object graph" 106 | ], 107 | "time": "2017-10-19T19:58:43+00:00" 108 | }, 109 | { 110 | "name": "phar-io/manifest", 111 | "version": "1.0.1", 112 | "source": { 113 | "type": "git", 114 | "url": "https://github.com/phar-io/manifest.git", 115 | "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" 116 | }, 117 | "dist": { 118 | "type": "zip", 119 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", 120 | "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", 121 | "shasum": "" 122 | }, 123 | "require": { 124 | "ext-dom": "*", 125 | "ext-phar": "*", 126 | "phar-io/version": "^1.0.1", 127 | "php": "^5.6 || ^7.0" 128 | }, 129 | "type": "library", 130 | "extra": { 131 | "branch-alias": { 132 | "dev-master": "1.0.x-dev" 133 | } 134 | }, 135 | "autoload": { 136 | "classmap": [ 137 | "src/" 138 | ] 139 | }, 140 | "notification-url": "https://packagist.org/downloads/", 141 | "license": [ 142 | "BSD-3-Clause" 143 | ], 144 | "authors": [ 145 | { 146 | "name": "Arne Blankerts", 147 | "email": "arne@blankerts.de", 148 | "role": "Developer" 149 | }, 150 | { 151 | "name": "Sebastian Heuer", 152 | "email": "sebastian@phpeople.de", 153 | "role": "Developer" 154 | }, 155 | { 156 | "name": "Sebastian Bergmann", 157 | "email": "sebastian@phpunit.de", 158 | "role": "Developer" 159 | } 160 | ], 161 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", 162 | "time": "2017-03-05T18:14:27+00:00" 163 | }, 164 | { 165 | "name": "phar-io/version", 166 | "version": "1.0.1", 167 | "source": { 168 | "type": "git", 169 | "url": "https://github.com/phar-io/version.git", 170 | "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" 171 | }, 172 | "dist": { 173 | "type": "zip", 174 | "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", 175 | "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", 176 | "shasum": "" 177 | }, 178 | "require": { 179 | "php": "^5.6 || ^7.0" 180 | }, 181 | "type": "library", 182 | "autoload": { 183 | "classmap": [ 184 | "src/" 185 | ] 186 | }, 187 | "notification-url": "https://packagist.org/downloads/", 188 | "license": [ 189 | "BSD-3-Clause" 190 | ], 191 | "authors": [ 192 | { 193 | "name": "Arne Blankerts", 194 | "email": "arne@blankerts.de", 195 | "role": "Developer" 196 | }, 197 | { 198 | "name": "Sebastian Heuer", 199 | "email": "sebastian@phpeople.de", 200 | "role": "Developer" 201 | }, 202 | { 203 | "name": "Sebastian Bergmann", 204 | "email": "sebastian@phpunit.de", 205 | "role": "Developer" 206 | } 207 | ], 208 | "description": "Library for handling version information and constraints", 209 | "time": "2017-03-05T17:38:23+00:00" 210 | }, 211 | { 212 | "name": "phpdocumentor/reflection-common", 213 | "version": "1.0.1", 214 | "source": { 215 | "type": "git", 216 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 217 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" 218 | }, 219 | "dist": { 220 | "type": "zip", 221 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 222 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 223 | "shasum": "" 224 | }, 225 | "require": { 226 | "php": ">=5.5" 227 | }, 228 | "require-dev": { 229 | "phpunit/phpunit": "^4.6" 230 | }, 231 | "type": "library", 232 | "extra": { 233 | "branch-alias": { 234 | "dev-master": "1.0.x-dev" 235 | } 236 | }, 237 | "autoload": { 238 | "psr-4": { 239 | "phpDocumentor\\Reflection\\": [ 240 | "src" 241 | ] 242 | } 243 | }, 244 | "notification-url": "https://packagist.org/downloads/", 245 | "license": [ 246 | "MIT" 247 | ], 248 | "authors": [ 249 | { 250 | "name": "Jaap van Otterdijk", 251 | "email": "opensource@ijaap.nl" 252 | } 253 | ], 254 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 255 | "homepage": "http://www.phpdoc.org", 256 | "keywords": [ 257 | "FQSEN", 258 | "phpDocumentor", 259 | "phpdoc", 260 | "reflection", 261 | "static analysis" 262 | ], 263 | "time": "2017-09-11T18:02:19+00:00" 264 | }, 265 | { 266 | "name": "phpdocumentor/reflection-docblock", 267 | "version": "4.3.0", 268 | "source": { 269 | "type": "git", 270 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 271 | "reference": "94fd0001232e47129dd3504189fa1c7225010d08" 272 | }, 273 | "dist": { 274 | "type": "zip", 275 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", 276 | "reference": "94fd0001232e47129dd3504189fa1c7225010d08", 277 | "shasum": "" 278 | }, 279 | "require": { 280 | "php": "^7.0", 281 | "phpdocumentor/reflection-common": "^1.0.0", 282 | "phpdocumentor/type-resolver": "^0.4.0", 283 | "webmozart/assert": "^1.0" 284 | }, 285 | "require-dev": { 286 | "doctrine/instantiator": "~1.0.5", 287 | "mockery/mockery": "^1.0", 288 | "phpunit/phpunit": "^6.4" 289 | }, 290 | "type": "library", 291 | "extra": { 292 | "branch-alias": { 293 | "dev-master": "4.x-dev" 294 | } 295 | }, 296 | "autoload": { 297 | "psr-4": { 298 | "phpDocumentor\\Reflection\\": [ 299 | "src/" 300 | ] 301 | } 302 | }, 303 | "notification-url": "https://packagist.org/downloads/", 304 | "license": [ 305 | "MIT" 306 | ], 307 | "authors": [ 308 | { 309 | "name": "Mike van Riel", 310 | "email": "me@mikevanriel.com" 311 | } 312 | ], 313 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 314 | "time": "2017-11-30T07:14:17+00:00" 315 | }, 316 | { 317 | "name": "phpdocumentor/type-resolver", 318 | "version": "0.4.0", 319 | "source": { 320 | "type": "git", 321 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 322 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" 323 | }, 324 | "dist": { 325 | "type": "zip", 326 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", 327 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", 328 | "shasum": "" 329 | }, 330 | "require": { 331 | "php": "^5.5 || ^7.0", 332 | "phpdocumentor/reflection-common": "^1.0" 333 | }, 334 | "require-dev": { 335 | "mockery/mockery": "^0.9.4", 336 | "phpunit/phpunit": "^5.2||^4.8.24" 337 | }, 338 | "type": "library", 339 | "extra": { 340 | "branch-alias": { 341 | "dev-master": "1.0.x-dev" 342 | } 343 | }, 344 | "autoload": { 345 | "psr-4": { 346 | "phpDocumentor\\Reflection\\": [ 347 | "src/" 348 | ] 349 | } 350 | }, 351 | "notification-url": "https://packagist.org/downloads/", 352 | "license": [ 353 | "MIT" 354 | ], 355 | "authors": [ 356 | { 357 | "name": "Mike van Riel", 358 | "email": "me@mikevanriel.com" 359 | } 360 | ], 361 | "time": "2017-07-14T14:27:02+00:00" 362 | }, 363 | { 364 | "name": "phpspec/prophecy", 365 | "version": "1.7.5", 366 | "source": { 367 | "type": "git", 368 | "url": "https://github.com/phpspec/prophecy.git", 369 | "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401" 370 | }, 371 | "dist": { 372 | "type": "zip", 373 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401", 374 | "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401", 375 | "shasum": "" 376 | }, 377 | "require": { 378 | "doctrine/instantiator": "^1.0.2", 379 | "php": "^5.3|^7.0", 380 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", 381 | "sebastian/comparator": "^1.1|^2.0", 382 | "sebastian/recursion-context": "^1.0|^2.0|^3.0" 383 | }, 384 | "require-dev": { 385 | "phpspec/phpspec": "^2.5|^3.2", 386 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" 387 | }, 388 | "type": "library", 389 | "extra": { 390 | "branch-alias": { 391 | "dev-master": "1.7.x-dev" 392 | } 393 | }, 394 | "autoload": { 395 | "psr-0": { 396 | "Prophecy\\": "src/" 397 | } 398 | }, 399 | "notification-url": "https://packagist.org/downloads/", 400 | "license": [ 401 | "MIT" 402 | ], 403 | "authors": [ 404 | { 405 | "name": "Konstantin Kudryashov", 406 | "email": "ever.zet@gmail.com", 407 | "homepage": "http://everzet.com" 408 | }, 409 | { 410 | "name": "Marcello Duarte", 411 | "email": "marcello.duarte@gmail.com" 412 | } 413 | ], 414 | "description": "Highly opinionated mocking framework for PHP 5.3+", 415 | "homepage": "https://github.com/phpspec/prophecy", 416 | "keywords": [ 417 | "Double", 418 | "Dummy", 419 | "fake", 420 | "mock", 421 | "spy", 422 | "stub" 423 | ], 424 | "time": "2018-02-19T10:16:54+00:00" 425 | }, 426 | { 427 | "name": "phpunit/php-code-coverage", 428 | "version": "6.0.1", 429 | "source": { 430 | "type": "git", 431 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 432 | "reference": "f8ca4b604baf23dab89d87773c28cc07405189ba" 433 | }, 434 | "dist": { 435 | "type": "zip", 436 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f8ca4b604baf23dab89d87773c28cc07405189ba", 437 | "reference": "f8ca4b604baf23dab89d87773c28cc07405189ba", 438 | "shasum": "" 439 | }, 440 | "require": { 441 | "ext-dom": "*", 442 | "ext-xmlwriter": "*", 443 | "php": "^7.1", 444 | "phpunit/php-file-iterator": "^1.4.2", 445 | "phpunit/php-text-template": "^1.2.1", 446 | "phpunit/php-token-stream": "^3.0", 447 | "sebastian/code-unit-reverse-lookup": "^1.0.1", 448 | "sebastian/environment": "^3.0", 449 | "sebastian/version": "^2.0.1", 450 | "theseer/tokenizer": "^1.1" 451 | }, 452 | "require-dev": { 453 | "phpunit/phpunit": "^7.0" 454 | }, 455 | "suggest": { 456 | "ext-xdebug": "^2.6.0" 457 | }, 458 | "type": "library", 459 | "extra": { 460 | "branch-alias": { 461 | "dev-master": "6.0-dev" 462 | } 463 | }, 464 | "autoload": { 465 | "classmap": [ 466 | "src/" 467 | ] 468 | }, 469 | "notification-url": "https://packagist.org/downloads/", 470 | "license": [ 471 | "BSD-3-Clause" 472 | ], 473 | "authors": [ 474 | { 475 | "name": "Sebastian Bergmann", 476 | "email": "sebastian@phpunit.de", 477 | "role": "lead" 478 | } 479 | ], 480 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 481 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 482 | "keywords": [ 483 | "coverage", 484 | "testing", 485 | "xunit" 486 | ], 487 | "time": "2018-02-02T07:01:41+00:00" 488 | }, 489 | { 490 | "name": "phpunit/php-file-iterator", 491 | "version": "1.4.5", 492 | "source": { 493 | "type": "git", 494 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 495 | "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" 496 | }, 497 | "dist": { 498 | "type": "zip", 499 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", 500 | "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", 501 | "shasum": "" 502 | }, 503 | "require": { 504 | "php": ">=5.3.3" 505 | }, 506 | "type": "library", 507 | "extra": { 508 | "branch-alias": { 509 | "dev-master": "1.4.x-dev" 510 | } 511 | }, 512 | "autoload": { 513 | "classmap": [ 514 | "src/" 515 | ] 516 | }, 517 | "notification-url": "https://packagist.org/downloads/", 518 | "license": [ 519 | "BSD-3-Clause" 520 | ], 521 | "authors": [ 522 | { 523 | "name": "Sebastian Bergmann", 524 | "email": "sb@sebastian-bergmann.de", 525 | "role": "lead" 526 | } 527 | ], 528 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 529 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 530 | "keywords": [ 531 | "filesystem", 532 | "iterator" 533 | ], 534 | "time": "2017-11-27T13:52:08+00:00" 535 | }, 536 | { 537 | "name": "phpunit/php-text-template", 538 | "version": "1.2.1", 539 | "source": { 540 | "type": "git", 541 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 542 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 543 | }, 544 | "dist": { 545 | "type": "zip", 546 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 547 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 548 | "shasum": "" 549 | }, 550 | "require": { 551 | "php": ">=5.3.3" 552 | }, 553 | "type": "library", 554 | "autoload": { 555 | "classmap": [ 556 | "src/" 557 | ] 558 | }, 559 | "notification-url": "https://packagist.org/downloads/", 560 | "license": [ 561 | "BSD-3-Clause" 562 | ], 563 | "authors": [ 564 | { 565 | "name": "Sebastian Bergmann", 566 | "email": "sebastian@phpunit.de", 567 | "role": "lead" 568 | } 569 | ], 570 | "description": "Simple template engine.", 571 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 572 | "keywords": [ 573 | "template" 574 | ], 575 | "time": "2015-06-21T13:50:34+00:00" 576 | }, 577 | { 578 | "name": "phpunit/php-timer", 579 | "version": "2.0.0", 580 | "source": { 581 | "type": "git", 582 | "url": "https://github.com/sebastianbergmann/php-timer.git", 583 | "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f" 584 | }, 585 | "dist": { 586 | "type": "zip", 587 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f", 588 | "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f", 589 | "shasum": "" 590 | }, 591 | "require": { 592 | "php": "^7.1" 593 | }, 594 | "require-dev": { 595 | "phpunit/phpunit": "^7.0" 596 | }, 597 | "type": "library", 598 | "extra": { 599 | "branch-alias": { 600 | "dev-master": "2.0-dev" 601 | } 602 | }, 603 | "autoload": { 604 | "classmap": [ 605 | "src/" 606 | ] 607 | }, 608 | "notification-url": "https://packagist.org/downloads/", 609 | "license": [ 610 | "BSD-3-Clause" 611 | ], 612 | "authors": [ 613 | { 614 | "name": "Sebastian Bergmann", 615 | "email": "sebastian@phpunit.de", 616 | "role": "lead" 617 | } 618 | ], 619 | "description": "Utility class for timing", 620 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 621 | "keywords": [ 622 | "timer" 623 | ], 624 | "time": "2018-02-01T13:07:23+00:00" 625 | }, 626 | { 627 | "name": "phpunit/php-token-stream", 628 | "version": "3.0.0", 629 | "source": { 630 | "type": "git", 631 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 632 | "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace" 633 | }, 634 | "dist": { 635 | "type": "zip", 636 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace", 637 | "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace", 638 | "shasum": "" 639 | }, 640 | "require": { 641 | "ext-tokenizer": "*", 642 | "php": "^7.1" 643 | }, 644 | "require-dev": { 645 | "phpunit/phpunit": "^7.0" 646 | }, 647 | "type": "library", 648 | "extra": { 649 | "branch-alias": { 650 | "dev-master": "3.0-dev" 651 | } 652 | }, 653 | "autoload": { 654 | "classmap": [ 655 | "src/" 656 | ] 657 | }, 658 | "notification-url": "https://packagist.org/downloads/", 659 | "license": [ 660 | "BSD-3-Clause" 661 | ], 662 | "authors": [ 663 | { 664 | "name": "Sebastian Bergmann", 665 | "email": "sebastian@phpunit.de" 666 | } 667 | ], 668 | "description": "Wrapper around PHP's tokenizer extension.", 669 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 670 | "keywords": [ 671 | "tokenizer" 672 | ], 673 | "time": "2018-02-01T13:16:43+00:00" 674 | }, 675 | { 676 | "name": "phpunit/phpunit", 677 | "version": "7.0.2", 678 | "source": { 679 | "type": "git", 680 | "url": "https://github.com/sebastianbergmann/phpunit.git", 681 | "reference": "e2f8aa21bc54b6ba218bdd4f9e0dac1e9bc3b4e9" 682 | }, 683 | "dist": { 684 | "type": "zip", 685 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e2f8aa21bc54b6ba218bdd4f9e0dac1e9bc3b4e9", 686 | "reference": "e2f8aa21bc54b6ba218bdd4f9e0dac1e9bc3b4e9", 687 | "shasum": "" 688 | }, 689 | "require": { 690 | "ext-dom": "*", 691 | "ext-json": "*", 692 | "ext-libxml": "*", 693 | "ext-mbstring": "*", 694 | "ext-xml": "*", 695 | "myclabs/deep-copy": "^1.6.1", 696 | "phar-io/manifest": "^1.0.1", 697 | "phar-io/version": "^1.0", 698 | "php": "^7.1", 699 | "phpspec/prophecy": "^1.7", 700 | "phpunit/php-code-coverage": "^6.0", 701 | "phpunit/php-file-iterator": "^1.4.3", 702 | "phpunit/php-text-template": "^1.2.1", 703 | "phpunit/php-timer": "^2.0", 704 | "phpunit/phpunit-mock-objects": "^6.0", 705 | "sebastian/comparator": "^2.1", 706 | "sebastian/diff": "^3.0", 707 | "sebastian/environment": "^3.1", 708 | "sebastian/exporter": "^3.1", 709 | "sebastian/global-state": "^2.0", 710 | "sebastian/object-enumerator": "^3.0.3", 711 | "sebastian/resource-operations": "^1.0", 712 | "sebastian/version": "^2.0.1" 713 | }, 714 | "require-dev": { 715 | "ext-pdo": "*" 716 | }, 717 | "suggest": { 718 | "ext-xdebug": "*", 719 | "phpunit/php-invoker": "^2.0" 720 | }, 721 | "bin": [ 722 | "phpunit" 723 | ], 724 | "type": "library", 725 | "extra": { 726 | "branch-alias": { 727 | "dev-master": "7.0-dev" 728 | } 729 | }, 730 | "autoload": { 731 | "classmap": [ 732 | "src/" 733 | ] 734 | }, 735 | "notification-url": "https://packagist.org/downloads/", 736 | "license": [ 737 | "BSD-3-Clause" 738 | ], 739 | "authors": [ 740 | { 741 | "name": "Sebastian Bergmann", 742 | "email": "sebastian@phpunit.de", 743 | "role": "lead" 744 | } 745 | ], 746 | "description": "The PHP Unit Testing framework.", 747 | "homepage": "https://phpunit.de/", 748 | "keywords": [ 749 | "phpunit", 750 | "testing", 751 | "xunit" 752 | ], 753 | "time": "2018-02-26T07:03:12+00:00" 754 | }, 755 | { 756 | "name": "phpunit/phpunit-mock-objects", 757 | "version": "6.0.1", 758 | "source": { 759 | "type": "git", 760 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 761 | "reference": "e3249dedc2d99259ccae6affbc2684eac37c2e53" 762 | }, 763 | "dist": { 764 | "type": "zip", 765 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/e3249dedc2d99259ccae6affbc2684eac37c2e53", 766 | "reference": "e3249dedc2d99259ccae6affbc2684eac37c2e53", 767 | "shasum": "" 768 | }, 769 | "require": { 770 | "doctrine/instantiator": "^1.0.5", 771 | "php": "^7.1", 772 | "phpunit/php-text-template": "^1.2.1", 773 | "sebastian/exporter": "^3.1" 774 | }, 775 | "require-dev": { 776 | "phpunit/phpunit": "^7.0" 777 | }, 778 | "suggest": { 779 | "ext-soap": "*" 780 | }, 781 | "type": "library", 782 | "extra": { 783 | "branch-alias": { 784 | "dev-master": "6.0.x-dev" 785 | } 786 | }, 787 | "autoload": { 788 | "classmap": [ 789 | "src/" 790 | ] 791 | }, 792 | "notification-url": "https://packagist.org/downloads/", 793 | "license": [ 794 | "BSD-3-Clause" 795 | ], 796 | "authors": [ 797 | { 798 | "name": "Sebastian Bergmann", 799 | "email": "sebastian@phpunit.de", 800 | "role": "lead" 801 | } 802 | ], 803 | "description": "Mock Object library for PHPUnit", 804 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 805 | "keywords": [ 806 | "mock", 807 | "xunit" 808 | ], 809 | "time": "2018-02-15T05:27:38+00:00" 810 | }, 811 | { 812 | "name": "sebastian/code-unit-reverse-lookup", 813 | "version": "1.0.1", 814 | "source": { 815 | "type": "git", 816 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 817 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" 818 | }, 819 | "dist": { 820 | "type": "zip", 821 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 822 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 823 | "shasum": "" 824 | }, 825 | "require": { 826 | "php": "^5.6 || ^7.0" 827 | }, 828 | "require-dev": { 829 | "phpunit/phpunit": "^5.7 || ^6.0" 830 | }, 831 | "type": "library", 832 | "extra": { 833 | "branch-alias": { 834 | "dev-master": "1.0.x-dev" 835 | } 836 | }, 837 | "autoload": { 838 | "classmap": [ 839 | "src/" 840 | ] 841 | }, 842 | "notification-url": "https://packagist.org/downloads/", 843 | "license": [ 844 | "BSD-3-Clause" 845 | ], 846 | "authors": [ 847 | { 848 | "name": "Sebastian Bergmann", 849 | "email": "sebastian@phpunit.de" 850 | } 851 | ], 852 | "description": "Looks up which function or method a line of code belongs to", 853 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 854 | "time": "2017-03-04T06:30:41+00:00" 855 | }, 856 | { 857 | "name": "sebastian/comparator", 858 | "version": "2.1.3", 859 | "source": { 860 | "type": "git", 861 | "url": "https://github.com/sebastianbergmann/comparator.git", 862 | "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" 863 | }, 864 | "dist": { 865 | "type": "zip", 866 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", 867 | "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", 868 | "shasum": "" 869 | }, 870 | "require": { 871 | "php": "^7.0", 872 | "sebastian/diff": "^2.0 || ^3.0", 873 | "sebastian/exporter": "^3.1" 874 | }, 875 | "require-dev": { 876 | "phpunit/phpunit": "^6.4" 877 | }, 878 | "type": "library", 879 | "extra": { 880 | "branch-alias": { 881 | "dev-master": "2.1.x-dev" 882 | } 883 | }, 884 | "autoload": { 885 | "classmap": [ 886 | "src/" 887 | ] 888 | }, 889 | "notification-url": "https://packagist.org/downloads/", 890 | "license": [ 891 | "BSD-3-Clause" 892 | ], 893 | "authors": [ 894 | { 895 | "name": "Jeff Welch", 896 | "email": "whatthejeff@gmail.com" 897 | }, 898 | { 899 | "name": "Volker Dusch", 900 | "email": "github@wallbash.com" 901 | }, 902 | { 903 | "name": "Bernhard Schussek", 904 | "email": "bschussek@2bepublished.at" 905 | }, 906 | { 907 | "name": "Sebastian Bergmann", 908 | "email": "sebastian@phpunit.de" 909 | } 910 | ], 911 | "description": "Provides the functionality to compare PHP values for equality", 912 | "homepage": "https://github.com/sebastianbergmann/comparator", 913 | "keywords": [ 914 | "comparator", 915 | "compare", 916 | "equality" 917 | ], 918 | "time": "2018-02-01T13:46:46+00:00" 919 | }, 920 | { 921 | "name": "sebastian/diff", 922 | "version": "3.0.0", 923 | "source": { 924 | "type": "git", 925 | "url": "https://github.com/sebastianbergmann/diff.git", 926 | "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8" 927 | }, 928 | "dist": { 929 | "type": "zip", 930 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/e09160918c66281713f1c324c1f4c4c3037ba1e8", 931 | "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8", 932 | "shasum": "" 933 | }, 934 | "require": { 935 | "php": "^7.1" 936 | }, 937 | "require-dev": { 938 | "phpunit/phpunit": "^7.0", 939 | "symfony/process": "^2 || ^3.3 || ^4" 940 | }, 941 | "type": "library", 942 | "extra": { 943 | "branch-alias": { 944 | "dev-master": "3.0-dev" 945 | } 946 | }, 947 | "autoload": { 948 | "classmap": [ 949 | "src/" 950 | ] 951 | }, 952 | "notification-url": "https://packagist.org/downloads/", 953 | "license": [ 954 | "BSD-3-Clause" 955 | ], 956 | "authors": [ 957 | { 958 | "name": "Kore Nordmann", 959 | "email": "mail@kore-nordmann.de" 960 | }, 961 | { 962 | "name": "Sebastian Bergmann", 963 | "email": "sebastian@phpunit.de" 964 | } 965 | ], 966 | "description": "Diff implementation", 967 | "homepage": "https://github.com/sebastianbergmann/diff", 968 | "keywords": [ 969 | "diff", 970 | "udiff", 971 | "unidiff", 972 | "unified diff" 973 | ], 974 | "time": "2018-02-01T13:45:15+00:00" 975 | }, 976 | { 977 | "name": "sebastian/environment", 978 | "version": "3.1.0", 979 | "source": { 980 | "type": "git", 981 | "url": "https://github.com/sebastianbergmann/environment.git", 982 | "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" 983 | }, 984 | "dist": { 985 | "type": "zip", 986 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", 987 | "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", 988 | "shasum": "" 989 | }, 990 | "require": { 991 | "php": "^7.0" 992 | }, 993 | "require-dev": { 994 | "phpunit/phpunit": "^6.1" 995 | }, 996 | "type": "library", 997 | "extra": { 998 | "branch-alias": { 999 | "dev-master": "3.1.x-dev" 1000 | } 1001 | }, 1002 | "autoload": { 1003 | "classmap": [ 1004 | "src/" 1005 | ] 1006 | }, 1007 | "notification-url": "https://packagist.org/downloads/", 1008 | "license": [ 1009 | "BSD-3-Clause" 1010 | ], 1011 | "authors": [ 1012 | { 1013 | "name": "Sebastian Bergmann", 1014 | "email": "sebastian@phpunit.de" 1015 | } 1016 | ], 1017 | "description": "Provides functionality to handle HHVM/PHP environments", 1018 | "homepage": "http://www.github.com/sebastianbergmann/environment", 1019 | "keywords": [ 1020 | "Xdebug", 1021 | "environment", 1022 | "hhvm" 1023 | ], 1024 | "time": "2017-07-01T08:51:00+00:00" 1025 | }, 1026 | { 1027 | "name": "sebastian/exporter", 1028 | "version": "3.1.0", 1029 | "source": { 1030 | "type": "git", 1031 | "url": "https://github.com/sebastianbergmann/exporter.git", 1032 | "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" 1033 | }, 1034 | "dist": { 1035 | "type": "zip", 1036 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", 1037 | "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", 1038 | "shasum": "" 1039 | }, 1040 | "require": { 1041 | "php": "^7.0", 1042 | "sebastian/recursion-context": "^3.0" 1043 | }, 1044 | "require-dev": { 1045 | "ext-mbstring": "*", 1046 | "phpunit/phpunit": "^6.0" 1047 | }, 1048 | "type": "library", 1049 | "extra": { 1050 | "branch-alias": { 1051 | "dev-master": "3.1.x-dev" 1052 | } 1053 | }, 1054 | "autoload": { 1055 | "classmap": [ 1056 | "src/" 1057 | ] 1058 | }, 1059 | "notification-url": "https://packagist.org/downloads/", 1060 | "license": [ 1061 | "BSD-3-Clause" 1062 | ], 1063 | "authors": [ 1064 | { 1065 | "name": "Jeff Welch", 1066 | "email": "whatthejeff@gmail.com" 1067 | }, 1068 | { 1069 | "name": "Volker Dusch", 1070 | "email": "github@wallbash.com" 1071 | }, 1072 | { 1073 | "name": "Bernhard Schussek", 1074 | "email": "bschussek@2bepublished.at" 1075 | }, 1076 | { 1077 | "name": "Sebastian Bergmann", 1078 | "email": "sebastian@phpunit.de" 1079 | }, 1080 | { 1081 | "name": "Adam Harvey", 1082 | "email": "aharvey@php.net" 1083 | } 1084 | ], 1085 | "description": "Provides the functionality to export PHP variables for visualization", 1086 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 1087 | "keywords": [ 1088 | "export", 1089 | "exporter" 1090 | ], 1091 | "time": "2017-04-03T13:19:02+00:00" 1092 | }, 1093 | { 1094 | "name": "sebastian/global-state", 1095 | "version": "2.0.0", 1096 | "source": { 1097 | "type": "git", 1098 | "url": "https://github.com/sebastianbergmann/global-state.git", 1099 | "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" 1100 | }, 1101 | "dist": { 1102 | "type": "zip", 1103 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", 1104 | "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", 1105 | "shasum": "" 1106 | }, 1107 | "require": { 1108 | "php": "^7.0" 1109 | }, 1110 | "require-dev": { 1111 | "phpunit/phpunit": "^6.0" 1112 | }, 1113 | "suggest": { 1114 | "ext-uopz": "*" 1115 | }, 1116 | "type": "library", 1117 | "extra": { 1118 | "branch-alias": { 1119 | "dev-master": "2.0-dev" 1120 | } 1121 | }, 1122 | "autoload": { 1123 | "classmap": [ 1124 | "src/" 1125 | ] 1126 | }, 1127 | "notification-url": "https://packagist.org/downloads/", 1128 | "license": [ 1129 | "BSD-3-Clause" 1130 | ], 1131 | "authors": [ 1132 | { 1133 | "name": "Sebastian Bergmann", 1134 | "email": "sebastian@phpunit.de" 1135 | } 1136 | ], 1137 | "description": "Snapshotting of global state", 1138 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1139 | "keywords": [ 1140 | "global state" 1141 | ], 1142 | "time": "2017-04-27T15:39:26+00:00" 1143 | }, 1144 | { 1145 | "name": "sebastian/object-enumerator", 1146 | "version": "3.0.3", 1147 | "source": { 1148 | "type": "git", 1149 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1150 | "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" 1151 | }, 1152 | "dist": { 1153 | "type": "zip", 1154 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", 1155 | "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", 1156 | "shasum": "" 1157 | }, 1158 | "require": { 1159 | "php": "^7.0", 1160 | "sebastian/object-reflector": "^1.1.1", 1161 | "sebastian/recursion-context": "^3.0" 1162 | }, 1163 | "require-dev": { 1164 | "phpunit/phpunit": "^6.0" 1165 | }, 1166 | "type": "library", 1167 | "extra": { 1168 | "branch-alias": { 1169 | "dev-master": "3.0.x-dev" 1170 | } 1171 | }, 1172 | "autoload": { 1173 | "classmap": [ 1174 | "src/" 1175 | ] 1176 | }, 1177 | "notification-url": "https://packagist.org/downloads/", 1178 | "license": [ 1179 | "BSD-3-Clause" 1180 | ], 1181 | "authors": [ 1182 | { 1183 | "name": "Sebastian Bergmann", 1184 | "email": "sebastian@phpunit.de" 1185 | } 1186 | ], 1187 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1188 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1189 | "time": "2017-08-03T12:35:26+00:00" 1190 | }, 1191 | { 1192 | "name": "sebastian/object-reflector", 1193 | "version": "1.1.1", 1194 | "source": { 1195 | "type": "git", 1196 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 1197 | "reference": "773f97c67f28de00d397be301821b06708fca0be" 1198 | }, 1199 | "dist": { 1200 | "type": "zip", 1201 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", 1202 | "reference": "773f97c67f28de00d397be301821b06708fca0be", 1203 | "shasum": "" 1204 | }, 1205 | "require": { 1206 | "php": "^7.0" 1207 | }, 1208 | "require-dev": { 1209 | "phpunit/phpunit": "^6.0" 1210 | }, 1211 | "type": "library", 1212 | "extra": { 1213 | "branch-alias": { 1214 | "dev-master": "1.1-dev" 1215 | } 1216 | }, 1217 | "autoload": { 1218 | "classmap": [ 1219 | "src/" 1220 | ] 1221 | }, 1222 | "notification-url": "https://packagist.org/downloads/", 1223 | "license": [ 1224 | "BSD-3-Clause" 1225 | ], 1226 | "authors": [ 1227 | { 1228 | "name": "Sebastian Bergmann", 1229 | "email": "sebastian@phpunit.de" 1230 | } 1231 | ], 1232 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 1233 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 1234 | "time": "2017-03-29T09:07:27+00:00" 1235 | }, 1236 | { 1237 | "name": "sebastian/recursion-context", 1238 | "version": "3.0.0", 1239 | "source": { 1240 | "type": "git", 1241 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1242 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" 1243 | }, 1244 | "dist": { 1245 | "type": "zip", 1246 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", 1247 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", 1248 | "shasum": "" 1249 | }, 1250 | "require": { 1251 | "php": "^7.0" 1252 | }, 1253 | "require-dev": { 1254 | "phpunit/phpunit": "^6.0" 1255 | }, 1256 | "type": "library", 1257 | "extra": { 1258 | "branch-alias": { 1259 | "dev-master": "3.0.x-dev" 1260 | } 1261 | }, 1262 | "autoload": { 1263 | "classmap": [ 1264 | "src/" 1265 | ] 1266 | }, 1267 | "notification-url": "https://packagist.org/downloads/", 1268 | "license": [ 1269 | "BSD-3-Clause" 1270 | ], 1271 | "authors": [ 1272 | { 1273 | "name": "Jeff Welch", 1274 | "email": "whatthejeff@gmail.com" 1275 | }, 1276 | { 1277 | "name": "Sebastian Bergmann", 1278 | "email": "sebastian@phpunit.de" 1279 | }, 1280 | { 1281 | "name": "Adam Harvey", 1282 | "email": "aharvey@php.net" 1283 | } 1284 | ], 1285 | "description": "Provides functionality to recursively process PHP variables", 1286 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 1287 | "time": "2017-03-03T06:23:57+00:00" 1288 | }, 1289 | { 1290 | "name": "sebastian/resource-operations", 1291 | "version": "1.0.0", 1292 | "source": { 1293 | "type": "git", 1294 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 1295 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" 1296 | }, 1297 | "dist": { 1298 | "type": "zip", 1299 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1300 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1301 | "shasum": "" 1302 | }, 1303 | "require": { 1304 | "php": ">=5.6.0" 1305 | }, 1306 | "type": "library", 1307 | "extra": { 1308 | "branch-alias": { 1309 | "dev-master": "1.0.x-dev" 1310 | } 1311 | }, 1312 | "autoload": { 1313 | "classmap": [ 1314 | "src/" 1315 | ] 1316 | }, 1317 | "notification-url": "https://packagist.org/downloads/", 1318 | "license": [ 1319 | "BSD-3-Clause" 1320 | ], 1321 | "authors": [ 1322 | { 1323 | "name": "Sebastian Bergmann", 1324 | "email": "sebastian@phpunit.de" 1325 | } 1326 | ], 1327 | "description": "Provides a list of PHP built-in functions that operate on resources", 1328 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 1329 | "time": "2015-07-28T20:34:47+00:00" 1330 | }, 1331 | { 1332 | "name": "sebastian/version", 1333 | "version": "2.0.1", 1334 | "source": { 1335 | "type": "git", 1336 | "url": "https://github.com/sebastianbergmann/version.git", 1337 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" 1338 | }, 1339 | "dist": { 1340 | "type": "zip", 1341 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", 1342 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", 1343 | "shasum": "" 1344 | }, 1345 | "require": { 1346 | "php": ">=5.6" 1347 | }, 1348 | "type": "library", 1349 | "extra": { 1350 | "branch-alias": { 1351 | "dev-master": "2.0.x-dev" 1352 | } 1353 | }, 1354 | "autoload": { 1355 | "classmap": [ 1356 | "src/" 1357 | ] 1358 | }, 1359 | "notification-url": "https://packagist.org/downloads/", 1360 | "license": [ 1361 | "BSD-3-Clause" 1362 | ], 1363 | "authors": [ 1364 | { 1365 | "name": "Sebastian Bergmann", 1366 | "email": "sebastian@phpunit.de", 1367 | "role": "lead" 1368 | } 1369 | ], 1370 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1371 | "homepage": "https://github.com/sebastianbergmann/version", 1372 | "time": "2016-10-03T07:35:21+00:00" 1373 | }, 1374 | { 1375 | "name": "squizlabs/php_codesniffer", 1376 | "version": "2.9.1", 1377 | "source": { 1378 | "type": "git", 1379 | "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", 1380 | "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62" 1381 | }, 1382 | "dist": { 1383 | "type": "zip", 1384 | "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dcbed1074f8244661eecddfc2a675430d8d33f62", 1385 | "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62", 1386 | "shasum": "" 1387 | }, 1388 | "require": { 1389 | "ext-simplexml": "*", 1390 | "ext-tokenizer": "*", 1391 | "ext-xmlwriter": "*", 1392 | "php": ">=5.1.2" 1393 | }, 1394 | "require-dev": { 1395 | "phpunit/phpunit": "~4.0" 1396 | }, 1397 | "bin": [ 1398 | "scripts/phpcs", 1399 | "scripts/phpcbf" 1400 | ], 1401 | "type": "library", 1402 | "extra": { 1403 | "branch-alias": { 1404 | "dev-master": "2.x-dev" 1405 | } 1406 | }, 1407 | "autoload": { 1408 | "classmap": [ 1409 | "CodeSniffer.php", 1410 | "CodeSniffer/CLI.php", 1411 | "CodeSniffer/Exception.php", 1412 | "CodeSniffer/File.php", 1413 | "CodeSniffer/Fixer.php", 1414 | "CodeSniffer/Report.php", 1415 | "CodeSniffer/Reporting.php", 1416 | "CodeSniffer/Sniff.php", 1417 | "CodeSniffer/Tokens.php", 1418 | "CodeSniffer/Reports/", 1419 | "CodeSniffer/Tokenizers/", 1420 | "CodeSniffer/DocGenerators/", 1421 | "CodeSniffer/Standards/AbstractPatternSniff.php", 1422 | "CodeSniffer/Standards/AbstractScopeSniff.php", 1423 | "CodeSniffer/Standards/AbstractVariableSniff.php", 1424 | "CodeSniffer/Standards/IncorrectPatternException.php", 1425 | "CodeSniffer/Standards/Generic/Sniffs/", 1426 | "CodeSniffer/Standards/MySource/Sniffs/", 1427 | "CodeSniffer/Standards/PEAR/Sniffs/", 1428 | "CodeSniffer/Standards/PSR1/Sniffs/", 1429 | "CodeSniffer/Standards/PSR2/Sniffs/", 1430 | "CodeSniffer/Standards/Squiz/Sniffs/", 1431 | "CodeSniffer/Standards/Zend/Sniffs/" 1432 | ] 1433 | }, 1434 | "notification-url": "https://packagist.org/downloads/", 1435 | "license": [ 1436 | "BSD-3-Clause" 1437 | ], 1438 | "authors": [ 1439 | { 1440 | "name": "Greg Sherwood", 1441 | "role": "lead" 1442 | } 1443 | ], 1444 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", 1445 | "homepage": "http://www.squizlabs.com/php-codesniffer", 1446 | "keywords": [ 1447 | "phpcs", 1448 | "standards" 1449 | ], 1450 | "time": "2017-05-22T02:43:20+00:00" 1451 | }, 1452 | { 1453 | "name": "theseer/tokenizer", 1454 | "version": "1.1.0", 1455 | "source": { 1456 | "type": "git", 1457 | "url": "https://github.com/theseer/tokenizer.git", 1458 | "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" 1459 | }, 1460 | "dist": { 1461 | "type": "zip", 1462 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", 1463 | "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", 1464 | "shasum": "" 1465 | }, 1466 | "require": { 1467 | "ext-dom": "*", 1468 | "ext-tokenizer": "*", 1469 | "ext-xmlwriter": "*", 1470 | "php": "^7.0" 1471 | }, 1472 | "type": "library", 1473 | "autoload": { 1474 | "classmap": [ 1475 | "src/" 1476 | ] 1477 | }, 1478 | "notification-url": "https://packagist.org/downloads/", 1479 | "license": [ 1480 | "BSD-3-Clause" 1481 | ], 1482 | "authors": [ 1483 | { 1484 | "name": "Arne Blankerts", 1485 | "email": "arne@blankerts.de", 1486 | "role": "Developer" 1487 | } 1488 | ], 1489 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", 1490 | "time": "2017-04-07T12:08:54+00:00" 1491 | }, 1492 | { 1493 | "name": "webmozart/assert", 1494 | "version": "1.3.0", 1495 | "source": { 1496 | "type": "git", 1497 | "url": "https://github.com/webmozart/assert.git", 1498 | "reference": "0df1908962e7a3071564e857d86874dad1ef204a" 1499 | }, 1500 | "dist": { 1501 | "type": "zip", 1502 | "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", 1503 | "reference": "0df1908962e7a3071564e857d86874dad1ef204a", 1504 | "shasum": "" 1505 | }, 1506 | "require": { 1507 | "php": "^5.3.3 || ^7.0" 1508 | }, 1509 | "require-dev": { 1510 | "phpunit/phpunit": "^4.6", 1511 | "sebastian/version": "^1.0.1" 1512 | }, 1513 | "type": "library", 1514 | "extra": { 1515 | "branch-alias": { 1516 | "dev-master": "1.3-dev" 1517 | } 1518 | }, 1519 | "autoload": { 1520 | "psr-4": { 1521 | "Webmozart\\Assert\\": "src/" 1522 | } 1523 | }, 1524 | "notification-url": "https://packagist.org/downloads/", 1525 | "license": [ 1526 | "MIT" 1527 | ], 1528 | "authors": [ 1529 | { 1530 | "name": "Bernhard Schussek", 1531 | "email": "bschussek@gmail.com" 1532 | } 1533 | ], 1534 | "description": "Assertions to validate method input/output with nice error messages.", 1535 | "keywords": [ 1536 | "assert", 1537 | "check", 1538 | "validate" 1539 | ], 1540 | "time": "2018-01-29T19:49:41+00:00" 1541 | }, 1542 | { 1543 | "name": "zendframework/zend-coding-standard", 1544 | "version": "1.0.0", 1545 | "source": { 1546 | "type": "git", 1547 | "url": "https://github.com/zendframework/zend-coding-standard.git", 1548 | "reference": "893316d2904e93f1c74c1384b6d7d57778299cb6" 1549 | }, 1550 | "dist": { 1551 | "type": "zip", 1552 | "url": "https://api.github.com/repos/zendframework/zend-coding-standard/zipball/893316d2904e93f1c74c1384b6d7d57778299cb6", 1553 | "reference": "893316d2904e93f1c74c1384b6d7d57778299cb6", 1554 | "shasum": "" 1555 | }, 1556 | "require": { 1557 | "squizlabs/php_codesniffer": "^2.7" 1558 | }, 1559 | "type": "library", 1560 | "notification-url": "https://packagist.org/downloads/", 1561 | "license": [ 1562 | "BSD-3-Clause" 1563 | ], 1564 | "description": "Zend Framework coding standard", 1565 | "keywords": [ 1566 | "Coding Standard", 1567 | "zf" 1568 | ], 1569 | "time": "2016-11-09T21:30:43+00:00" 1570 | } 1571 | ], 1572 | "aliases": [], 1573 | "minimum-stability": "dev", 1574 | "stability-flags": [], 1575 | "prefer-stable": true, 1576 | "prefer-lowest": false, 1577 | "platform": { 1578 | "php": "^7.1" 1579 | }, 1580 | "platform-dev": [] 1581 | } 1582 | -------------------------------------------------------------------------------- /doc/book/examples.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | The following is a list of common use-case examples for zend-permission-rbac. 4 | 5 | ## Roles 6 | 7 | Extending and adding roles via instantiation: 8 | 9 | ```php 10 | use Zend\Permissions\Rbac\Rbac; 11 | use Zend\Permissions\Rbac\AbstractRole; 12 | 13 | class MyRole extends AbstractRole 14 | { 15 | // .. implementation 16 | } 17 | 18 | // Creating roles manually 19 | $foo = new MyRole('foo'); 20 | 21 | $rbac = new Rbac(); 22 | $rbac->addRole($foo); 23 | 24 | var_dump($rbac->hasRole('foo')); // true 25 | ``` 26 | 27 | Adding roles directly to RBAC with the default `Zend\Permission\Rbac\Role`: 28 | 29 | ```php 30 | use Zend\Permissions\Rbac\Rbac; 31 | 32 | $rbac = new Rbac(); 33 | $rbac->addRole('foo'); 34 | 35 | var_dump($rbac->hasRole('foo')); // true 36 | ``` 37 | 38 | Handling roles with children: 39 | 40 | ```php 41 | use Zend\Permissions\Rbac\Rbac; 42 | use Zend\Permissions\Rbac\Role; 43 | 44 | $rbac = new Rbac(); 45 | $foo = new Role('foo'); 46 | $bar = new Role('bar'); 47 | 48 | // 1 - Add a role with child role directly with instantiated classes. 49 | $foo->addChild($bar); 50 | $rbac->addRole($foo); 51 | 52 | // 2 - Same as one, only via rbac container. 53 | $rbac->addRole('boo', 'baz'); // baz is a parent of boo 54 | $rbac->addRole('baz', ['out', 'of', 'roles']); // create several parents of baz 55 | ``` 56 | 57 | ## Permissions 58 | 59 | ```php 60 | use Zend\Permissions\Rbac\Rbac; 61 | use Zend\Permissions\Rbac\Role; 62 | 63 | $rbac = new Rbac(); 64 | $foo = new Role('foo'); 65 | $foo->addPermission('bar'); 66 | 67 | var_dump($foo->hasPermission('bar')); // true 68 | 69 | $rbac->addRole($foo); 70 | $rbac->isGranted('foo', 'bar'); // true 71 | $rbac->isGranted('foo', 'baz'); // false 72 | 73 | $rbac->getRole('foo')->addPermission('baz'); 74 | $rbac->isGranted('foo', 'baz'); // true 75 | ``` 76 | 77 | ## Dynamic Assertions 78 | 79 | Checking permission using `isGranted()` with a class implementing 80 | `Zend\Permissions\Rbac\AssertionInterface`: 81 | 82 | ```php 83 | use App\Model\Article; 84 | use Zend\Permissions\Rbac\AssertionInterface; 85 | use Zend\Permissions\Rbac\Rbac; 86 | 87 | class AssertUserRoleMatches implements AssertionInterface 88 | { 89 | protected $userId; 90 | protected $article; 91 | 92 | public function __construct(string $userId) 93 | { 94 | $this->userId = $userId; 95 | } 96 | 97 | public function setArticle(Article $article) 98 | { 99 | $this->article = $article; 100 | } 101 | 102 | public function assert(Rbac $rbac, RoleInterface $role = null, string $permission = null) 103 | { 104 | if (! $this->article) { 105 | return false; 106 | } 107 | return ($this->userId === $this->article->getUserId()); 108 | } 109 | } 110 | 111 | // User is assigned the foo role with id 5 112 | // News article belongs to userId 5 113 | // Jazz article belongs to userId 6 114 | 115 | $rbac = new Rbac(); 116 | $user = $mySessionObject->getUser(); 117 | $news = $articleService->getArticle(5); 118 | $jazz = $articleService->getArticle(6); 119 | 120 | $rbac->addRole($user->getRole()); 121 | $rbac->getRole($user->getRole())->addPermission('edit.article'); 122 | 123 | $assertion = new AssertUserIdMatches($user->getId()); 124 | $assertion->setArticle($news); 125 | 126 | // true always - bad! 127 | if ($rbac->isGranted($user->getRole(), 'edit.article')) { 128 | // hacks another user's article 129 | } 130 | 131 | // true for user id 5, because he belongs to write group and user id matches 132 | if ($rbac->isGranted($user->getRole(), 'edit.article', $assertion)) { 133 | // edits his own article 134 | } 135 | 136 | $assertion->setArticle($jazz); 137 | 138 | // false for user id 5 139 | if ($rbac->isGranted($user->getRole(), 'edit.article', $assertion)) { 140 | // can not edit another user's article 141 | } 142 | ``` 143 | 144 | Performing the same as above with a closure: 145 | 146 | ```php 147 | // assume same variables from previous example 148 | 149 | $assertion = function($rbac) use ($user, $news) { 150 | return ($user->getId() === $news->getUserId()); 151 | }; 152 | 153 | // true 154 | if ($rbac->isGranted($user->getRole(), 'edit.article', $assertion)) { 155 | // edits his own article 156 | } 157 | ``` 158 | -------------------------------------------------------------------------------- /doc/book/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

zend-permissions-rbac

4 | 5 |

6 | Provide and query Role-Based Access Controls (RBAC) for your application. 7 |

8 | 9 |
$ composer require zendframework/zend-permissions-rbac
10 |
11 |
12 | -------------------------------------------------------------------------------- /doc/book/index.md: -------------------------------------------------------------------------------- 1 | ../../README.md -------------------------------------------------------------------------------- /doc/book/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | `zend-permissions-rbac` provides a lightweight [Role-Based Access Control](https://it.wikipedia.org/wiki/Role-based_access_control) 4 | (RBAC) implementation in PHP. RBAC differs from access control lists (ACL) by 5 | putting the emphasis on roles and their permissions rather than objects 6 | (resources). 7 | 8 | For the purposes of this documentation: 9 | 10 | - an **identity** has one or more roles. 11 | - a **role** requests access to a permission. 12 | - a **permission** is given to a role. 13 | 14 | Thus, RBAC has the following model: 15 | 16 | - many to many relationship between **identities** and **roles**. 17 | - many to many relationship between **roles** and **permissions**. 18 | - **roles** can have parent and child roles (hierarchy of roles). 19 | 20 | ## Roles 21 | 22 | To create a role, extend the abstract class `Zend\Permission\Rbac\AbstractRole` 23 | or use the default role class, `Zend\Permission\Rbac\Role`. You can instantiate 24 | a role and add it to the RBAC container or add a role directly using the RBAC 25 | container `addRole()` method. 26 | 27 | ## Permissions 28 | 29 | Each role can have zero or more permissions and can be set directly to the role 30 | or by first retrieving the role from the RBAC container. Any parent role will 31 | inherit the permissions of their children. 32 | 33 | ## Dynamic Assertions 34 | 35 | In certain situations simply checking a permission key for access may not be 36 | enough. For example, assume two users, Foo and Bar, both have `article.edit` 37 | permission. What's to stop Bar from editing Foo's articles? The answer is 38 | dynamic assertions which allow you to specify extra runtime credentials that 39 | must pass for access to be granted. 40 | -------------------------------------------------------------------------------- /doc/book/methods.md: -------------------------------------------------------------------------------- 1 | # Methods 2 | 3 | ## `Zend\Permissions\Rbac\Role` 4 | 5 | The `Role` provides the base functionality required by the `RoleInterface`. 6 | 7 | Method signature | Description 8 | ----------------------------------------------- | ----------- 9 | `__construct(string $name) : void` | Create a new instance with the provided name. 10 | `getName() : string` | Retrieve the name assigned to this role. 11 | `addPermission(string $name) : void` | Add a permission for the current role. 12 | `hasPermission(string $name) : bool` | Does the role have the given permission? 13 | `getPermissions(bool $children = true) : array` | Retrieve all permissions, including child permissions if `$children` is true. 14 | `addChild(RoleInterface $child) : Role` | Add a child role to the current instance. 15 | `getChildren() : RoleInterface[]` | Get all child roles. 16 | `addParent(RoleInterface $parent) : Role` | Add a parent role to the current instance. 17 | `getParents() : RoleInterface[]` | Get all parent roles. 18 | 19 | ## `Zend\Permissions\Rbac\AssertionInterface` 20 | 21 | Custom assertions can be provided to `Rbac::isGranted()` (see below); such 22 | assertions are provided the `Rbac` instance on invocation, along with the role 23 | and permission being tested against. 24 | 25 | Method signature | Description 26 | -------------------------------------------------------------------- | ----------- 27 | `assert(Rbac $rbac, RoleInterface $role, string $permission) : bool` | Given an RBAC, a role, and a permission, determine if permission is granted. 28 | 29 | ## `Zend\Permissions\Rbac\Rbac` 30 | 31 | `Rbac` is the object with which you will interact within your application in 32 | order to query for permissions. 33 | 34 | Method signature | Description 35 | ----------------------------------------------------------------------------- | ----------- 36 | `addRole(string\|RoleInterface $child, array\|RoleInterface $parents = null)` | Add a role to the RBAC. If `$parents` is non-null, the `$child` is also added to any parents provided. 37 | `getRole(string $role) : RoleInterface` | Get the role specified by name, raising an exception if not found. 38 | `getRoles(): RoleInterface[]` | Retrieve all the roles. 39 | `hasRole(string\|RoleInterface $role) : bool` | Recursively queries the RBAC for the given role, returning `true` if found, `false` otherwise. 40 | `getCreateMissingRoles() : bool` | Retrieve the flag that determines whether or not `$parent` roles are added automatically if not present when calling `addRole()`. 41 | `setCreateMissingRoles(bool $flag) : void` | Set the flag that determines whether or not `$parent` roles are added automatically if not present when calling `addRole()`. 42 | `isGranted(string\|RoleInterface $role, string $permission, $assert = null)` | Determine if the role has the given permission. If `$assert` is provided and either an `AssertInterface` instance or callable, it will be queried before checking against the given role. 43 | -------------------------------------------------------------------------------- /doc/book/migration/to-v3-0.md: -------------------------------------------------------------------------------- 1 | # Upgrading to 3.0 2 | 3 | If you upgrade from version 2 releases, you will notice a few changes. This 4 | document details the changes 5 | 6 | ## Minimum supported PHP version 7 | 8 | Version 3 drops support for PHP versions prior to PHP 7.1. 9 | 10 | ## AssertionInterface 11 | 12 | The primary change is the `Zend\Permissions\Rbac\AssertionInterface::assert()` 13 | method definition. 14 | 15 | The new `assert` method has the following signature: 16 | 17 | ```php 18 | namespace Zend\Permissions\Rbac; 19 | 20 | public function assert( 21 | Rbac $rbac, 22 | RoleInterface $role, 23 | string $permission 24 | ) : bool 25 | ``` 26 | 27 | The version 2 releases defined the method such that it only accepted a single 28 | parameter, `Rbac $rbac`. Version 3 adds the `$role` and `$permission` 29 | parameters. This simplifies implementation of dynamic assertions using the role 30 | and the permission information. 31 | 32 | For instance, imagine you want to disable a specific permission `foo` for an 33 | `admin` role; you can implement that as follows: 34 | 35 | ```php 36 | public function assert(Rbac $rbac, RoleInterface $role, string $permission) : bool 37 | { 38 | return ! ($permission === 'foo' && $role->getName() === 'admin'); 39 | } 40 | ``` 41 | 42 | If you were previously implementing `AssertionInterface`, you will need to 43 | update the `assert()` signature to match the changes in version 3. 44 | 45 | If you were creating assertions as PHP callables, you may continue to use the 46 | existing signature; however, you may also expand them to accept the new 47 | arguments should they assist you in creating more complex, dynamic assertions. 48 | 49 | ## RoleInterface 50 | 51 | `Zend\Permissions\Rbac\RoleInterface` also received a number of changes, 52 | including type hints and method name changes. 53 | 54 | ### Type hints 55 | 56 | With the update to [PHP 7.1](#minimum-supported-php-version), we also updated 57 | the `RoleInterface` to provide: 58 | 59 | - scalar type hints where applicable (`addPermission()` and `hasPermission()`). 60 | - add return type hints (including scalar type hints) to all methods. 61 | 62 | You will need to examine the `RoleInterface` definitions to determine what 63 | changes to make to your implementations. 64 | 65 | ### setParent becomes addParent 66 | 67 | In version 3, we renamed the method `Role::setParent()` to `Role::addParent()`. 68 | This naming is more consistent with other method names, such as 69 | `Role::addChild()`, and also makes clear that more than one parent may be 70 | provided to any given role. 71 | 72 | ### getParent becomes getParents 73 | 74 | In line with the previous change, `getParent()` was also renamed to 75 | `getParents()`, which returns an array of `RoleInterface` instances. 76 | 77 | ### Removed support for string arguments in Role::addChild 78 | 79 | Version 3 no longer allows adding a child using a string role name; you may only 80 | provide `RoleInterface` instances. 81 | 82 | ### Adds getChildren 83 | 84 | Since roles may have multiple children, the method `getChildren()` was added; it 85 | returns an array of `RoleInterface` instances. 86 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | docs_dir: doc/book 2 | site_dir: doc/html 3 | pages: 4 | - index.md 5 | - Intro: intro.md 6 | - Reference: 7 | - Methods: methods.md 8 | - Examples: examples.md 9 | - Migration: 10 | - 'v2.X to v3.0': migration/to-v3-0.md 11 | site_name: zend-permissions-rbac 12 | site_description: zend-permissions-rbac 13 | repo_url: 'https://github.com/zendframework/zend-permissions-rbac' 14 | copyright: 'Copyright (c) 2016 Zend Technologies USA Inc.' 15 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | src 7 | test 8 | 9 | -------------------------------------------------------------------------------- /src/Assertion/CallbackAssertion.php: -------------------------------------------------------------------------------- 1 | callback = function ( 28 | Rbac $rbac, 29 | RoleInterface $role = null, 30 | string $permission = null 31 | ) use ($callback) : bool { 32 | return $callback($rbac, $role, $permission); 33 | }; 34 | } 35 | 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | public function assert(Rbac $rbac, RoleInterface $role, string $permission) : bool 40 | { 41 | return ($this->callback)($rbac, $role, $permission); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/AssertionInterface.php: -------------------------------------------------------------------------------- 1 | createMissingRoles = $createMissingRoles; 30 | } 31 | 32 | public function getCreateMissingRoles() : bool 33 | { 34 | return $this->createMissingRoles; 35 | } 36 | 37 | /** 38 | * Add a child. 39 | * 40 | * @param string|RoleInterface $role 41 | * @param null|array|RoleInterface $parents 42 | * @throws Exception\InvalidArgumentException if $role is not a string or 43 | * RoleInterface. 44 | */ 45 | public function addRole($role, $parents = null) : void 46 | { 47 | if (is_string($role)) { 48 | $role = new Role($role); 49 | } 50 | if (! $role instanceof RoleInterface) { 51 | throw new Exception\InvalidArgumentException( 52 | 'Role must be a string or implement Zend\Permissions\Rbac\RoleInterface' 53 | ); 54 | } 55 | 56 | if ($parents) { 57 | $parents = is_array($parents) ? $parents : [$parents]; 58 | foreach ($parents as $parent) { 59 | if ($this->createMissingRoles && ! $this->hasRole($parent)) { 60 | $this->addRole($parent); 61 | } 62 | if (is_string($parent)) { 63 | $parent = $this->getRole($parent); 64 | } 65 | $parent->addChild($role); 66 | } 67 | } 68 | 69 | $this->roles[$role->getName()] = $role; 70 | } 71 | 72 | /** 73 | * Is a role registered? 74 | * 75 | * @param RoleInterface|string $role 76 | */ 77 | public function hasRole($role) : bool 78 | { 79 | if (! is_string($role) && ! $role instanceof RoleInterface) { 80 | throw new Exception\InvalidArgumentException( 81 | 'Role must be a string or implement Zend\Permissions\Rbac\RoleInterface' 82 | ); 83 | } 84 | 85 | if (is_string($role)) { 86 | return isset($this->roles[$role]); 87 | } 88 | 89 | $roleName = $role->getName(); 90 | return isset($this->roles[$roleName]) 91 | && $this->roles[$roleName] === $role; 92 | } 93 | 94 | /** 95 | * Get a registered role by name 96 | * 97 | * @throws Exception\InvalidArgumentException if role is not found. 98 | */ 99 | public function getRole(string $roleName) : RoleInterface 100 | { 101 | if (! isset($this->roles[$roleName])) { 102 | throw new Exception\InvalidArgumentException(sprintf( 103 | 'No role with name "%s" could be found', 104 | $roleName 105 | )); 106 | } 107 | return $this->roles[$roleName]; 108 | } 109 | 110 | /** 111 | * Return all the roles 112 | * 113 | * @return RoleInterface[] 114 | */ 115 | public function getRoles(): array 116 | { 117 | return array_values($this->roles); 118 | } 119 | 120 | /** 121 | * Determines if access is granted by checking the role and child roles for permission. 122 | * 123 | * @param RoleInterface|string $role 124 | * @param null|AssertionInterface|Callable $assertion 125 | * @throws Exception\InvalidArgumentException if the role is not found. 126 | * @throws Exception\InvalidArgumentException if the assertion is an invalid type. 127 | */ 128 | public function isGranted($role, string $permission, $assertion = null) : bool 129 | { 130 | if (! $this->hasRole($role)) { 131 | throw new Exception\InvalidArgumentException(sprintf( 132 | 'No role with name "%s" could be found', 133 | is_object($role) ? $role->getName() : $role 134 | )); 135 | } 136 | 137 | if (is_string($role)) { 138 | $role = $this->getRole($role); 139 | } 140 | 141 | $result = $role->hasPermission($permission); 142 | if (false === $result || null === $assertion) { 143 | return $result; 144 | } 145 | 146 | if (! $assertion instanceof AssertionInterface 147 | && ! is_callable($assertion) 148 | ) { 149 | throw new Exception\InvalidArgumentException( 150 | 'Assertions must be a Callable or an instance of Zend\Permissions\Rbac\AssertionInterface' 151 | ); 152 | } 153 | 154 | if ($assertion instanceof AssertionInterface) { 155 | return $result && $assertion->assert($this, $role, $permission); 156 | } 157 | 158 | // Callable assertion provided. 159 | return $result && $assertion($this, $role, $permission); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/Role.php: -------------------------------------------------------------------------------- 1 | name = $name; 37 | } 38 | 39 | /** 40 | * Get the name of the role. 41 | */ 42 | public function getName() : string 43 | { 44 | return $this->name; 45 | } 46 | 47 | /** 48 | * Add a permission to the role. 49 | */ 50 | public function addPermission(string $name) : void 51 | { 52 | $this->permissions[$name] = true; 53 | } 54 | 55 | /** 56 | * Checks if a permission exists for this role or any child roles. 57 | */ 58 | public function hasPermission(string $name) : bool 59 | { 60 | if (isset($this->permissions[$name])) { 61 | return true; 62 | } 63 | 64 | foreach ($this->children as $child) { 65 | if ($child->hasPermission($name)) { 66 | return true; 67 | } 68 | } 69 | 70 | return false; 71 | } 72 | 73 | /** 74 | * Get the permissions of the role, included all the permissions 75 | * of the children if $children == true 76 | */ 77 | public function getPermissions(bool $children = true) : array 78 | { 79 | $permissions = array_keys($this->permissions); 80 | if ($children) { 81 | foreach ($this->children as $child) { 82 | $permissions = array_merge($permissions, $child->getPermissions()); 83 | } 84 | } 85 | return $permissions; 86 | } 87 | 88 | /** 89 | * Add a child role. 90 | * 91 | * @throws Exception\CircularReferenceException 92 | */ 93 | public function addChild(RoleInterface $child) : void 94 | { 95 | $childName = $child->getName(); 96 | if ($this->hasAncestor($child)) { 97 | throw new Exception\CircularReferenceException(sprintf( 98 | 'To prevent circular references, you cannot add role "%s" as child', 99 | $childName 100 | )); 101 | } 102 | 103 | if (! isset($this->children[$childName])) { 104 | $this->children[$childName] = $child; 105 | $child->addParent($this); 106 | } 107 | } 108 | 109 | /** 110 | * Check if a role is an ancestor. 111 | */ 112 | protected function hasAncestor(RoleInterface $role) : bool 113 | { 114 | if (isset($this->parents[$role->getName()])) { 115 | return true; 116 | } 117 | 118 | foreach ($this->parents as $parent) { 119 | if ($parent->hasAncestor($role)) { 120 | return true; 121 | } 122 | } 123 | 124 | return false; 125 | } 126 | 127 | /** 128 | * Get all child roles 129 | * 130 | * @return RoleInterface[] 131 | */ 132 | public function getChildren() : array 133 | { 134 | return array_values($this->children); 135 | } 136 | 137 | /** 138 | * Add a parent role. 139 | * 140 | * @throws Exception\CircularReferenceException 141 | */ 142 | public function addParent(RoleInterface $parent) : void 143 | { 144 | $parentName = $parent->getName(); 145 | if ($this->hasDescendant($parent)) { 146 | throw new Exception\CircularReferenceException(sprintf( 147 | 'To prevent circular references, you cannot add role "%s" as parent', 148 | $parentName 149 | )); 150 | } 151 | 152 | if (! isset($this->parents[$parentName])) { 153 | $this->parents[$parentName] = $parent; 154 | $parent->addChild($this); 155 | } 156 | } 157 | 158 | /** 159 | * Check if a role is a descendant. 160 | */ 161 | protected function hasDescendant(RoleInterface $role) : bool 162 | { 163 | if (isset($this->children[$role->getName()])) { 164 | return true; 165 | } 166 | 167 | foreach ($this->children as $child) { 168 | if ($child->hasDescendant($role)) { 169 | return true; 170 | } 171 | } 172 | 173 | return false; 174 | } 175 | 176 | /** 177 | * Get the parent roles. 178 | * 179 | * @return RoleInterface[] 180 | */ 181 | public function getParents() : array 182 | { 183 | return array_values($this->parents); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /src/RoleInterface.php: -------------------------------------------------------------------------------- 1 |