├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── composer.lock └── src ├── DuplicateKeyException.php └── Manager.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor 3 | tests/_output/* 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Redis Yii2 RBAC Change Log 2 | ========================== 3 | 4 | 1.1.1 July 11, 2017 5 | ------------------- 6 | 7 | * Fix: fix missing `.gitattributes` 8 | 9 | 1.1.0 July 11, 2017 10 | ------------------- 11 | 12 | * Chg: remove testing on `HHVM` and `PHP 5.6` 13 | * Chg: update dependencies 14 | * Enh: adding `.gitattributes` 15 | 16 | 1.0.5.1 March 15, 2017 17 | ---------------------- 18 | 19 | * Fix: fix bad commit for test config 20 | 21 | 1.0.5 March 15, 2017 22 | -------------------- 23 | 24 | * Chg: update dependencies 25 | * Chg: adding `PHP 7.1` testing 26 | 27 | 1.0.4 December 6, 2016 28 | ---------------------- 29 | 30 | * Chg: Update dependencies 31 | 32 | 1.0.3 November 2, 2016 33 | ---------------------- 34 | 35 | * Chg: Update dependencies 36 | * Fix: Added `getChildRoles($roleName)` 37 | 38 | 1.0.2 June 22, 2016 39 | ------------------- 40 | 41 | * Fix: Update documentation 42 | * Chg: Update dependencies 43 | 44 | 1.0.1 May 2, 2016 45 | ----------------- 46 | 47 | * Fix: Remove forced type in `canAddChild()` to allow correct build 48 | 49 | 1.0.0 May 2, 2016 50 | ----------------- 51 | 52 | * Chg: Initial public release 53 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Sweelix Redis RBAC Manager is free software. It is released under the terms of the following BSD License. 2 | 3 | Copyright 2010-2017 by Sweelix SAS 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 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 | * Neither the name of Sweelix SAS nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Redis Yii2 RBAC integration 2 | =========================== 3 | 4 | This extension allow the developper to use REDIS database as the RBAC repository. 5 | 6 | 7 | [![Latest Stable Version](https://poser.pugx.org/sweelix/yii2-redis-rbac/v/stable)](https://packagist.org/packages/sweelix/yii2-redis-rbac) 8 | [![Build Status](https://api.travis-ci.org/pgaultier/yii2-redis-rbac.svg?branch=master)](https://travis-ci.org/pgaultier/yii2-redis-rbac) 9 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/pgaultier/yii2-redis-rbac/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/pgaultier/yii2-redis-rbac/?branch=master) 10 | [![Code Coverage](https://scrutinizer-ci.com/g/pgaultier/yii2-redis-rbac/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/pgaultier/yii2-redis-rbac/?branch=master) 11 | [![License](https://poser.pugx.org/sweelix/yii2-redis-rbac/license)](https://packagist.org/packages/sweelix/yii2-redis-rbac) 12 | 13 | [![Latest Development Version](https://img.shields.io/badge/unstable-devel-yellowgreen.svg)](https://packagist.org/packages/sweelix/yii2-redis-rbac) 14 | [![Build Status](https://travis-ci.org/pgaultier/yii2-redis-rbac.svg?branch=devel)](https://travis-ci.org/pgaultier/yii2-redis-rbac) 15 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/pgaultier/yii2-redis-rbac/badges/quality-score.png?b=devel)](https://scrutinizer-ci.com/g/pgaultier/yii2-redis-rbac/?branch=devel) 16 | [![Code Coverage](https://scrutinizer-ci.com/g/pgaultier/yii2-redis-rbac/badges/coverage.png?b=devel)](https://scrutinizer-ci.com/g/pgaultier/yii2-redis-rbac/?branch=devel) 17 | 18 | Installation 19 | ------------ 20 | 21 | If you use Packagist for installing packages, then you can update your composer.json like this : 22 | 23 | ``` json 24 | { 25 | "require": { 26 | "sweelix/yii2-redis-rbac": "*" 27 | } 28 | } 29 | ``` 30 | 31 | Howto use it 32 | ------------ 33 | 34 | Add extension to your configuration 35 | 36 | ``` php 37 | return [ 38 | //.... 39 | 'components' => [ 40 | 'authManager' => [ 41 | 'class' => 'sweelix\rbac\redis\Manager', 42 | 'db' => 'redis', 43 | ], 44 | // ... 45 | ], 46 | ]; 47 | ``` 48 | 49 | 50 | For further instructions refer to the [related section in the Yii Definitive Guide](http://www.yiiframework.com/doc-2.0/guide-security-authorization.html) 51 | 52 | 53 | Running the tests 54 | ----------------- 55 | 56 | Before running the tests, you should edit the file tests/config/redis.php and change the config to match your environment. 57 | 58 | Contributing 59 | ------------ 60 | 61 | All code contributions - including those of people having commit access - 62 | must go through a pull request and approved by a core developer before being 63 | merged. This is to ensure proper review of all the code. 64 | 65 | Fork the project, create a [feature branch ](http://nvie.com/posts/a-successful-git-branching-model/), and send us a pull request. 66 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sweelix/yii2-redis-rbac", 3 | "description": "PHP 5.6+ Redis / RBAC integration for the Yii framework", 4 | "keywords": ["yii2", "RBAC", "redis"], 5 | "type": "yii2-extension", 6 | "license": "BSD-3-Clause", 7 | "authors": [ 8 | { 9 | "name": "Philippe Gaultier", 10 | "email": "pgaultier@gmail.com" 11 | } 12 | ], 13 | "require": { 14 | "yiisoft/yii2": "~2.0", 15 | "yiisoft/yii2-redis": "~2.0", 16 | "php" : ">=5.6.0", 17 | "sweelix/guid": "~1.0" 18 | }, 19 | "require-dev" : { 20 | "php" : ">=5.6.0", 21 | "codeception/codeception": "~2.2" 22 | }, 23 | "autoload": { 24 | "psr-4": { "sweelix\\rbac\\redis\\": "src" } 25 | }, 26 | "extra": { 27 | "branch-alias": { 28 | "dev-devel": "1.0.x-dev" 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /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": "7ac5aa80a97ff6cfb622e3dc8e9069d5", 8 | "packages": [ 9 | { 10 | "name": "bower-asset/jquery", 11 | "version": "2.2.4", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/jquery/jquery-dist.git", 15 | "reference": "c0185ab7c75aab88762c5aae780b9d83b80eda72" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/jquery/jquery-dist/zipball/c0185ab7c75aab88762c5aae780b9d83b80eda72", 20 | "reference": "c0185ab7c75aab88762c5aae780b9d83b80eda72", 21 | "shasum": "" 22 | }, 23 | "type": "bower-asset-library", 24 | "extra": { 25 | "bower-asset-main": "dist/jquery.js", 26 | "bower-asset-ignore": [ 27 | "package.json" 28 | ] 29 | }, 30 | "license": [ 31 | "MIT" 32 | ], 33 | "keywords": [ 34 | "browser", 35 | "javascript", 36 | "jquery", 37 | "library" 38 | ] 39 | }, 40 | { 41 | "name": "bower-asset/jquery.inputmask", 42 | "version": "3.3.7", 43 | "source": { 44 | "type": "git", 45 | "url": "https://github.com/RobinHerbots/Inputmask.git", 46 | "reference": "9835731cb78cac749734d94a1cb5bd70da4d3b10" 47 | }, 48 | "dist": { 49 | "type": "zip", 50 | "url": "https://api.github.com/repos/RobinHerbots/Inputmask/zipball/9835731cb78cac749734d94a1cb5bd70da4d3b10", 51 | "reference": "9835731cb78cac749734d94a1cb5bd70da4d3b10", 52 | "shasum": "" 53 | }, 54 | "require": { 55 | "bower-asset/jquery": ">=1.7" 56 | }, 57 | "type": "bower-asset-library", 58 | "extra": { 59 | "bower-asset-main": [ 60 | "./dist/inputmask/inputmask.js", 61 | "./dist/inputmask/inputmask.extensions.js", 62 | "./dist/inputmask/inputmask.date.extensions.js", 63 | "./dist/inputmask/inputmask.numeric.extensions.js", 64 | "./dist/inputmask/inputmask.phone.extensions.js", 65 | "./dist/inputmask/jquery.inputmask.js", 66 | "./dist/inputmask/global/document.js", 67 | "./dist/inputmask/global/window.js", 68 | "./dist/inputmask/phone-codes/phone.js", 69 | "./dist/inputmask/phone-codes/phone-be.js", 70 | "./dist/inputmask/phone-codes/phone-nl.js", 71 | "./dist/inputmask/phone-codes/phone-ru.js", 72 | "./dist/inputmask/phone-codes/phone-uk.js", 73 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.jqlite.js", 74 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.jquery.js", 75 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.js", 76 | "./dist/inputmask/bindings/inputmask.binding.js" 77 | ], 78 | "bower-asset-ignore": [ 79 | "**/*", 80 | "!dist/*", 81 | "!dist/inputmask/*", 82 | "!dist/min/*", 83 | "!dist/min/inputmask/*" 84 | ] 85 | }, 86 | "license": [ 87 | "http://opensource.org/licenses/mit-license.php" 88 | ], 89 | "description": "Inputmask is a javascript library which creates an input mask. Inputmask can run against vanilla javascript, jQuery and jqlite.", 90 | "keywords": [ 91 | "form", 92 | "input", 93 | "inputmask", 94 | "jquery", 95 | "mask", 96 | "plugins" 97 | ] 98 | }, 99 | { 100 | "name": "bower-asset/punycode", 101 | "version": "v1.3.2", 102 | "source": { 103 | "type": "git", 104 | "url": "https://github.com/bestiejs/punycode.js.git", 105 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3" 106 | }, 107 | "dist": { 108 | "type": "zip", 109 | "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3", 110 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3", 111 | "shasum": "" 112 | }, 113 | "type": "bower-asset-library", 114 | "extra": { 115 | "bower-asset-main": "punycode.js", 116 | "bower-asset-ignore": [ 117 | "coverage", 118 | "tests", 119 | ".*", 120 | "component.json", 121 | "Gruntfile.js", 122 | "node_modules", 123 | "package.json" 124 | ] 125 | } 126 | }, 127 | { 128 | "name": "bower-asset/yii2-pjax", 129 | "version": "v2.0.6", 130 | "source": { 131 | "type": "git", 132 | "url": "https://github.com/yiisoft/jquery-pjax.git", 133 | "reference": "60728da6ade5879e807a49ce59ef9a72039b8978" 134 | }, 135 | "dist": { 136 | "type": "zip", 137 | "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/60728da6ade5879e807a49ce59ef9a72039b8978", 138 | "reference": "60728da6ade5879e807a49ce59ef9a72039b8978", 139 | "shasum": "" 140 | }, 141 | "require": { 142 | "bower-asset/jquery": ">=1.8" 143 | }, 144 | "type": "bower-asset-library", 145 | "extra": { 146 | "bower-asset-main": "./jquery.pjax.js", 147 | "bower-asset-ignore": [ 148 | ".travis.yml", 149 | "Gemfile", 150 | "Gemfile.lock", 151 | "CONTRIBUTING.md", 152 | "vendor/", 153 | "script/", 154 | "test/" 155 | ] 156 | }, 157 | "license": [ 158 | "MIT" 159 | ] 160 | }, 161 | { 162 | "name": "cebe/markdown", 163 | "version": "1.1.1", 164 | "source": { 165 | "type": "git", 166 | "url": "https://github.com/cebe/markdown.git", 167 | "reference": "c30eb5e01fe021cc5bba2f9ee0eeef96d4931166" 168 | }, 169 | "dist": { 170 | "type": "zip", 171 | "url": "https://api.github.com/repos/cebe/markdown/zipball/c30eb5e01fe021cc5bba2f9ee0eeef96d4931166", 172 | "reference": "c30eb5e01fe021cc5bba2f9ee0eeef96d4931166", 173 | "shasum": "" 174 | }, 175 | "require": { 176 | "lib-pcre": "*", 177 | "php": ">=5.4.0" 178 | }, 179 | "require-dev": { 180 | "cebe/indent": "*", 181 | "facebook/xhprof": "*@dev", 182 | "phpunit/phpunit": "4.1.*" 183 | }, 184 | "bin": [ 185 | "bin/markdown" 186 | ], 187 | "type": "library", 188 | "extra": { 189 | "branch-alias": { 190 | "dev-master": "1.1.x-dev" 191 | } 192 | }, 193 | "autoload": { 194 | "psr-4": { 195 | "cebe\\markdown\\": "" 196 | } 197 | }, 198 | "notification-url": "https://packagist.org/downloads/", 199 | "license": [ 200 | "MIT" 201 | ], 202 | "authors": [ 203 | { 204 | "name": "Carsten Brandt", 205 | "email": "mail@cebe.cc", 206 | "homepage": "http://cebe.cc/", 207 | "role": "Creator" 208 | } 209 | ], 210 | "description": "A super fast, highly extensible markdown parser for PHP", 211 | "homepage": "https://github.com/cebe/markdown#readme", 212 | "keywords": [ 213 | "extensible", 214 | "fast", 215 | "gfm", 216 | "markdown", 217 | "markdown-extra" 218 | ], 219 | "time": "2016-09-14T20:40:20+00:00" 220 | }, 221 | { 222 | "name": "ezyang/htmlpurifier", 223 | "version": "v4.9.3", 224 | "source": { 225 | "type": "git", 226 | "url": "https://github.com/ezyang/htmlpurifier.git", 227 | "reference": "95e1bae3182efc0f3422896a3236e991049dac69" 228 | }, 229 | "dist": { 230 | "type": "zip", 231 | "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/95e1bae3182efc0f3422896a3236e991049dac69", 232 | "reference": "95e1bae3182efc0f3422896a3236e991049dac69", 233 | "shasum": "" 234 | }, 235 | "require": { 236 | "php": ">=5.2" 237 | }, 238 | "require-dev": { 239 | "simpletest/simpletest": "^1.1" 240 | }, 241 | "type": "library", 242 | "autoload": { 243 | "psr-0": { 244 | "HTMLPurifier": "library/" 245 | }, 246 | "files": [ 247 | "library/HTMLPurifier.composer.php" 248 | ] 249 | }, 250 | "notification-url": "https://packagist.org/downloads/", 251 | "license": [ 252 | "LGPL" 253 | ], 254 | "authors": [ 255 | { 256 | "name": "Edward Z. Yang", 257 | "email": "admin@htmlpurifier.org", 258 | "homepage": "http://ezyang.com" 259 | } 260 | ], 261 | "description": "Standards compliant HTML filter written in PHP", 262 | "homepage": "http://htmlpurifier.org/", 263 | "keywords": [ 264 | "html" 265 | ], 266 | "time": "2017-06-03T02:28:16+00:00" 267 | }, 268 | { 269 | "name": "sweelix/guid", 270 | "version": "1.0.0", 271 | "source": { 272 | "type": "git", 273 | "url": "https://github.com/pgaultier/guid.git", 274 | "reference": "31aec7d6c0e314f2056cff18c8da9f9ed796504f" 275 | }, 276 | "dist": { 277 | "type": "zip", 278 | "url": "https://api.github.com/repos/pgaultier/guid/zipball/31aec7d6c0e314f2056cff18c8da9f9ed796504f", 279 | "reference": "31aec7d6c0e314f2056cff18c8da9f9ed796504f", 280 | "shasum": "" 281 | }, 282 | "require": { 283 | "php": ">=5.3.0" 284 | }, 285 | "require-dev": { 286 | "php": ">=5.3.0" 287 | }, 288 | "type": "library", 289 | "autoload": { 290 | "psr-4": { 291 | "sweelix\\guid\\": "" 292 | } 293 | }, 294 | "notification-url": "https://packagist.org/downloads/", 295 | "license": [ 296 | "BSD-3-Clause" 297 | ], 298 | "authors": [ 299 | { 300 | "name": "Philippe Gaultier", 301 | "email": "pgaultier@sweelix.net" 302 | } 303 | ], 304 | "description": "PHP 5.3+ simple GUID generator", 305 | "keywords": [ 306 | "guid", 307 | "uuid" 308 | ], 309 | "time": "2014-02-12T13:47:50+00:00" 310 | }, 311 | { 312 | "name": "yiisoft/yii2", 313 | "version": "2.0.12", 314 | "source": { 315 | "type": "git", 316 | "url": "https://github.com/yiisoft/yii2-framework.git", 317 | "reference": "70acbecc75cb26b6cd66d16be0b06e4b73db190d" 318 | }, 319 | "dist": { 320 | "type": "zip", 321 | "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/70acbecc75cb26b6cd66d16be0b06e4b73db190d", 322 | "reference": "70acbecc75cb26b6cd66d16be0b06e4b73db190d", 323 | "shasum": "" 324 | }, 325 | "require": { 326 | "bower-asset/jquery": "2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable", 327 | "bower-asset/jquery.inputmask": "~3.2.2 | ~3.3.5", 328 | "bower-asset/punycode": "1.3.*", 329 | "bower-asset/yii2-pjax": "~2.0.1", 330 | "cebe/markdown": "~1.0.0 | ~1.1.0", 331 | "ext-ctype": "*", 332 | "ext-mbstring": "*", 333 | "ezyang/htmlpurifier": "~4.6", 334 | "lib-pcre": "*", 335 | "php": ">=5.4.0", 336 | "yiisoft/yii2-composer": "~2.0.4" 337 | }, 338 | "bin": [ 339 | "yii" 340 | ], 341 | "type": "library", 342 | "extra": { 343 | "branch-alias": { 344 | "dev-master": "2.0.x-dev" 345 | } 346 | }, 347 | "autoload": { 348 | "psr-4": { 349 | "yii\\": "" 350 | } 351 | }, 352 | "notification-url": "https://packagist.org/downloads/", 353 | "license": [ 354 | "BSD-3-Clause" 355 | ], 356 | "authors": [ 357 | { 358 | "name": "Qiang Xue", 359 | "email": "qiang.xue@gmail.com", 360 | "homepage": "http://www.yiiframework.com/", 361 | "role": "Founder and project lead" 362 | }, 363 | { 364 | "name": "Alexander Makarov", 365 | "email": "sam@rmcreative.ru", 366 | "homepage": "http://rmcreative.ru/", 367 | "role": "Core framework development" 368 | }, 369 | { 370 | "name": "Maurizio Domba", 371 | "homepage": "http://mdomba.info/", 372 | "role": "Core framework development" 373 | }, 374 | { 375 | "name": "Carsten Brandt", 376 | "email": "mail@cebe.cc", 377 | "homepage": "http://cebe.cc/", 378 | "role": "Core framework development" 379 | }, 380 | { 381 | "name": "Timur Ruziev", 382 | "email": "resurtm@gmail.com", 383 | "homepage": "http://resurtm.com/", 384 | "role": "Core framework development" 385 | }, 386 | { 387 | "name": "Paul Klimov", 388 | "email": "klimov.paul@gmail.com", 389 | "role": "Core framework development" 390 | }, 391 | { 392 | "name": "Dmitry Naumenko", 393 | "email": "d.naumenko.a@gmail.com", 394 | "role": "Core framework development" 395 | }, 396 | { 397 | "name": "Boudewijn Vahrmeijer", 398 | "email": "info@dynasource.eu", 399 | "homepage": "http://dynasource.eu", 400 | "role": "Core framework development" 401 | } 402 | ], 403 | "description": "Yii PHP Framework Version 2", 404 | "homepage": "http://www.yiiframework.com/", 405 | "keywords": [ 406 | "framework", 407 | "yii2" 408 | ], 409 | "time": "2017-06-05T14:33:41+00:00" 410 | }, 411 | { 412 | "name": "yiisoft/yii2-composer", 413 | "version": "2.0.5", 414 | "source": { 415 | "type": "git", 416 | "url": "https://github.com/yiisoft/yii2-composer.git", 417 | "reference": "3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2" 418 | }, 419 | "dist": { 420 | "type": "zip", 421 | "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2", 422 | "reference": "3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2", 423 | "shasum": "" 424 | }, 425 | "require": { 426 | "composer-plugin-api": "^1.0" 427 | }, 428 | "require-dev": { 429 | "composer/composer": "^1.0" 430 | }, 431 | "type": "composer-plugin", 432 | "extra": { 433 | "class": "yii\\composer\\Plugin", 434 | "branch-alias": { 435 | "dev-master": "2.0.x-dev" 436 | } 437 | }, 438 | "autoload": { 439 | "psr-4": { 440 | "yii\\composer\\": "" 441 | } 442 | }, 443 | "notification-url": "https://packagist.org/downloads/", 444 | "license": [ 445 | "BSD-3-Clause" 446 | ], 447 | "authors": [ 448 | { 449 | "name": "Qiang Xue", 450 | "email": "qiang.xue@gmail.com" 451 | } 452 | ], 453 | "description": "The composer plugin for Yii extension installer", 454 | "keywords": [ 455 | "composer", 456 | "extension installer", 457 | "yii2" 458 | ], 459 | "time": "2016-12-20T13:26:02+00:00" 460 | }, 461 | { 462 | "name": "yiisoft/yii2-redis", 463 | "version": "2.0.6", 464 | "source": { 465 | "type": "git", 466 | "url": "https://github.com/yiisoft/yii2-redis.git", 467 | "reference": "5dc55d5187923219e9db86d149d56acf1f5a6ee8" 468 | }, 469 | "dist": { 470 | "type": "zip", 471 | "url": "https://api.github.com/repos/yiisoft/yii2-redis/zipball/5dc55d5187923219e9db86d149d56acf1f5a6ee8", 472 | "reference": "5dc55d5187923219e9db86d149d56acf1f5a6ee8", 473 | "shasum": "" 474 | }, 475 | "require": { 476 | "yiisoft/yii2": "~2.0.11" 477 | }, 478 | "type": "yii2-extension", 479 | "extra": { 480 | "branch-alias": { 481 | "dev-master": "2.0.x-dev" 482 | } 483 | }, 484 | "autoload": { 485 | "psr-4": { 486 | "yii\\redis\\": "" 487 | } 488 | }, 489 | "notification-url": "https://packagist.org/downloads/", 490 | "license": [ 491 | "BSD-3-Clause" 492 | ], 493 | "authors": [ 494 | { 495 | "name": "Carsten Brandt", 496 | "email": "mail@cebe.cc" 497 | } 498 | ], 499 | "description": "Redis Cache, Session and ActiveRecord for the Yii framework", 500 | "keywords": [ 501 | "active-record", 502 | "cache", 503 | "redis", 504 | "session", 505 | "yii2" 506 | ], 507 | "time": "2017-04-05T13:42:11+00:00" 508 | } 509 | ], 510 | "packages-dev": [ 511 | { 512 | "name": "behat/gherkin", 513 | "version": "v4.4.5", 514 | "source": { 515 | "type": "git", 516 | "url": "https://github.com/Behat/Gherkin.git", 517 | "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74" 518 | }, 519 | "dist": { 520 | "type": "zip", 521 | "url": "https://api.github.com/repos/Behat/Gherkin/zipball/5c14cff4f955b17d20d088dec1bde61c0539ec74", 522 | "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74", 523 | "shasum": "" 524 | }, 525 | "require": { 526 | "php": ">=5.3.1" 527 | }, 528 | "require-dev": { 529 | "phpunit/phpunit": "~4.5|~5", 530 | "symfony/phpunit-bridge": "~2.7|~3", 531 | "symfony/yaml": "~2.3|~3" 532 | }, 533 | "suggest": { 534 | "symfony/yaml": "If you want to parse features, represented in YAML files" 535 | }, 536 | "type": "library", 537 | "extra": { 538 | "branch-alias": { 539 | "dev-master": "4.4-dev" 540 | } 541 | }, 542 | "autoload": { 543 | "psr-0": { 544 | "Behat\\Gherkin": "src/" 545 | } 546 | }, 547 | "notification-url": "https://packagist.org/downloads/", 548 | "license": [ 549 | "MIT" 550 | ], 551 | "authors": [ 552 | { 553 | "name": "Konstantin Kudryashov", 554 | "email": "ever.zet@gmail.com", 555 | "homepage": "http://everzet.com" 556 | } 557 | ], 558 | "description": "Gherkin DSL parser for PHP 5.3", 559 | "homepage": "http://behat.org/", 560 | "keywords": [ 561 | "BDD", 562 | "Behat", 563 | "Cucumber", 564 | "DSL", 565 | "gherkin", 566 | "parser" 567 | ], 568 | "time": "2016-10-30T11:50:56+00:00" 569 | }, 570 | { 571 | "name": "codeception/codeception", 572 | "version": "2.3.4", 573 | "source": { 574 | "type": "git", 575 | "url": "https://github.com/Codeception/Codeception.git", 576 | "reference": "b5391497f9a3c9d0a9c02ae39b53441e413e35a8" 577 | }, 578 | "dist": { 579 | "type": "zip", 580 | "url": "https://api.github.com/repos/Codeception/Codeception/zipball/b5391497f9a3c9d0a9c02ae39b53441e413e35a8", 581 | "reference": "b5391497f9a3c9d0a9c02ae39b53441e413e35a8", 582 | "shasum": "" 583 | }, 584 | "require": { 585 | "behat/gherkin": "~4.4.0", 586 | "ext-json": "*", 587 | "ext-mbstring": "*", 588 | "facebook/webdriver": ">=1.0.1 <2.0", 589 | "guzzlehttp/guzzle": ">=4.1.4 <7.0", 590 | "guzzlehttp/psr7": "~1.0", 591 | "php": ">=5.4.0 <8.0", 592 | "phpunit/php-code-coverage": ">=2.2.4 <6.0", 593 | "phpunit/phpunit": ">4.8.20 <7.0", 594 | "phpunit/phpunit-mock-objects": ">2.3 <5.0", 595 | "sebastian/comparator": ">1.1 <3.0", 596 | "sebastian/diff": "^1.4", 597 | "stecman/symfony-console-completion": "^0.7.0", 598 | "symfony/browser-kit": ">=2.7 <4.0", 599 | "symfony/console": ">=2.7 <4.0", 600 | "symfony/css-selector": ">=2.7 <4.0", 601 | "symfony/dom-crawler": ">=2.7.5 <4.0", 602 | "symfony/event-dispatcher": ">=2.7 <4.0", 603 | "symfony/finder": ">=2.7 <4.0", 604 | "symfony/yaml": ">=2.7 <4.0" 605 | }, 606 | "require-dev": { 607 | "codeception/specify": "~0.3", 608 | "facebook/graph-sdk": "~5.3", 609 | "flow/jsonpath": "~0.2", 610 | "league/factory-muffin": "^3.0", 611 | "league/factory-muffin-faker": "^1.0", 612 | "mongodb/mongodb": "^1.0", 613 | "monolog/monolog": "~1.8", 614 | "pda/pheanstalk": "~3.0", 615 | "php-amqplib/php-amqplib": "~2.4", 616 | "predis/predis": "^1.0", 617 | "squizlabs/php_codesniffer": "~2.0", 618 | "symfony/process": ">=2.7 <4.0", 619 | "vlucas/phpdotenv": "^2.4.0" 620 | }, 621 | "suggest": { 622 | "codeception/specify": "BDD-style code blocks", 623 | "codeception/verify": "BDD-style assertions", 624 | "flow/jsonpath": "For using JSONPath in REST module", 625 | "league/factory-muffin": "For DataFactory module", 626 | "league/factory-muffin-faker": "For Faker support in DataFactory module", 627 | "phpseclib/phpseclib": "for SFTP option in FTP Module", 628 | "symfony/phpunit-bridge": "For phpunit-bridge support" 629 | }, 630 | "bin": [ 631 | "codecept" 632 | ], 633 | "type": "library", 634 | "extra": { 635 | "branch-alias": [] 636 | }, 637 | "autoload": { 638 | "psr-4": { 639 | "Codeception\\": "src\\Codeception", 640 | "Codeception\\Extension\\": "ext" 641 | } 642 | }, 643 | "notification-url": "https://packagist.org/downloads/", 644 | "license": [ 645 | "MIT" 646 | ], 647 | "authors": [ 648 | { 649 | "name": "Michael Bodnarchuk", 650 | "email": "davert@mail.ua", 651 | "homepage": "http://codegyre.com" 652 | } 653 | ], 654 | "description": "BDD-style testing framework", 655 | "homepage": "http://codeception.com/", 656 | "keywords": [ 657 | "BDD", 658 | "TDD", 659 | "acceptance testing", 660 | "functional testing", 661 | "unit testing" 662 | ], 663 | "time": "2017-07-10T19:45:09+00:00" 664 | }, 665 | { 666 | "name": "doctrine/instantiator", 667 | "version": "1.0.5", 668 | "source": { 669 | "type": "git", 670 | "url": "https://github.com/doctrine/instantiator.git", 671 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" 672 | }, 673 | "dist": { 674 | "type": "zip", 675 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", 676 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", 677 | "shasum": "" 678 | }, 679 | "require": { 680 | "php": ">=5.3,<8.0-DEV" 681 | }, 682 | "require-dev": { 683 | "athletic/athletic": "~0.1.8", 684 | "ext-pdo": "*", 685 | "ext-phar": "*", 686 | "phpunit/phpunit": "~4.0", 687 | "squizlabs/php_codesniffer": "~2.0" 688 | }, 689 | "type": "library", 690 | "extra": { 691 | "branch-alias": { 692 | "dev-master": "1.0.x-dev" 693 | } 694 | }, 695 | "autoload": { 696 | "psr-4": { 697 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 698 | } 699 | }, 700 | "notification-url": "https://packagist.org/downloads/", 701 | "license": [ 702 | "MIT" 703 | ], 704 | "authors": [ 705 | { 706 | "name": "Marco Pivetta", 707 | "email": "ocramius@gmail.com", 708 | "homepage": "http://ocramius.github.com/" 709 | } 710 | ], 711 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 712 | "homepage": "https://github.com/doctrine/instantiator", 713 | "keywords": [ 714 | "constructor", 715 | "instantiate" 716 | ], 717 | "time": "2015-06-14T21:17:01+00:00" 718 | }, 719 | { 720 | "name": "facebook/webdriver", 721 | "version": "1.4.1", 722 | "source": { 723 | "type": "git", 724 | "url": "https://github.com/facebook/php-webdriver.git", 725 | "reference": "eadb0b7a7c3e6578185197fd40158b08c3164c83" 726 | }, 727 | "dist": { 728 | "type": "zip", 729 | "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/eadb0b7a7c3e6578185197fd40158b08c3164c83", 730 | "reference": "eadb0b7a7c3e6578185197fd40158b08c3164c83", 731 | "shasum": "" 732 | }, 733 | "require": { 734 | "ext-curl": "*", 735 | "ext-zip": "*", 736 | "php": "^5.5 || ~7.0", 737 | "symfony/process": "^2.8 || ^3.1" 738 | }, 739 | "require-dev": { 740 | "friendsofphp/php-cs-fixer": "^2.0", 741 | "php-mock/php-mock-phpunit": "^1.1", 742 | "phpunit/phpunit": "4.6.* || ~5.0", 743 | "satooshi/php-coveralls": "^1.0", 744 | "squizlabs/php_codesniffer": "^2.6" 745 | }, 746 | "type": "library", 747 | "extra": { 748 | "branch-alias": { 749 | "dev-community": "1.5-dev" 750 | } 751 | }, 752 | "autoload": { 753 | "psr-4": { 754 | "Facebook\\WebDriver\\": "lib/" 755 | } 756 | }, 757 | "notification-url": "https://packagist.org/downloads/", 758 | "license": [ 759 | "Apache-2.0" 760 | ], 761 | "description": "A PHP client for Selenium WebDriver", 762 | "homepage": "https://github.com/facebook/php-webdriver", 763 | "keywords": [ 764 | "facebook", 765 | "php", 766 | "selenium", 767 | "webdriver" 768 | ], 769 | "time": "2017-04-28T14:54:49+00:00" 770 | }, 771 | { 772 | "name": "guzzlehttp/guzzle", 773 | "version": "6.3.0", 774 | "source": { 775 | "type": "git", 776 | "url": "https://github.com/guzzle/guzzle.git", 777 | "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699" 778 | }, 779 | "dist": { 780 | "type": "zip", 781 | "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699", 782 | "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699", 783 | "shasum": "" 784 | }, 785 | "require": { 786 | "guzzlehttp/promises": "^1.0", 787 | "guzzlehttp/psr7": "^1.4", 788 | "php": ">=5.5" 789 | }, 790 | "require-dev": { 791 | "ext-curl": "*", 792 | "phpunit/phpunit": "^4.0 || ^5.0", 793 | "psr/log": "^1.0" 794 | }, 795 | "suggest": { 796 | "psr/log": "Required for using the Log middleware" 797 | }, 798 | "type": "library", 799 | "extra": { 800 | "branch-alias": { 801 | "dev-master": "6.2-dev" 802 | } 803 | }, 804 | "autoload": { 805 | "files": [ 806 | "src/functions_include.php" 807 | ], 808 | "psr-4": { 809 | "GuzzleHttp\\": "src/" 810 | } 811 | }, 812 | "notification-url": "https://packagist.org/downloads/", 813 | "license": [ 814 | "MIT" 815 | ], 816 | "authors": [ 817 | { 818 | "name": "Michael Dowling", 819 | "email": "mtdowling@gmail.com", 820 | "homepage": "https://github.com/mtdowling" 821 | } 822 | ], 823 | "description": "Guzzle is a PHP HTTP client library", 824 | "homepage": "http://guzzlephp.org/", 825 | "keywords": [ 826 | "client", 827 | "curl", 828 | "framework", 829 | "http", 830 | "http client", 831 | "rest", 832 | "web service" 833 | ], 834 | "time": "2017-06-22T18:50:49+00:00" 835 | }, 836 | { 837 | "name": "guzzlehttp/promises", 838 | "version": "v1.3.1", 839 | "source": { 840 | "type": "git", 841 | "url": "https://github.com/guzzle/promises.git", 842 | "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" 843 | }, 844 | "dist": { 845 | "type": "zip", 846 | "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", 847 | "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", 848 | "shasum": "" 849 | }, 850 | "require": { 851 | "php": ">=5.5.0" 852 | }, 853 | "require-dev": { 854 | "phpunit/phpunit": "^4.0" 855 | }, 856 | "type": "library", 857 | "extra": { 858 | "branch-alias": { 859 | "dev-master": "1.4-dev" 860 | } 861 | }, 862 | "autoload": { 863 | "psr-4": { 864 | "GuzzleHttp\\Promise\\": "src/" 865 | }, 866 | "files": [ 867 | "src/functions_include.php" 868 | ] 869 | }, 870 | "notification-url": "https://packagist.org/downloads/", 871 | "license": [ 872 | "MIT" 873 | ], 874 | "authors": [ 875 | { 876 | "name": "Michael Dowling", 877 | "email": "mtdowling@gmail.com", 878 | "homepage": "https://github.com/mtdowling" 879 | } 880 | ], 881 | "description": "Guzzle promises library", 882 | "keywords": [ 883 | "promise" 884 | ], 885 | "time": "2016-12-20T10:07:11+00:00" 886 | }, 887 | { 888 | "name": "guzzlehttp/psr7", 889 | "version": "1.4.2", 890 | "source": { 891 | "type": "git", 892 | "url": "https://github.com/guzzle/psr7.git", 893 | "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" 894 | }, 895 | "dist": { 896 | "type": "zip", 897 | "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", 898 | "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", 899 | "shasum": "" 900 | }, 901 | "require": { 902 | "php": ">=5.4.0", 903 | "psr/http-message": "~1.0" 904 | }, 905 | "provide": { 906 | "psr/http-message-implementation": "1.0" 907 | }, 908 | "require-dev": { 909 | "phpunit/phpunit": "~4.0" 910 | }, 911 | "type": "library", 912 | "extra": { 913 | "branch-alias": { 914 | "dev-master": "1.4-dev" 915 | } 916 | }, 917 | "autoload": { 918 | "psr-4": { 919 | "GuzzleHttp\\Psr7\\": "src/" 920 | }, 921 | "files": [ 922 | "src/functions_include.php" 923 | ] 924 | }, 925 | "notification-url": "https://packagist.org/downloads/", 926 | "license": [ 927 | "MIT" 928 | ], 929 | "authors": [ 930 | { 931 | "name": "Michael Dowling", 932 | "email": "mtdowling@gmail.com", 933 | "homepage": "https://github.com/mtdowling" 934 | }, 935 | { 936 | "name": "Tobias Schultze", 937 | "homepage": "https://github.com/Tobion" 938 | } 939 | ], 940 | "description": "PSR-7 message implementation that also provides common utility methods", 941 | "keywords": [ 942 | "http", 943 | "message", 944 | "request", 945 | "response", 946 | "stream", 947 | "uri", 948 | "url" 949 | ], 950 | "time": "2017-03-20T17:10:46+00:00" 951 | }, 952 | { 953 | "name": "myclabs/deep-copy", 954 | "version": "1.6.1", 955 | "source": { 956 | "type": "git", 957 | "url": "https://github.com/myclabs/DeepCopy.git", 958 | "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102" 959 | }, 960 | "dist": { 961 | "type": "zip", 962 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/8e6e04167378abf1ddb4d3522d8755c5fd90d102", 963 | "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102", 964 | "shasum": "" 965 | }, 966 | "require": { 967 | "php": ">=5.4.0" 968 | }, 969 | "require-dev": { 970 | "doctrine/collections": "1.*", 971 | "phpunit/phpunit": "~4.1" 972 | }, 973 | "type": "library", 974 | "autoload": { 975 | "psr-4": { 976 | "DeepCopy\\": "src/DeepCopy/" 977 | } 978 | }, 979 | "notification-url": "https://packagist.org/downloads/", 980 | "license": [ 981 | "MIT" 982 | ], 983 | "description": "Create deep copies (clones) of your objects", 984 | "homepage": "https://github.com/myclabs/DeepCopy", 985 | "keywords": [ 986 | "clone", 987 | "copy", 988 | "duplicate", 989 | "object", 990 | "object graph" 991 | ], 992 | "time": "2017-04-12T18:52:22+00:00" 993 | }, 994 | { 995 | "name": "phar-io/manifest", 996 | "version": "1.0.1", 997 | "source": { 998 | "type": "git", 999 | "url": "https://github.com/phar-io/manifest.git", 1000 | "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" 1001 | }, 1002 | "dist": { 1003 | "type": "zip", 1004 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", 1005 | "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", 1006 | "shasum": "" 1007 | }, 1008 | "require": { 1009 | "ext-dom": "*", 1010 | "ext-phar": "*", 1011 | "phar-io/version": "^1.0.1", 1012 | "php": "^5.6 || ^7.0" 1013 | }, 1014 | "type": "library", 1015 | "extra": { 1016 | "branch-alias": { 1017 | "dev-master": "1.0.x-dev" 1018 | } 1019 | }, 1020 | "autoload": { 1021 | "classmap": [ 1022 | "src/" 1023 | ] 1024 | }, 1025 | "notification-url": "https://packagist.org/downloads/", 1026 | "license": [ 1027 | "BSD-3-Clause" 1028 | ], 1029 | "authors": [ 1030 | { 1031 | "name": "Arne Blankerts", 1032 | "email": "arne@blankerts.de", 1033 | "role": "Developer" 1034 | }, 1035 | { 1036 | "name": "Sebastian Heuer", 1037 | "email": "sebastian@phpeople.de", 1038 | "role": "Developer" 1039 | }, 1040 | { 1041 | "name": "Sebastian Bergmann", 1042 | "email": "sebastian@phpunit.de", 1043 | "role": "Developer" 1044 | } 1045 | ], 1046 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", 1047 | "time": "2017-03-05T18:14:27+00:00" 1048 | }, 1049 | { 1050 | "name": "phar-io/version", 1051 | "version": "1.0.1", 1052 | "source": { 1053 | "type": "git", 1054 | "url": "https://github.com/phar-io/version.git", 1055 | "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" 1056 | }, 1057 | "dist": { 1058 | "type": "zip", 1059 | "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", 1060 | "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", 1061 | "shasum": "" 1062 | }, 1063 | "require": { 1064 | "php": "^5.6 || ^7.0" 1065 | }, 1066 | "type": "library", 1067 | "autoload": { 1068 | "classmap": [ 1069 | "src/" 1070 | ] 1071 | }, 1072 | "notification-url": "https://packagist.org/downloads/", 1073 | "license": [ 1074 | "BSD-3-Clause" 1075 | ], 1076 | "authors": [ 1077 | { 1078 | "name": "Arne Blankerts", 1079 | "email": "arne@blankerts.de", 1080 | "role": "Developer" 1081 | }, 1082 | { 1083 | "name": "Sebastian Heuer", 1084 | "email": "sebastian@phpeople.de", 1085 | "role": "Developer" 1086 | }, 1087 | { 1088 | "name": "Sebastian Bergmann", 1089 | "email": "sebastian@phpunit.de", 1090 | "role": "Developer" 1091 | } 1092 | ], 1093 | "description": "Library for handling version information and constraints", 1094 | "time": "2017-03-05T17:38:23+00:00" 1095 | }, 1096 | { 1097 | "name": "phpdocumentor/reflection-common", 1098 | "version": "1.0", 1099 | "source": { 1100 | "type": "git", 1101 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 1102 | "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" 1103 | }, 1104 | "dist": { 1105 | "type": "zip", 1106 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", 1107 | "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", 1108 | "shasum": "" 1109 | }, 1110 | "require": { 1111 | "php": ">=5.5" 1112 | }, 1113 | "require-dev": { 1114 | "phpunit/phpunit": "^4.6" 1115 | }, 1116 | "type": "library", 1117 | "extra": { 1118 | "branch-alias": { 1119 | "dev-master": "1.0.x-dev" 1120 | } 1121 | }, 1122 | "autoload": { 1123 | "psr-4": { 1124 | "phpDocumentor\\Reflection\\": [ 1125 | "src" 1126 | ] 1127 | } 1128 | }, 1129 | "notification-url": "https://packagist.org/downloads/", 1130 | "license": [ 1131 | "MIT" 1132 | ], 1133 | "authors": [ 1134 | { 1135 | "name": "Jaap van Otterdijk", 1136 | "email": "opensource@ijaap.nl" 1137 | } 1138 | ], 1139 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 1140 | "homepage": "http://www.phpdoc.org", 1141 | "keywords": [ 1142 | "FQSEN", 1143 | "phpDocumentor", 1144 | "phpdoc", 1145 | "reflection", 1146 | "static analysis" 1147 | ], 1148 | "time": "2015-12-27T11:43:31+00:00" 1149 | }, 1150 | { 1151 | "name": "phpdocumentor/reflection-docblock", 1152 | "version": "3.1.1", 1153 | "source": { 1154 | "type": "git", 1155 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 1156 | "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" 1157 | }, 1158 | "dist": { 1159 | "type": "zip", 1160 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", 1161 | "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", 1162 | "shasum": "" 1163 | }, 1164 | "require": { 1165 | "php": ">=5.5", 1166 | "phpdocumentor/reflection-common": "^1.0@dev", 1167 | "phpdocumentor/type-resolver": "^0.2.0", 1168 | "webmozart/assert": "^1.0" 1169 | }, 1170 | "require-dev": { 1171 | "mockery/mockery": "^0.9.4", 1172 | "phpunit/phpunit": "^4.4" 1173 | }, 1174 | "type": "library", 1175 | "autoload": { 1176 | "psr-4": { 1177 | "phpDocumentor\\Reflection\\": [ 1178 | "src/" 1179 | ] 1180 | } 1181 | }, 1182 | "notification-url": "https://packagist.org/downloads/", 1183 | "license": [ 1184 | "MIT" 1185 | ], 1186 | "authors": [ 1187 | { 1188 | "name": "Mike van Riel", 1189 | "email": "me@mikevanriel.com" 1190 | } 1191 | ], 1192 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 1193 | "time": "2016-09-30T07:12:33+00:00" 1194 | }, 1195 | { 1196 | "name": "phpdocumentor/type-resolver", 1197 | "version": "0.2.1", 1198 | "source": { 1199 | "type": "git", 1200 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 1201 | "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb" 1202 | }, 1203 | "dist": { 1204 | "type": "zip", 1205 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", 1206 | "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", 1207 | "shasum": "" 1208 | }, 1209 | "require": { 1210 | "php": ">=5.5", 1211 | "phpdocumentor/reflection-common": "^1.0" 1212 | }, 1213 | "require-dev": { 1214 | "mockery/mockery": "^0.9.4", 1215 | "phpunit/phpunit": "^5.2||^4.8.24" 1216 | }, 1217 | "type": "library", 1218 | "extra": { 1219 | "branch-alias": { 1220 | "dev-master": "1.0.x-dev" 1221 | } 1222 | }, 1223 | "autoload": { 1224 | "psr-4": { 1225 | "phpDocumentor\\Reflection\\": [ 1226 | "src/" 1227 | ] 1228 | } 1229 | }, 1230 | "notification-url": "https://packagist.org/downloads/", 1231 | "license": [ 1232 | "MIT" 1233 | ], 1234 | "authors": [ 1235 | { 1236 | "name": "Mike van Riel", 1237 | "email": "me@mikevanriel.com" 1238 | } 1239 | ], 1240 | "time": "2016-11-25T06:54:22+00:00" 1241 | }, 1242 | { 1243 | "name": "phpspec/prophecy", 1244 | "version": "v1.7.0", 1245 | "source": { 1246 | "type": "git", 1247 | "url": "https://github.com/phpspec/prophecy.git", 1248 | "reference": "93d39f1f7f9326d746203c7c056f300f7f126073" 1249 | }, 1250 | "dist": { 1251 | "type": "zip", 1252 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073", 1253 | "reference": "93d39f1f7f9326d746203c7c056f300f7f126073", 1254 | "shasum": "" 1255 | }, 1256 | "require": { 1257 | "doctrine/instantiator": "^1.0.2", 1258 | "php": "^5.3|^7.0", 1259 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", 1260 | "sebastian/comparator": "^1.1|^2.0", 1261 | "sebastian/recursion-context": "^1.0|^2.0|^3.0" 1262 | }, 1263 | "require-dev": { 1264 | "phpspec/phpspec": "^2.5|^3.2", 1265 | "phpunit/phpunit": "^4.8 || ^5.6.5" 1266 | }, 1267 | "type": "library", 1268 | "extra": { 1269 | "branch-alias": { 1270 | "dev-master": "1.6.x-dev" 1271 | } 1272 | }, 1273 | "autoload": { 1274 | "psr-0": { 1275 | "Prophecy\\": "src/" 1276 | } 1277 | }, 1278 | "notification-url": "https://packagist.org/downloads/", 1279 | "license": [ 1280 | "MIT" 1281 | ], 1282 | "authors": [ 1283 | { 1284 | "name": "Konstantin Kudryashov", 1285 | "email": "ever.zet@gmail.com", 1286 | "homepage": "http://everzet.com" 1287 | }, 1288 | { 1289 | "name": "Marcello Duarte", 1290 | "email": "marcello.duarte@gmail.com" 1291 | } 1292 | ], 1293 | "description": "Highly opinionated mocking framework for PHP 5.3+", 1294 | "homepage": "https://github.com/phpspec/prophecy", 1295 | "keywords": [ 1296 | "Double", 1297 | "Dummy", 1298 | "fake", 1299 | "mock", 1300 | "spy", 1301 | "stub" 1302 | ], 1303 | "time": "2017-03-02T20:05:34+00:00" 1304 | }, 1305 | { 1306 | "name": "phpunit/php-code-coverage", 1307 | "version": "5.2.1", 1308 | "source": { 1309 | "type": "git", 1310 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 1311 | "reference": "dc421f9ca5082a0c0cb04afb171c765f79add85b" 1312 | }, 1313 | "dist": { 1314 | "type": "zip", 1315 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/dc421f9ca5082a0c0cb04afb171c765f79add85b", 1316 | "reference": "dc421f9ca5082a0c0cb04afb171c765f79add85b", 1317 | "shasum": "" 1318 | }, 1319 | "require": { 1320 | "ext-dom": "*", 1321 | "ext-xmlwriter": "*", 1322 | "php": "^7.0", 1323 | "phpunit/php-file-iterator": "^1.3", 1324 | "phpunit/php-text-template": "^1.2", 1325 | "phpunit/php-token-stream": "^1.4.11 || ^2.0", 1326 | "sebastian/code-unit-reverse-lookup": "^1.0", 1327 | "sebastian/environment": "^3.0", 1328 | "sebastian/version": "^2.0", 1329 | "theseer/tokenizer": "^1.1" 1330 | }, 1331 | "require-dev": { 1332 | "ext-xdebug": "^2.5", 1333 | "phpunit/phpunit": "^6.0" 1334 | }, 1335 | "suggest": { 1336 | "ext-xdebug": "^2.5.3" 1337 | }, 1338 | "type": "library", 1339 | "extra": { 1340 | "branch-alias": { 1341 | "dev-master": "5.2.x-dev" 1342 | } 1343 | }, 1344 | "autoload": { 1345 | "classmap": [ 1346 | "src/" 1347 | ] 1348 | }, 1349 | "notification-url": "https://packagist.org/downloads/", 1350 | "license": [ 1351 | "BSD-3-Clause" 1352 | ], 1353 | "authors": [ 1354 | { 1355 | "name": "Sebastian Bergmann", 1356 | "email": "sb@sebastian-bergmann.de", 1357 | "role": "lead" 1358 | } 1359 | ], 1360 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 1361 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 1362 | "keywords": [ 1363 | "coverage", 1364 | "testing", 1365 | "xunit" 1366 | ], 1367 | "time": "2017-04-21T08:03:57+00:00" 1368 | }, 1369 | { 1370 | "name": "phpunit/php-file-iterator", 1371 | "version": "1.4.2", 1372 | "source": { 1373 | "type": "git", 1374 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 1375 | "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" 1376 | }, 1377 | "dist": { 1378 | "type": "zip", 1379 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", 1380 | "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", 1381 | "shasum": "" 1382 | }, 1383 | "require": { 1384 | "php": ">=5.3.3" 1385 | }, 1386 | "type": "library", 1387 | "extra": { 1388 | "branch-alias": { 1389 | "dev-master": "1.4.x-dev" 1390 | } 1391 | }, 1392 | "autoload": { 1393 | "classmap": [ 1394 | "src/" 1395 | ] 1396 | }, 1397 | "notification-url": "https://packagist.org/downloads/", 1398 | "license": [ 1399 | "BSD-3-Clause" 1400 | ], 1401 | "authors": [ 1402 | { 1403 | "name": "Sebastian Bergmann", 1404 | "email": "sb@sebastian-bergmann.de", 1405 | "role": "lead" 1406 | } 1407 | ], 1408 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 1409 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 1410 | "keywords": [ 1411 | "filesystem", 1412 | "iterator" 1413 | ], 1414 | "time": "2016-10-03T07:40:28+00:00" 1415 | }, 1416 | { 1417 | "name": "phpunit/php-text-template", 1418 | "version": "1.2.1", 1419 | "source": { 1420 | "type": "git", 1421 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 1422 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 1423 | }, 1424 | "dist": { 1425 | "type": "zip", 1426 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 1427 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 1428 | "shasum": "" 1429 | }, 1430 | "require": { 1431 | "php": ">=5.3.3" 1432 | }, 1433 | "type": "library", 1434 | "autoload": { 1435 | "classmap": [ 1436 | "src/" 1437 | ] 1438 | }, 1439 | "notification-url": "https://packagist.org/downloads/", 1440 | "license": [ 1441 | "BSD-3-Clause" 1442 | ], 1443 | "authors": [ 1444 | { 1445 | "name": "Sebastian Bergmann", 1446 | "email": "sebastian@phpunit.de", 1447 | "role": "lead" 1448 | } 1449 | ], 1450 | "description": "Simple template engine.", 1451 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 1452 | "keywords": [ 1453 | "template" 1454 | ], 1455 | "time": "2015-06-21T13:50:34+00:00" 1456 | }, 1457 | { 1458 | "name": "phpunit/php-timer", 1459 | "version": "1.0.9", 1460 | "source": { 1461 | "type": "git", 1462 | "url": "https://github.com/sebastianbergmann/php-timer.git", 1463 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" 1464 | }, 1465 | "dist": { 1466 | "type": "zip", 1467 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", 1468 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", 1469 | "shasum": "" 1470 | }, 1471 | "require": { 1472 | "php": "^5.3.3 || ^7.0" 1473 | }, 1474 | "require-dev": { 1475 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" 1476 | }, 1477 | "type": "library", 1478 | "extra": { 1479 | "branch-alias": { 1480 | "dev-master": "1.0-dev" 1481 | } 1482 | }, 1483 | "autoload": { 1484 | "classmap": [ 1485 | "src/" 1486 | ] 1487 | }, 1488 | "notification-url": "https://packagist.org/downloads/", 1489 | "license": [ 1490 | "BSD-3-Clause" 1491 | ], 1492 | "authors": [ 1493 | { 1494 | "name": "Sebastian Bergmann", 1495 | "email": "sb@sebastian-bergmann.de", 1496 | "role": "lead" 1497 | } 1498 | ], 1499 | "description": "Utility class for timing", 1500 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 1501 | "keywords": [ 1502 | "timer" 1503 | ], 1504 | "time": "2017-02-26T11:10:40+00:00" 1505 | }, 1506 | { 1507 | "name": "phpunit/php-token-stream", 1508 | "version": "1.4.11", 1509 | "source": { 1510 | "type": "git", 1511 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 1512 | "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7" 1513 | }, 1514 | "dist": { 1515 | "type": "zip", 1516 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7", 1517 | "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7", 1518 | "shasum": "" 1519 | }, 1520 | "require": { 1521 | "ext-tokenizer": "*", 1522 | "php": ">=5.3.3" 1523 | }, 1524 | "require-dev": { 1525 | "phpunit/phpunit": "~4.2" 1526 | }, 1527 | "type": "library", 1528 | "extra": { 1529 | "branch-alias": { 1530 | "dev-master": "1.4-dev" 1531 | } 1532 | }, 1533 | "autoload": { 1534 | "classmap": [ 1535 | "src/" 1536 | ] 1537 | }, 1538 | "notification-url": "https://packagist.org/downloads/", 1539 | "license": [ 1540 | "BSD-3-Clause" 1541 | ], 1542 | "authors": [ 1543 | { 1544 | "name": "Sebastian Bergmann", 1545 | "email": "sebastian@phpunit.de" 1546 | } 1547 | ], 1548 | "description": "Wrapper around PHP's tokenizer extension.", 1549 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 1550 | "keywords": [ 1551 | "tokenizer" 1552 | ], 1553 | "time": "2017-02-27T10:12:30+00:00" 1554 | }, 1555 | { 1556 | "name": "phpunit/phpunit", 1557 | "version": "6.2.3", 1558 | "source": { 1559 | "type": "git", 1560 | "url": "https://github.com/sebastianbergmann/phpunit.git", 1561 | "reference": "fa5711d0559fc4b64deba0702be52d41434cbcb7" 1562 | }, 1563 | "dist": { 1564 | "type": "zip", 1565 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fa5711d0559fc4b64deba0702be52d41434cbcb7", 1566 | "reference": "fa5711d0559fc4b64deba0702be52d41434cbcb7", 1567 | "shasum": "" 1568 | }, 1569 | "require": { 1570 | "ext-dom": "*", 1571 | "ext-json": "*", 1572 | "ext-libxml": "*", 1573 | "ext-mbstring": "*", 1574 | "ext-xml": "*", 1575 | "myclabs/deep-copy": "^1.3", 1576 | "phar-io/manifest": "^1.0.1", 1577 | "phar-io/version": "^1.0", 1578 | "php": "^7.0", 1579 | "phpspec/prophecy": "^1.7", 1580 | "phpunit/php-code-coverage": "^5.2", 1581 | "phpunit/php-file-iterator": "^1.4", 1582 | "phpunit/php-text-template": "^1.2", 1583 | "phpunit/php-timer": "^1.0.6", 1584 | "phpunit/phpunit-mock-objects": "^4.0", 1585 | "sebastian/comparator": "^2.0", 1586 | "sebastian/diff": "^1.4.3 || ^2.0", 1587 | "sebastian/environment": "^3.0.2", 1588 | "sebastian/exporter": "^3.1", 1589 | "sebastian/global-state": "^1.1 || ^2.0", 1590 | "sebastian/object-enumerator": "^3.0.2", 1591 | "sebastian/resource-operations": "^1.0", 1592 | "sebastian/version": "^2.0" 1593 | }, 1594 | "conflict": { 1595 | "phpdocumentor/reflection-docblock": "3.0.2", 1596 | "phpunit/dbunit": "<3.0" 1597 | }, 1598 | "require-dev": { 1599 | "ext-pdo": "*" 1600 | }, 1601 | "suggest": { 1602 | "ext-xdebug": "*", 1603 | "phpunit/php-invoker": "^1.1" 1604 | }, 1605 | "bin": [ 1606 | "phpunit" 1607 | ], 1608 | "type": "library", 1609 | "extra": { 1610 | "branch-alias": { 1611 | "dev-master": "6.2.x-dev" 1612 | } 1613 | }, 1614 | "autoload": { 1615 | "classmap": [ 1616 | "src/" 1617 | ] 1618 | }, 1619 | "notification-url": "https://packagist.org/downloads/", 1620 | "license": [ 1621 | "BSD-3-Clause" 1622 | ], 1623 | "authors": [ 1624 | { 1625 | "name": "Sebastian Bergmann", 1626 | "email": "sebastian@phpunit.de", 1627 | "role": "lead" 1628 | } 1629 | ], 1630 | "description": "The PHP Unit Testing framework.", 1631 | "homepage": "https://phpunit.de/", 1632 | "keywords": [ 1633 | "phpunit", 1634 | "testing", 1635 | "xunit" 1636 | ], 1637 | "time": "2017-07-03T15:54:24+00:00" 1638 | }, 1639 | { 1640 | "name": "phpunit/phpunit-mock-objects", 1641 | "version": "4.0.2", 1642 | "source": { 1643 | "type": "git", 1644 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 1645 | "reference": "d8833b396dce9162bb2eb5d59aee5a3ab3cfa5b4" 1646 | }, 1647 | "dist": { 1648 | "type": "zip", 1649 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/d8833b396dce9162bb2eb5d59aee5a3ab3cfa5b4", 1650 | "reference": "d8833b396dce9162bb2eb5d59aee5a3ab3cfa5b4", 1651 | "shasum": "" 1652 | }, 1653 | "require": { 1654 | "doctrine/instantiator": "^1.0.2", 1655 | "php": "^7.0", 1656 | "phpunit/php-text-template": "^1.2", 1657 | "sebastian/exporter": "^3.0" 1658 | }, 1659 | "conflict": { 1660 | "phpunit/phpunit": "<6.0" 1661 | }, 1662 | "require-dev": { 1663 | "phpunit/phpunit": "^6.0" 1664 | }, 1665 | "suggest": { 1666 | "ext-soap": "*" 1667 | }, 1668 | "type": "library", 1669 | "extra": { 1670 | "branch-alias": { 1671 | "dev-master": "4.0.x-dev" 1672 | } 1673 | }, 1674 | "autoload": { 1675 | "classmap": [ 1676 | "src/" 1677 | ] 1678 | }, 1679 | "notification-url": "https://packagist.org/downloads/", 1680 | "license": [ 1681 | "BSD-3-Clause" 1682 | ], 1683 | "authors": [ 1684 | { 1685 | "name": "Sebastian Bergmann", 1686 | "email": "sb@sebastian-bergmann.de", 1687 | "role": "lead" 1688 | } 1689 | ], 1690 | "description": "Mock Object library for PHPUnit", 1691 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 1692 | "keywords": [ 1693 | "mock", 1694 | "xunit" 1695 | ], 1696 | "time": "2017-06-30T08:15:21+00:00" 1697 | }, 1698 | { 1699 | "name": "psr/http-message", 1700 | "version": "1.0.1", 1701 | "source": { 1702 | "type": "git", 1703 | "url": "https://github.com/php-fig/http-message.git", 1704 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" 1705 | }, 1706 | "dist": { 1707 | "type": "zip", 1708 | "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", 1709 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", 1710 | "shasum": "" 1711 | }, 1712 | "require": { 1713 | "php": ">=5.3.0" 1714 | }, 1715 | "type": "library", 1716 | "extra": { 1717 | "branch-alias": { 1718 | "dev-master": "1.0.x-dev" 1719 | } 1720 | }, 1721 | "autoload": { 1722 | "psr-4": { 1723 | "Psr\\Http\\Message\\": "src/" 1724 | } 1725 | }, 1726 | "notification-url": "https://packagist.org/downloads/", 1727 | "license": [ 1728 | "MIT" 1729 | ], 1730 | "authors": [ 1731 | { 1732 | "name": "PHP-FIG", 1733 | "homepage": "http://www.php-fig.org/" 1734 | } 1735 | ], 1736 | "description": "Common interface for HTTP messages", 1737 | "homepage": "https://github.com/php-fig/http-message", 1738 | "keywords": [ 1739 | "http", 1740 | "http-message", 1741 | "psr", 1742 | "psr-7", 1743 | "request", 1744 | "response" 1745 | ], 1746 | "time": "2016-08-06T14:39:51+00:00" 1747 | }, 1748 | { 1749 | "name": "psr/log", 1750 | "version": "1.0.2", 1751 | "source": { 1752 | "type": "git", 1753 | "url": "https://github.com/php-fig/log.git", 1754 | "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" 1755 | }, 1756 | "dist": { 1757 | "type": "zip", 1758 | "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", 1759 | "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", 1760 | "shasum": "" 1761 | }, 1762 | "require": { 1763 | "php": ">=5.3.0" 1764 | }, 1765 | "type": "library", 1766 | "extra": { 1767 | "branch-alias": { 1768 | "dev-master": "1.0.x-dev" 1769 | } 1770 | }, 1771 | "autoload": { 1772 | "psr-4": { 1773 | "Psr\\Log\\": "Psr/Log/" 1774 | } 1775 | }, 1776 | "notification-url": "https://packagist.org/downloads/", 1777 | "license": [ 1778 | "MIT" 1779 | ], 1780 | "authors": [ 1781 | { 1782 | "name": "PHP-FIG", 1783 | "homepage": "http://www.php-fig.org/" 1784 | } 1785 | ], 1786 | "description": "Common interface for logging libraries", 1787 | "homepage": "https://github.com/php-fig/log", 1788 | "keywords": [ 1789 | "log", 1790 | "psr", 1791 | "psr-3" 1792 | ], 1793 | "time": "2016-10-10T12:19:37+00:00" 1794 | }, 1795 | { 1796 | "name": "sebastian/code-unit-reverse-lookup", 1797 | "version": "1.0.1", 1798 | "source": { 1799 | "type": "git", 1800 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 1801 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" 1802 | }, 1803 | "dist": { 1804 | "type": "zip", 1805 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 1806 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 1807 | "shasum": "" 1808 | }, 1809 | "require": { 1810 | "php": "^5.6 || ^7.0" 1811 | }, 1812 | "require-dev": { 1813 | "phpunit/phpunit": "^5.7 || ^6.0" 1814 | }, 1815 | "type": "library", 1816 | "extra": { 1817 | "branch-alias": { 1818 | "dev-master": "1.0.x-dev" 1819 | } 1820 | }, 1821 | "autoload": { 1822 | "classmap": [ 1823 | "src/" 1824 | ] 1825 | }, 1826 | "notification-url": "https://packagist.org/downloads/", 1827 | "license": [ 1828 | "BSD-3-Clause" 1829 | ], 1830 | "authors": [ 1831 | { 1832 | "name": "Sebastian Bergmann", 1833 | "email": "sebastian@phpunit.de" 1834 | } 1835 | ], 1836 | "description": "Looks up which function or method a line of code belongs to", 1837 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 1838 | "time": "2017-03-04T06:30:41+00:00" 1839 | }, 1840 | { 1841 | "name": "sebastian/comparator", 1842 | "version": "2.0.0", 1843 | "source": { 1844 | "type": "git", 1845 | "url": "https://github.com/sebastianbergmann/comparator.git", 1846 | "reference": "20f84f468cb67efee293246e6a09619b891f55f0" 1847 | }, 1848 | "dist": { 1849 | "type": "zip", 1850 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/20f84f468cb67efee293246e6a09619b891f55f0", 1851 | "reference": "20f84f468cb67efee293246e6a09619b891f55f0", 1852 | "shasum": "" 1853 | }, 1854 | "require": { 1855 | "php": "^7.0", 1856 | "sebastian/diff": "^1.2", 1857 | "sebastian/exporter": "^3.0" 1858 | }, 1859 | "require-dev": { 1860 | "phpunit/phpunit": "^6.0" 1861 | }, 1862 | "type": "library", 1863 | "extra": { 1864 | "branch-alias": { 1865 | "dev-master": "2.0.x-dev" 1866 | } 1867 | }, 1868 | "autoload": { 1869 | "classmap": [ 1870 | "src/" 1871 | ] 1872 | }, 1873 | "notification-url": "https://packagist.org/downloads/", 1874 | "license": [ 1875 | "BSD-3-Clause" 1876 | ], 1877 | "authors": [ 1878 | { 1879 | "name": "Jeff Welch", 1880 | "email": "whatthejeff@gmail.com" 1881 | }, 1882 | { 1883 | "name": "Volker Dusch", 1884 | "email": "github@wallbash.com" 1885 | }, 1886 | { 1887 | "name": "Bernhard Schussek", 1888 | "email": "bschussek@2bepublished.at" 1889 | }, 1890 | { 1891 | "name": "Sebastian Bergmann", 1892 | "email": "sebastian@phpunit.de" 1893 | } 1894 | ], 1895 | "description": "Provides the functionality to compare PHP values for equality", 1896 | "homepage": "http://www.github.com/sebastianbergmann/comparator", 1897 | "keywords": [ 1898 | "comparator", 1899 | "compare", 1900 | "equality" 1901 | ], 1902 | "time": "2017-03-03T06:26:08+00:00" 1903 | }, 1904 | { 1905 | "name": "sebastian/diff", 1906 | "version": "1.4.3", 1907 | "source": { 1908 | "type": "git", 1909 | "url": "https://github.com/sebastianbergmann/diff.git", 1910 | "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" 1911 | }, 1912 | "dist": { 1913 | "type": "zip", 1914 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", 1915 | "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", 1916 | "shasum": "" 1917 | }, 1918 | "require": { 1919 | "php": "^5.3.3 || ^7.0" 1920 | }, 1921 | "require-dev": { 1922 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" 1923 | }, 1924 | "type": "library", 1925 | "extra": { 1926 | "branch-alias": { 1927 | "dev-master": "1.4-dev" 1928 | } 1929 | }, 1930 | "autoload": { 1931 | "classmap": [ 1932 | "src/" 1933 | ] 1934 | }, 1935 | "notification-url": "https://packagist.org/downloads/", 1936 | "license": [ 1937 | "BSD-3-Clause" 1938 | ], 1939 | "authors": [ 1940 | { 1941 | "name": "Kore Nordmann", 1942 | "email": "mail@kore-nordmann.de" 1943 | }, 1944 | { 1945 | "name": "Sebastian Bergmann", 1946 | "email": "sebastian@phpunit.de" 1947 | } 1948 | ], 1949 | "description": "Diff implementation", 1950 | "homepage": "https://github.com/sebastianbergmann/diff", 1951 | "keywords": [ 1952 | "diff" 1953 | ], 1954 | "time": "2017-05-22T07:24:03+00:00" 1955 | }, 1956 | { 1957 | "name": "sebastian/environment", 1958 | "version": "3.1.0", 1959 | "source": { 1960 | "type": "git", 1961 | "url": "https://github.com/sebastianbergmann/environment.git", 1962 | "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" 1963 | }, 1964 | "dist": { 1965 | "type": "zip", 1966 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", 1967 | "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", 1968 | "shasum": "" 1969 | }, 1970 | "require": { 1971 | "php": "^7.0" 1972 | }, 1973 | "require-dev": { 1974 | "phpunit/phpunit": "^6.1" 1975 | }, 1976 | "type": "library", 1977 | "extra": { 1978 | "branch-alias": { 1979 | "dev-master": "3.1.x-dev" 1980 | } 1981 | }, 1982 | "autoload": { 1983 | "classmap": [ 1984 | "src/" 1985 | ] 1986 | }, 1987 | "notification-url": "https://packagist.org/downloads/", 1988 | "license": [ 1989 | "BSD-3-Clause" 1990 | ], 1991 | "authors": [ 1992 | { 1993 | "name": "Sebastian Bergmann", 1994 | "email": "sebastian@phpunit.de" 1995 | } 1996 | ], 1997 | "description": "Provides functionality to handle HHVM/PHP environments", 1998 | "homepage": "http://www.github.com/sebastianbergmann/environment", 1999 | "keywords": [ 2000 | "Xdebug", 2001 | "environment", 2002 | "hhvm" 2003 | ], 2004 | "time": "2017-07-01T08:51:00+00:00" 2005 | }, 2006 | { 2007 | "name": "sebastian/exporter", 2008 | "version": "3.1.0", 2009 | "source": { 2010 | "type": "git", 2011 | "url": "https://github.com/sebastianbergmann/exporter.git", 2012 | "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" 2013 | }, 2014 | "dist": { 2015 | "type": "zip", 2016 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", 2017 | "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", 2018 | "shasum": "" 2019 | }, 2020 | "require": { 2021 | "php": "^7.0", 2022 | "sebastian/recursion-context": "^3.0" 2023 | }, 2024 | "require-dev": { 2025 | "ext-mbstring": "*", 2026 | "phpunit/phpunit": "^6.0" 2027 | }, 2028 | "type": "library", 2029 | "extra": { 2030 | "branch-alias": { 2031 | "dev-master": "3.1.x-dev" 2032 | } 2033 | }, 2034 | "autoload": { 2035 | "classmap": [ 2036 | "src/" 2037 | ] 2038 | }, 2039 | "notification-url": "https://packagist.org/downloads/", 2040 | "license": [ 2041 | "BSD-3-Clause" 2042 | ], 2043 | "authors": [ 2044 | { 2045 | "name": "Jeff Welch", 2046 | "email": "whatthejeff@gmail.com" 2047 | }, 2048 | { 2049 | "name": "Volker Dusch", 2050 | "email": "github@wallbash.com" 2051 | }, 2052 | { 2053 | "name": "Bernhard Schussek", 2054 | "email": "bschussek@2bepublished.at" 2055 | }, 2056 | { 2057 | "name": "Sebastian Bergmann", 2058 | "email": "sebastian@phpunit.de" 2059 | }, 2060 | { 2061 | "name": "Adam Harvey", 2062 | "email": "aharvey@php.net" 2063 | } 2064 | ], 2065 | "description": "Provides the functionality to export PHP variables for visualization", 2066 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 2067 | "keywords": [ 2068 | "export", 2069 | "exporter" 2070 | ], 2071 | "time": "2017-04-03T13:19:02+00:00" 2072 | }, 2073 | { 2074 | "name": "sebastian/global-state", 2075 | "version": "2.0.0", 2076 | "source": { 2077 | "type": "git", 2078 | "url": "https://github.com/sebastianbergmann/global-state.git", 2079 | "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" 2080 | }, 2081 | "dist": { 2082 | "type": "zip", 2083 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", 2084 | "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", 2085 | "shasum": "" 2086 | }, 2087 | "require": { 2088 | "php": "^7.0" 2089 | }, 2090 | "require-dev": { 2091 | "phpunit/phpunit": "^6.0" 2092 | }, 2093 | "suggest": { 2094 | "ext-uopz": "*" 2095 | }, 2096 | "type": "library", 2097 | "extra": { 2098 | "branch-alias": { 2099 | "dev-master": "2.0-dev" 2100 | } 2101 | }, 2102 | "autoload": { 2103 | "classmap": [ 2104 | "src/" 2105 | ] 2106 | }, 2107 | "notification-url": "https://packagist.org/downloads/", 2108 | "license": [ 2109 | "BSD-3-Clause" 2110 | ], 2111 | "authors": [ 2112 | { 2113 | "name": "Sebastian Bergmann", 2114 | "email": "sebastian@phpunit.de" 2115 | } 2116 | ], 2117 | "description": "Snapshotting of global state", 2118 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 2119 | "keywords": [ 2120 | "global state" 2121 | ], 2122 | "time": "2017-04-27T15:39:26+00:00" 2123 | }, 2124 | { 2125 | "name": "sebastian/object-enumerator", 2126 | "version": "3.0.2", 2127 | "source": { 2128 | "type": "git", 2129 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 2130 | "reference": "31dd3379d16446c5d86dec32ab1ad1f378581ad8" 2131 | }, 2132 | "dist": { 2133 | "type": "zip", 2134 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/31dd3379d16446c5d86dec32ab1ad1f378581ad8", 2135 | "reference": "31dd3379d16446c5d86dec32ab1ad1f378581ad8", 2136 | "shasum": "" 2137 | }, 2138 | "require": { 2139 | "php": "^7.0", 2140 | "sebastian/object-reflector": "^1.0", 2141 | "sebastian/recursion-context": "^3.0" 2142 | }, 2143 | "require-dev": { 2144 | "phpunit/phpunit": "^6.0" 2145 | }, 2146 | "type": "library", 2147 | "extra": { 2148 | "branch-alias": { 2149 | "dev-master": "3.0.x-dev" 2150 | } 2151 | }, 2152 | "autoload": { 2153 | "classmap": [ 2154 | "src/" 2155 | ] 2156 | }, 2157 | "notification-url": "https://packagist.org/downloads/", 2158 | "license": [ 2159 | "BSD-3-Clause" 2160 | ], 2161 | "authors": [ 2162 | { 2163 | "name": "Sebastian Bergmann", 2164 | "email": "sebastian@phpunit.de" 2165 | } 2166 | ], 2167 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 2168 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 2169 | "time": "2017-03-12T15:17:29+00:00" 2170 | }, 2171 | { 2172 | "name": "sebastian/object-reflector", 2173 | "version": "1.1.1", 2174 | "source": { 2175 | "type": "git", 2176 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 2177 | "reference": "773f97c67f28de00d397be301821b06708fca0be" 2178 | }, 2179 | "dist": { 2180 | "type": "zip", 2181 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", 2182 | "reference": "773f97c67f28de00d397be301821b06708fca0be", 2183 | "shasum": "" 2184 | }, 2185 | "require": { 2186 | "php": "^7.0" 2187 | }, 2188 | "require-dev": { 2189 | "phpunit/phpunit": "^6.0" 2190 | }, 2191 | "type": "library", 2192 | "extra": { 2193 | "branch-alias": { 2194 | "dev-master": "1.1-dev" 2195 | } 2196 | }, 2197 | "autoload": { 2198 | "classmap": [ 2199 | "src/" 2200 | ] 2201 | }, 2202 | "notification-url": "https://packagist.org/downloads/", 2203 | "license": [ 2204 | "BSD-3-Clause" 2205 | ], 2206 | "authors": [ 2207 | { 2208 | "name": "Sebastian Bergmann", 2209 | "email": "sebastian@phpunit.de" 2210 | } 2211 | ], 2212 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 2213 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 2214 | "time": "2017-03-29T09:07:27+00:00" 2215 | }, 2216 | { 2217 | "name": "sebastian/recursion-context", 2218 | "version": "3.0.0", 2219 | "source": { 2220 | "type": "git", 2221 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 2222 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" 2223 | }, 2224 | "dist": { 2225 | "type": "zip", 2226 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", 2227 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", 2228 | "shasum": "" 2229 | }, 2230 | "require": { 2231 | "php": "^7.0" 2232 | }, 2233 | "require-dev": { 2234 | "phpunit/phpunit": "^6.0" 2235 | }, 2236 | "type": "library", 2237 | "extra": { 2238 | "branch-alias": { 2239 | "dev-master": "3.0.x-dev" 2240 | } 2241 | }, 2242 | "autoload": { 2243 | "classmap": [ 2244 | "src/" 2245 | ] 2246 | }, 2247 | "notification-url": "https://packagist.org/downloads/", 2248 | "license": [ 2249 | "BSD-3-Clause" 2250 | ], 2251 | "authors": [ 2252 | { 2253 | "name": "Jeff Welch", 2254 | "email": "whatthejeff@gmail.com" 2255 | }, 2256 | { 2257 | "name": "Sebastian Bergmann", 2258 | "email": "sebastian@phpunit.de" 2259 | }, 2260 | { 2261 | "name": "Adam Harvey", 2262 | "email": "aharvey@php.net" 2263 | } 2264 | ], 2265 | "description": "Provides functionality to recursively process PHP variables", 2266 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 2267 | "time": "2017-03-03T06:23:57+00:00" 2268 | }, 2269 | { 2270 | "name": "sebastian/resource-operations", 2271 | "version": "1.0.0", 2272 | "source": { 2273 | "type": "git", 2274 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 2275 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" 2276 | }, 2277 | "dist": { 2278 | "type": "zip", 2279 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 2280 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 2281 | "shasum": "" 2282 | }, 2283 | "require": { 2284 | "php": ">=5.6.0" 2285 | }, 2286 | "type": "library", 2287 | "extra": { 2288 | "branch-alias": { 2289 | "dev-master": "1.0.x-dev" 2290 | } 2291 | }, 2292 | "autoload": { 2293 | "classmap": [ 2294 | "src/" 2295 | ] 2296 | }, 2297 | "notification-url": "https://packagist.org/downloads/", 2298 | "license": [ 2299 | "BSD-3-Clause" 2300 | ], 2301 | "authors": [ 2302 | { 2303 | "name": "Sebastian Bergmann", 2304 | "email": "sebastian@phpunit.de" 2305 | } 2306 | ], 2307 | "description": "Provides a list of PHP built-in functions that operate on resources", 2308 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 2309 | "time": "2015-07-28T20:34:47+00:00" 2310 | }, 2311 | { 2312 | "name": "sebastian/version", 2313 | "version": "2.0.1", 2314 | "source": { 2315 | "type": "git", 2316 | "url": "https://github.com/sebastianbergmann/version.git", 2317 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" 2318 | }, 2319 | "dist": { 2320 | "type": "zip", 2321 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", 2322 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", 2323 | "shasum": "" 2324 | }, 2325 | "require": { 2326 | "php": ">=5.6" 2327 | }, 2328 | "type": "library", 2329 | "extra": { 2330 | "branch-alias": { 2331 | "dev-master": "2.0.x-dev" 2332 | } 2333 | }, 2334 | "autoload": { 2335 | "classmap": [ 2336 | "src/" 2337 | ] 2338 | }, 2339 | "notification-url": "https://packagist.org/downloads/", 2340 | "license": [ 2341 | "BSD-3-Clause" 2342 | ], 2343 | "authors": [ 2344 | { 2345 | "name": "Sebastian Bergmann", 2346 | "email": "sebastian@phpunit.de", 2347 | "role": "lead" 2348 | } 2349 | ], 2350 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 2351 | "homepage": "https://github.com/sebastianbergmann/version", 2352 | "time": "2016-10-03T07:35:21+00:00" 2353 | }, 2354 | { 2355 | "name": "stecman/symfony-console-completion", 2356 | "version": "0.7.0", 2357 | "source": { 2358 | "type": "git", 2359 | "url": "https://github.com/stecman/symfony-console-completion.git", 2360 | "reference": "5461d43e53092b3d3b9dbd9d999f2054730f4bbb" 2361 | }, 2362 | "dist": { 2363 | "type": "zip", 2364 | "url": "https://api.github.com/repos/stecman/symfony-console-completion/zipball/5461d43e53092b3d3b9dbd9d999f2054730f4bbb", 2365 | "reference": "5461d43e53092b3d3b9dbd9d999f2054730f4bbb", 2366 | "shasum": "" 2367 | }, 2368 | "require": { 2369 | "php": ">=5.3.2", 2370 | "symfony/console": "~2.3 || ~3.0" 2371 | }, 2372 | "require-dev": { 2373 | "phpunit/phpunit": "~4.4" 2374 | }, 2375 | "type": "library", 2376 | "extra": { 2377 | "branch-alias": { 2378 | "dev-master": "0.6.x-dev" 2379 | } 2380 | }, 2381 | "autoload": { 2382 | "psr-4": { 2383 | "Stecman\\Component\\Symfony\\Console\\BashCompletion\\": "src/" 2384 | } 2385 | }, 2386 | "notification-url": "https://packagist.org/downloads/", 2387 | "license": [ 2388 | "MIT" 2389 | ], 2390 | "authors": [ 2391 | { 2392 | "name": "Stephen Holdaway", 2393 | "email": "stephen@stecman.co.nz" 2394 | } 2395 | ], 2396 | "description": "Automatic BASH completion for Symfony Console Component based applications.", 2397 | "time": "2016-02-24T05:08:54+00:00" 2398 | }, 2399 | { 2400 | "name": "symfony/browser-kit", 2401 | "version": "v3.3.4", 2402 | "source": { 2403 | "type": "git", 2404 | "url": "https://github.com/symfony/browser-kit.git", 2405 | "reference": "3a4435e79a8401746e8525e98039199d0924b4e5" 2406 | }, 2407 | "dist": { 2408 | "type": "zip", 2409 | "url": "https://api.github.com/repos/symfony/browser-kit/zipball/3a4435e79a8401746e8525e98039199d0924b4e5", 2410 | "reference": "3a4435e79a8401746e8525e98039199d0924b4e5", 2411 | "shasum": "" 2412 | }, 2413 | "require": { 2414 | "php": ">=5.5.9", 2415 | "symfony/dom-crawler": "~2.8|~3.0" 2416 | }, 2417 | "require-dev": { 2418 | "symfony/css-selector": "~2.8|~3.0", 2419 | "symfony/process": "~2.8|~3.0" 2420 | }, 2421 | "suggest": { 2422 | "symfony/process": "" 2423 | }, 2424 | "type": "library", 2425 | "extra": { 2426 | "branch-alias": { 2427 | "dev-master": "3.3-dev" 2428 | } 2429 | }, 2430 | "autoload": { 2431 | "psr-4": { 2432 | "Symfony\\Component\\BrowserKit\\": "" 2433 | }, 2434 | "exclude-from-classmap": [ 2435 | "/Tests/" 2436 | ] 2437 | }, 2438 | "notification-url": "https://packagist.org/downloads/", 2439 | "license": [ 2440 | "MIT" 2441 | ], 2442 | "authors": [ 2443 | { 2444 | "name": "Fabien Potencier", 2445 | "email": "fabien@symfony.com" 2446 | }, 2447 | { 2448 | "name": "Symfony Community", 2449 | "homepage": "https://symfony.com/contributors" 2450 | } 2451 | ], 2452 | "description": "Symfony BrowserKit Component", 2453 | "homepage": "https://symfony.com", 2454 | "time": "2017-06-24T09:29:48+00:00" 2455 | }, 2456 | { 2457 | "name": "symfony/console", 2458 | "version": "v3.3.4", 2459 | "source": { 2460 | "type": "git", 2461 | "url": "https://github.com/symfony/console.git", 2462 | "reference": "a97e45d98c59510f085fa05225a1acb74dfe0546" 2463 | }, 2464 | "dist": { 2465 | "type": "zip", 2466 | "url": "https://api.github.com/repos/symfony/console/zipball/a97e45d98c59510f085fa05225a1acb74dfe0546", 2467 | "reference": "a97e45d98c59510f085fa05225a1acb74dfe0546", 2468 | "shasum": "" 2469 | }, 2470 | "require": { 2471 | "php": ">=5.5.9", 2472 | "symfony/debug": "~2.8|~3.0", 2473 | "symfony/polyfill-mbstring": "~1.0" 2474 | }, 2475 | "conflict": { 2476 | "symfony/dependency-injection": "<3.3" 2477 | }, 2478 | "require-dev": { 2479 | "psr/log": "~1.0", 2480 | "symfony/config": "~3.3", 2481 | "symfony/dependency-injection": "~3.3", 2482 | "symfony/event-dispatcher": "~2.8|~3.0", 2483 | "symfony/filesystem": "~2.8|~3.0", 2484 | "symfony/http-kernel": "~2.8|~3.0", 2485 | "symfony/process": "~2.8|~3.0" 2486 | }, 2487 | "suggest": { 2488 | "psr/log": "For using the console logger", 2489 | "symfony/event-dispatcher": "", 2490 | "symfony/filesystem": "", 2491 | "symfony/process": "" 2492 | }, 2493 | "type": "library", 2494 | "extra": { 2495 | "branch-alias": { 2496 | "dev-master": "3.3-dev" 2497 | } 2498 | }, 2499 | "autoload": { 2500 | "psr-4": { 2501 | "Symfony\\Component\\Console\\": "" 2502 | }, 2503 | "exclude-from-classmap": [ 2504 | "/Tests/" 2505 | ] 2506 | }, 2507 | "notification-url": "https://packagist.org/downloads/", 2508 | "license": [ 2509 | "MIT" 2510 | ], 2511 | "authors": [ 2512 | { 2513 | "name": "Fabien Potencier", 2514 | "email": "fabien@symfony.com" 2515 | }, 2516 | { 2517 | "name": "Symfony Community", 2518 | "homepage": "https://symfony.com/contributors" 2519 | } 2520 | ], 2521 | "description": "Symfony Console Component", 2522 | "homepage": "https://symfony.com", 2523 | "time": "2017-07-03T13:19:36+00:00" 2524 | }, 2525 | { 2526 | "name": "symfony/css-selector", 2527 | "version": "v3.3.4", 2528 | "source": { 2529 | "type": "git", 2530 | "url": "https://github.com/symfony/css-selector.git", 2531 | "reference": "4d882dced7b995d5274293039370148e291808f2" 2532 | }, 2533 | "dist": { 2534 | "type": "zip", 2535 | "url": "https://api.github.com/repos/symfony/css-selector/zipball/4d882dced7b995d5274293039370148e291808f2", 2536 | "reference": "4d882dced7b995d5274293039370148e291808f2", 2537 | "shasum": "" 2538 | }, 2539 | "require": { 2540 | "php": ">=5.5.9" 2541 | }, 2542 | "type": "library", 2543 | "extra": { 2544 | "branch-alias": { 2545 | "dev-master": "3.3-dev" 2546 | } 2547 | }, 2548 | "autoload": { 2549 | "psr-4": { 2550 | "Symfony\\Component\\CssSelector\\": "" 2551 | }, 2552 | "exclude-from-classmap": [ 2553 | "/Tests/" 2554 | ] 2555 | }, 2556 | "notification-url": "https://packagist.org/downloads/", 2557 | "license": [ 2558 | "MIT" 2559 | ], 2560 | "authors": [ 2561 | { 2562 | "name": "Jean-François Simon", 2563 | "email": "jeanfrancois.simon@sensiolabs.com" 2564 | }, 2565 | { 2566 | "name": "Fabien Potencier", 2567 | "email": "fabien@symfony.com" 2568 | }, 2569 | { 2570 | "name": "Symfony Community", 2571 | "homepage": "https://symfony.com/contributors" 2572 | } 2573 | ], 2574 | "description": "Symfony CssSelector Component", 2575 | "homepage": "https://symfony.com", 2576 | "time": "2017-05-01T15:01:29+00:00" 2577 | }, 2578 | { 2579 | "name": "symfony/debug", 2580 | "version": "v3.3.4", 2581 | "source": { 2582 | "type": "git", 2583 | "url": "https://github.com/symfony/debug.git", 2584 | "reference": "63b85a968486d95ff9542228dc2e4247f16f9743" 2585 | }, 2586 | "dist": { 2587 | "type": "zip", 2588 | "url": "https://api.github.com/repos/symfony/debug/zipball/63b85a968486d95ff9542228dc2e4247f16f9743", 2589 | "reference": "63b85a968486d95ff9542228dc2e4247f16f9743", 2590 | "shasum": "" 2591 | }, 2592 | "require": { 2593 | "php": ">=5.5.9", 2594 | "psr/log": "~1.0" 2595 | }, 2596 | "conflict": { 2597 | "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" 2598 | }, 2599 | "require-dev": { 2600 | "symfony/http-kernel": "~2.8|~3.0" 2601 | }, 2602 | "type": "library", 2603 | "extra": { 2604 | "branch-alias": { 2605 | "dev-master": "3.3-dev" 2606 | } 2607 | }, 2608 | "autoload": { 2609 | "psr-4": { 2610 | "Symfony\\Component\\Debug\\": "" 2611 | }, 2612 | "exclude-from-classmap": [ 2613 | "/Tests/" 2614 | ] 2615 | }, 2616 | "notification-url": "https://packagist.org/downloads/", 2617 | "license": [ 2618 | "MIT" 2619 | ], 2620 | "authors": [ 2621 | { 2622 | "name": "Fabien Potencier", 2623 | "email": "fabien@symfony.com" 2624 | }, 2625 | { 2626 | "name": "Symfony Community", 2627 | "homepage": "https://symfony.com/contributors" 2628 | } 2629 | ], 2630 | "description": "Symfony Debug Component", 2631 | "homepage": "https://symfony.com", 2632 | "time": "2017-07-05T13:02:37+00:00" 2633 | }, 2634 | { 2635 | "name": "symfony/dom-crawler", 2636 | "version": "v3.3.4", 2637 | "source": { 2638 | "type": "git", 2639 | "url": "https://github.com/symfony/dom-crawler.git", 2640 | "reference": "fc2c588ce376e9fe04a7b8c79e3ec62fe32d95b1" 2641 | }, 2642 | "dist": { 2643 | "type": "zip", 2644 | "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/fc2c588ce376e9fe04a7b8c79e3ec62fe32d95b1", 2645 | "reference": "fc2c588ce376e9fe04a7b8c79e3ec62fe32d95b1", 2646 | "shasum": "" 2647 | }, 2648 | "require": { 2649 | "php": ">=5.5.9", 2650 | "symfony/polyfill-mbstring": "~1.0" 2651 | }, 2652 | "require-dev": { 2653 | "symfony/css-selector": "~2.8|~3.0" 2654 | }, 2655 | "suggest": { 2656 | "symfony/css-selector": "" 2657 | }, 2658 | "type": "library", 2659 | "extra": { 2660 | "branch-alias": { 2661 | "dev-master": "3.3-dev" 2662 | } 2663 | }, 2664 | "autoload": { 2665 | "psr-4": { 2666 | "Symfony\\Component\\DomCrawler\\": "" 2667 | }, 2668 | "exclude-from-classmap": [ 2669 | "/Tests/" 2670 | ] 2671 | }, 2672 | "notification-url": "https://packagist.org/downloads/", 2673 | "license": [ 2674 | "MIT" 2675 | ], 2676 | "authors": [ 2677 | { 2678 | "name": "Fabien Potencier", 2679 | "email": "fabien@symfony.com" 2680 | }, 2681 | { 2682 | "name": "Symfony Community", 2683 | "homepage": "https://symfony.com/contributors" 2684 | } 2685 | ], 2686 | "description": "Symfony DomCrawler Component", 2687 | "homepage": "https://symfony.com", 2688 | "time": "2017-05-25T23:10:31+00:00" 2689 | }, 2690 | { 2691 | "name": "symfony/event-dispatcher", 2692 | "version": "v3.3.4", 2693 | "source": { 2694 | "type": "git", 2695 | "url": "https://github.com/symfony/event-dispatcher.git", 2696 | "reference": "67535f1e3fd662bdc68d7ba317c93eecd973617e" 2697 | }, 2698 | "dist": { 2699 | "type": "zip", 2700 | "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/67535f1e3fd662bdc68d7ba317c93eecd973617e", 2701 | "reference": "67535f1e3fd662bdc68d7ba317c93eecd973617e", 2702 | "shasum": "" 2703 | }, 2704 | "require": { 2705 | "php": ">=5.5.9" 2706 | }, 2707 | "conflict": { 2708 | "symfony/dependency-injection": "<3.3" 2709 | }, 2710 | "require-dev": { 2711 | "psr/log": "~1.0", 2712 | "symfony/config": "~2.8|~3.0", 2713 | "symfony/dependency-injection": "~3.3", 2714 | "symfony/expression-language": "~2.8|~3.0", 2715 | "symfony/stopwatch": "~2.8|~3.0" 2716 | }, 2717 | "suggest": { 2718 | "symfony/dependency-injection": "", 2719 | "symfony/http-kernel": "" 2720 | }, 2721 | "type": "library", 2722 | "extra": { 2723 | "branch-alias": { 2724 | "dev-master": "3.3-dev" 2725 | } 2726 | }, 2727 | "autoload": { 2728 | "psr-4": { 2729 | "Symfony\\Component\\EventDispatcher\\": "" 2730 | }, 2731 | "exclude-from-classmap": [ 2732 | "/Tests/" 2733 | ] 2734 | }, 2735 | "notification-url": "https://packagist.org/downloads/", 2736 | "license": [ 2737 | "MIT" 2738 | ], 2739 | "authors": [ 2740 | { 2741 | "name": "Fabien Potencier", 2742 | "email": "fabien@symfony.com" 2743 | }, 2744 | { 2745 | "name": "Symfony Community", 2746 | "homepage": "https://symfony.com/contributors" 2747 | } 2748 | ], 2749 | "description": "Symfony EventDispatcher Component", 2750 | "homepage": "https://symfony.com", 2751 | "time": "2017-06-09T14:53:08+00:00" 2752 | }, 2753 | { 2754 | "name": "symfony/finder", 2755 | "version": "v3.3.4", 2756 | "source": { 2757 | "type": "git", 2758 | "url": "https://github.com/symfony/finder.git", 2759 | "reference": "baea7f66d30854ad32988c11a09d7ffd485810c4" 2760 | }, 2761 | "dist": { 2762 | "type": "zip", 2763 | "url": "https://api.github.com/repos/symfony/finder/zipball/baea7f66d30854ad32988c11a09d7ffd485810c4", 2764 | "reference": "baea7f66d30854ad32988c11a09d7ffd485810c4", 2765 | "shasum": "" 2766 | }, 2767 | "require": { 2768 | "php": ">=5.5.9" 2769 | }, 2770 | "type": "library", 2771 | "extra": { 2772 | "branch-alias": { 2773 | "dev-master": "3.3-dev" 2774 | } 2775 | }, 2776 | "autoload": { 2777 | "psr-4": { 2778 | "Symfony\\Component\\Finder\\": "" 2779 | }, 2780 | "exclude-from-classmap": [ 2781 | "/Tests/" 2782 | ] 2783 | }, 2784 | "notification-url": "https://packagist.org/downloads/", 2785 | "license": [ 2786 | "MIT" 2787 | ], 2788 | "authors": [ 2789 | { 2790 | "name": "Fabien Potencier", 2791 | "email": "fabien@symfony.com" 2792 | }, 2793 | { 2794 | "name": "Symfony Community", 2795 | "homepage": "https://symfony.com/contributors" 2796 | } 2797 | ], 2798 | "description": "Symfony Finder Component", 2799 | "homepage": "https://symfony.com", 2800 | "time": "2017-06-01T21:01:25+00:00" 2801 | }, 2802 | { 2803 | "name": "symfony/polyfill-mbstring", 2804 | "version": "v1.4.0", 2805 | "source": { 2806 | "type": "git", 2807 | "url": "https://github.com/symfony/polyfill-mbstring.git", 2808 | "reference": "f29dca382a6485c3cbe6379f0c61230167681937" 2809 | }, 2810 | "dist": { 2811 | "type": "zip", 2812 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f29dca382a6485c3cbe6379f0c61230167681937", 2813 | "reference": "f29dca382a6485c3cbe6379f0c61230167681937", 2814 | "shasum": "" 2815 | }, 2816 | "require": { 2817 | "php": ">=5.3.3" 2818 | }, 2819 | "suggest": { 2820 | "ext-mbstring": "For best performance" 2821 | }, 2822 | "type": "library", 2823 | "extra": { 2824 | "branch-alias": { 2825 | "dev-master": "1.4-dev" 2826 | } 2827 | }, 2828 | "autoload": { 2829 | "psr-4": { 2830 | "Symfony\\Polyfill\\Mbstring\\": "" 2831 | }, 2832 | "files": [ 2833 | "bootstrap.php" 2834 | ] 2835 | }, 2836 | "notification-url": "https://packagist.org/downloads/", 2837 | "license": [ 2838 | "MIT" 2839 | ], 2840 | "authors": [ 2841 | { 2842 | "name": "Nicolas Grekas", 2843 | "email": "p@tchwork.com" 2844 | }, 2845 | { 2846 | "name": "Symfony Community", 2847 | "homepage": "https://symfony.com/contributors" 2848 | } 2849 | ], 2850 | "description": "Symfony polyfill for the Mbstring extension", 2851 | "homepage": "https://symfony.com", 2852 | "keywords": [ 2853 | "compatibility", 2854 | "mbstring", 2855 | "polyfill", 2856 | "portable", 2857 | "shim" 2858 | ], 2859 | "time": "2017-06-09T14:24:12+00:00" 2860 | }, 2861 | { 2862 | "name": "symfony/process", 2863 | "version": "v3.3.4", 2864 | "source": { 2865 | "type": "git", 2866 | "url": "https://github.com/symfony/process.git", 2867 | "reference": "5ab8949b682b1bf9d4511a228b5e045c96758c30" 2868 | }, 2869 | "dist": { 2870 | "type": "zip", 2871 | "url": "https://api.github.com/repos/symfony/process/zipball/5ab8949b682b1bf9d4511a228b5e045c96758c30", 2872 | "reference": "5ab8949b682b1bf9d4511a228b5e045c96758c30", 2873 | "shasum": "" 2874 | }, 2875 | "require": { 2876 | "php": ">=5.5.9" 2877 | }, 2878 | "type": "library", 2879 | "extra": { 2880 | "branch-alias": { 2881 | "dev-master": "3.3-dev" 2882 | } 2883 | }, 2884 | "autoload": { 2885 | "psr-4": { 2886 | "Symfony\\Component\\Process\\": "" 2887 | }, 2888 | "exclude-from-classmap": [ 2889 | "/Tests/" 2890 | ] 2891 | }, 2892 | "notification-url": "https://packagist.org/downloads/", 2893 | "license": [ 2894 | "MIT" 2895 | ], 2896 | "authors": [ 2897 | { 2898 | "name": "Fabien Potencier", 2899 | "email": "fabien@symfony.com" 2900 | }, 2901 | { 2902 | "name": "Symfony Community", 2903 | "homepage": "https://symfony.com/contributors" 2904 | } 2905 | ], 2906 | "description": "Symfony Process Component", 2907 | "homepage": "https://symfony.com", 2908 | "time": "2017-07-03T08:12:02+00:00" 2909 | }, 2910 | { 2911 | "name": "symfony/yaml", 2912 | "version": "v3.3.4", 2913 | "source": { 2914 | "type": "git", 2915 | "url": "https://github.com/symfony/yaml.git", 2916 | "reference": "1f93a8d19b8241617f5074a123e282575b821df8" 2917 | }, 2918 | "dist": { 2919 | "type": "zip", 2920 | "url": "https://api.github.com/repos/symfony/yaml/zipball/1f93a8d19b8241617f5074a123e282575b821df8", 2921 | "reference": "1f93a8d19b8241617f5074a123e282575b821df8", 2922 | "shasum": "" 2923 | }, 2924 | "require": { 2925 | "php": ">=5.5.9" 2926 | }, 2927 | "require-dev": { 2928 | "symfony/console": "~2.8|~3.0" 2929 | }, 2930 | "suggest": { 2931 | "symfony/console": "For validating YAML files using the lint command" 2932 | }, 2933 | "type": "library", 2934 | "extra": { 2935 | "branch-alias": { 2936 | "dev-master": "3.3-dev" 2937 | } 2938 | }, 2939 | "autoload": { 2940 | "psr-4": { 2941 | "Symfony\\Component\\Yaml\\": "" 2942 | }, 2943 | "exclude-from-classmap": [ 2944 | "/Tests/" 2945 | ] 2946 | }, 2947 | "notification-url": "https://packagist.org/downloads/", 2948 | "license": [ 2949 | "MIT" 2950 | ], 2951 | "authors": [ 2952 | { 2953 | "name": "Fabien Potencier", 2954 | "email": "fabien@symfony.com" 2955 | }, 2956 | { 2957 | "name": "Symfony Community", 2958 | "homepage": "https://symfony.com/contributors" 2959 | } 2960 | ], 2961 | "description": "Symfony Yaml Component", 2962 | "homepage": "https://symfony.com", 2963 | "time": "2017-06-15T12:58:50+00:00" 2964 | }, 2965 | { 2966 | "name": "theseer/tokenizer", 2967 | "version": "1.1.0", 2968 | "source": { 2969 | "type": "git", 2970 | "url": "https://github.com/theseer/tokenizer.git", 2971 | "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" 2972 | }, 2973 | "dist": { 2974 | "type": "zip", 2975 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", 2976 | "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", 2977 | "shasum": "" 2978 | }, 2979 | "require": { 2980 | "ext-dom": "*", 2981 | "ext-tokenizer": "*", 2982 | "ext-xmlwriter": "*", 2983 | "php": "^7.0" 2984 | }, 2985 | "type": "library", 2986 | "autoload": { 2987 | "classmap": [ 2988 | "src/" 2989 | ] 2990 | }, 2991 | "notification-url": "https://packagist.org/downloads/", 2992 | "license": [ 2993 | "BSD-3-Clause" 2994 | ], 2995 | "authors": [ 2996 | { 2997 | "name": "Arne Blankerts", 2998 | "email": "arne@blankerts.de", 2999 | "role": "Developer" 3000 | } 3001 | ], 3002 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", 3003 | "time": "2017-04-07T12:08:54+00:00" 3004 | }, 3005 | { 3006 | "name": "webmozart/assert", 3007 | "version": "1.2.0", 3008 | "source": { 3009 | "type": "git", 3010 | "url": "https://github.com/webmozart/assert.git", 3011 | "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" 3012 | }, 3013 | "dist": { 3014 | "type": "zip", 3015 | "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", 3016 | "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", 3017 | "shasum": "" 3018 | }, 3019 | "require": { 3020 | "php": "^5.3.3 || ^7.0" 3021 | }, 3022 | "require-dev": { 3023 | "phpunit/phpunit": "^4.6", 3024 | "sebastian/version": "^1.0.1" 3025 | }, 3026 | "type": "library", 3027 | "extra": { 3028 | "branch-alias": { 3029 | "dev-master": "1.3-dev" 3030 | } 3031 | }, 3032 | "autoload": { 3033 | "psr-4": { 3034 | "Webmozart\\Assert\\": "src/" 3035 | } 3036 | }, 3037 | "notification-url": "https://packagist.org/downloads/", 3038 | "license": [ 3039 | "MIT" 3040 | ], 3041 | "authors": [ 3042 | { 3043 | "name": "Bernhard Schussek", 3044 | "email": "bschussek@gmail.com" 3045 | } 3046 | ], 3047 | "description": "Assertions to validate method input/output with nice error messages.", 3048 | "keywords": [ 3049 | "assert", 3050 | "check", 3051 | "validate" 3052 | ], 3053 | "time": "2016-11-23T20:04:58+00:00" 3054 | } 3055 | ], 3056 | "aliases": [], 3057 | "minimum-stability": "stable", 3058 | "stability-flags": [], 3059 | "prefer-stable": false, 3060 | "prefer-lowest": false, 3061 | "platform": { 3062 | "php": ">=5.6.0" 3063 | }, 3064 | "platform-dev": { 3065 | "php": ">=5.6.0" 3066 | } 3067 | } 3068 | -------------------------------------------------------------------------------- /src/DuplicateKeyException.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright 2010-2017 Philippe Gaultier 9 | * @license http://www.sweelix.net/license license 10 | * @version XXX 11 | * @link http://www.sweelix.net 12 | * @package sweelix\rbac\redis 13 | */ 14 | 15 | namespace sweelix\rbac\redis; 16 | 17 | use Exception; 18 | 19 | /** 20 | * This exception is raised when a duplicate key is found and 21 | * entity cannot be inserted. 22 | * 23 | * @author Philippe Gaultier 24 | * @copyright 2010-2017 Philippe Gaultier 25 | * @license http://www.sweelix.net/license license 26 | * @version XXX 27 | * @link http://www.sweelix.net 28 | * @package sweelix\rbac\redis 29 | * @since XXX 30 | */ 31 | class DuplicateKeyException extends Exception 32 | { 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/Manager.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright 2010-2017 Philippe Gaultier 9 | * @license http://www.sweelix.net/license license 10 | * @version XXX 11 | * @link http://www.sweelix.net 12 | * @package sweelix\rbac\redis 13 | */ 14 | 15 | namespace sweelix\rbac\redis; 16 | 17 | use sweelix\guid\Guid; 18 | use Yii; 19 | use yii\base\InvalidCallException; 20 | use yii\base\InvalidParamException; 21 | use yii\di\Instance; 22 | use yii\rbac\Assignment; 23 | use yii\rbac\BaseManager; 24 | use yii\rbac\Permission; 25 | use yii\rbac\Role; 26 | use yii\rbac\Item; 27 | use yii\rbac\Rule; 28 | use yii\redis\Connection; 29 | 30 | /** 31 | * REDIS Manager represents an authorization manager that stores 32 | * authorization information in REDIS database 33 | * 34 | * database structure : 35 | * * auth:users::assignments : ZSET (string: roleName, score: createdAt) 36 | * * auth:roles::assignments : ZSET (string|int: userId, score: createdAt) 37 | * * auth:rules: : MAP (string: ruleName, string: data, integer: createdAt, integer: updatedAt) 38 | * * auth:types::items : SET (string: itemName) 39 | * * auth:items: : MAP (string: itemName, int: typeId, string: description, integer: createdAt, integer: updatedAt, string: ruleName) 40 | * * auth:rules::items : SET (string: itemName) 41 | * * auth:items::children : SET (string: itemName) 42 | * * auth:items::parents : SET (string: itemName) 43 | * * auth:mappings:items : MAP (string: itemName, string: guid) 44 | * * auth:mappings:itemsguid : MAP (string: guid, string: itemName) 45 | * * auth:mappings:rules : MAP (string: ruleName, string: guid) 46 | * * auth:mappings:rulesguid : MAP (string: guid, string: ruleName) 47 | * 48 | * @author Philippe Gaultier 49 | * @copyright 2010-2017 Philippe Gaultier 50 | * @license http://www.sweelix.net/license license 51 | * @version XXX 52 | * @link http://www.sweelix.net 53 | * @package application\controllers 54 | * @since XXX 55 | */ 56 | class Manager extends BaseManager 57 | { 58 | /** 59 | * @var Connection|array|string the Redis DB connection object or the application component ID of the DB connection. 60 | */ 61 | public $db = 'redis'; 62 | 63 | /** 64 | * @var string 65 | */ 66 | public $globalMatchKey = 'auth:*'; 67 | 68 | /** 69 | * @var string 70 | */ 71 | public $userAssignmentsKey = 'auth:users:{id}:assignments'; 72 | 73 | /** 74 | * @var string 75 | */ 76 | public $roleAssignmentsKey = 'auth:roles:{id}:assignments'; 77 | 78 | /** 79 | * @var string 80 | */ 81 | public $ruleKey = 'auth:rules:{id}'; 82 | 83 | /** 84 | * @var string 85 | */ 86 | public $typeItemsKey = 'auth:types:{id}:items'; 87 | 88 | /** 89 | * @var string 90 | */ 91 | public $itemKey = 'auth:items:{id}'; 92 | 93 | /** 94 | * @var string 95 | */ 96 | public $ruleItemsKey = 'auth:rules:{id}:items'; 97 | 98 | /** 99 | * @var string 100 | */ 101 | public $itemChildrenKey = 'auth:items:{id}:children'; 102 | 103 | /** 104 | * @var string 105 | */ 106 | public $itemParentsKey = 'auth:items:{id}:parents'; 107 | 108 | /** 109 | * @var string 110 | */ 111 | public $itemMappings = 'auth:mappings:items'; 112 | 113 | /** 114 | * @var string 115 | */ 116 | public $itemMappingsGuid = 'auth:mappings:itemsguid'; 117 | 118 | /** 119 | * @var string 120 | */ 121 | public $ruleMappings = 'auth:mappings:rules'; 122 | 123 | /** 124 | * @var string 125 | */ 126 | public $ruleMappingsGuid = 'auth:mappings:rulesguid'; 127 | 128 | 129 | /** 130 | * @param string|integer $userId user id 131 | * @return string the user assignments key 132 | * @since XXX 133 | */ 134 | public function getUserAssignmentsKey($userId) 135 | { 136 | return str_replace('{id}', $userId, $this->userAssignmentsKey); 137 | } 138 | 139 | /** 140 | * @param string $roleGuid role guid 141 | * @return string the rule assignments key 142 | * @since XXX 143 | */ 144 | public function getRoleAssignmentsKey($roleGuid) 145 | { 146 | return str_replace('{id}', $roleGuid, $this->roleAssignmentsKey); 147 | } 148 | 149 | /** 150 | * @param string $ruleGuid rule guid 151 | * @return string the rule key 152 | * @since XXX 153 | */ 154 | public function getRuleKey($ruleGuid) 155 | { 156 | return str_replace('{id}', $ruleGuid, $this->ruleKey); 157 | } 158 | 159 | /** 160 | * @param integer $typeId type id 161 | * @return string the type id key 162 | * @since XXX 163 | */ 164 | public function getTypeItemsKey($typeId) 165 | { 166 | return str_replace('{id}', $typeId, $this->typeItemsKey); 167 | } 168 | 169 | /** 170 | * @param string $itemGuid item guid 171 | * @return string 172 | * @since XXX 173 | */ 174 | public function getItemKey($itemGuid) 175 | { 176 | return str_replace('{id}', $itemGuid, $this->itemKey); 177 | } 178 | 179 | /** 180 | * @param string $ruleGuid rule guid 181 | * @return string the rule items key 182 | * @since XXX 183 | */ 184 | public function getRuleItemsKey($ruleGuid) 185 | { 186 | return str_replace('{id}', $ruleGuid, $this->ruleItemsKey); 187 | } 188 | 189 | /** 190 | * @param string $itemGuid item guid 191 | * @return string the item children key 192 | * @since XXX 193 | */ 194 | public function getItemChildrenKey($itemGuid) 195 | { 196 | return str_replace('{id}', $itemGuid, $this->itemChildrenKey); 197 | } 198 | 199 | /** 200 | * @param string $itemGuid item guid 201 | * @return string the item parents key 202 | * @since XXX 203 | */ 204 | public function getItemParentsKey($itemGuid) 205 | { 206 | return str_replace('{id}', $itemGuid, $this->itemParentsKey); 207 | } 208 | 209 | /** 210 | * @return string the item mapping key 211 | * @since XXX 212 | */ 213 | public function getItemMappingKey() 214 | { 215 | return $this->itemMappings; 216 | } 217 | 218 | /** 219 | * @return string the rule mapping key 220 | * @since XXX 221 | */ 222 | public function getRuleMappingKey() 223 | { 224 | return $this->ruleMappings; 225 | } 226 | 227 | /** 228 | * @return string the item mapping key 229 | * @since XXX 230 | */ 231 | public function getItemMappingGuidKey() 232 | { 233 | return $this->itemMappingsGuid; 234 | } 235 | 236 | /** 237 | * @return string the rule mapping key 238 | * @since XXX 239 | */ 240 | public function getRuleMappingGuidKey() 241 | { 242 | return $this->ruleMappingsGuid; 243 | } 244 | 245 | 246 | /** 247 | * @inheritdoc 248 | */ 249 | public function init() 250 | { 251 | parent::init(); 252 | $this->db = Instance::ensure($this->db, Connection::className()); 253 | } 254 | 255 | /** 256 | * @inheritdoc 257 | */ 258 | protected function getItem($name) 259 | { 260 | $item = null; 261 | $guid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $name]); 262 | if ($guid !== null) { 263 | $item = $this->getItemByGuid($guid, $name); 264 | } 265 | return $item; 266 | } 267 | 268 | /** 269 | * @param string $guid item guid 270 | * @param string $name name if known to avoid additional call 271 | * @return mixed 272 | * @since XXX 273 | */ 274 | protected function getItemByGuid($guid, $name = null) 275 | { 276 | if ($name === null) { 277 | $name = $this->db->executeCommand('HGET', [$this->getItemMappingGuidKey(), $guid]); 278 | } 279 | $data = $this->db->executeCommand('HGETALL', [$this->getItemKey($guid)]); 280 | $dataRow = ['name' => $name]; 281 | $nbProps = count($data); 282 | for ($i = 0; $i < $nbProps; $i = $i + 2) { 283 | $dataRow[$data[$i]] = $data[($i + 1)]; 284 | } 285 | if (isset($dataRow['ruleGuid']) === true) { 286 | $dataRow['ruleName'] = $this->db->executeCommand('HGET', [$this->getRuleMappingGuidKey(), $dataRow['ruleGuid']]); 287 | unset($dataRow['ruleGuid']); 288 | } elseif(isset($dataRow['ruleClass']) === true) { 289 | $dataRow['ruleName'] = $dataRow['ruleClass']; 290 | unset($dataRow['ruleClass']); 291 | } 292 | $item = $this->populateItem($dataRow); 293 | return $item; 294 | } 295 | 296 | /** 297 | * @inheritdoc 298 | */ 299 | protected function getItems($type) 300 | { 301 | $itemGuids = $this->db->executeCommand('SMEMBERS', [$this->getTypeItemsKey($type)]); 302 | $items = []; 303 | foreach($itemGuids as $itemGuid) { 304 | $item = $this->getItemByGuid($itemGuid); 305 | $items[$item->name] = $item; 306 | } 307 | return $items; 308 | } 309 | 310 | /** 311 | * @inheritdoc 312 | */ 313 | protected function addItem($item) 314 | { 315 | if (empty($item->name) === true) { 316 | throw new InvalidParamException("Item name must be defined"); 317 | } 318 | $itemExists = (int)$this->db->executeCommand('HEXISTS', [$this->getItemMappingKey(), $item->name]); 319 | if ($itemExists === 1) { 320 | throw new DuplicateKeyException("Rule '{$item->name}' already defined"); 321 | } 322 | $guid = Guid::v4(); 323 | $time = time(); 324 | if ($item->createdAt === null) { 325 | $item->createdAt = $time; 326 | } 327 | if ($item->updatedAt === null) { 328 | $item->updatedAt = $time; 329 | } 330 | 331 | list($insertInRedis, ) = $this->prepareRedisItem($item, $guid); 332 | $this->db->executeCommand('MULTI'); 333 | // update mapping 334 | $this->db->executeCommand('HSET', [$this->getItemMappingKey(), $item->name, $guid]); 335 | $this->db->executeCommand('HSET', [$this->getItemMappingGuidKey(), $guid, $item->name]); 336 | // insert item 337 | $this->db->executeCommand('HMSET', $insertInRedis); 338 | $this->db->executeCommand('SADD', [$this->getTypeItemsKey($item->type), $guid]); 339 | // affect rule 340 | if (isset($insertInRedis['ruleGuid']) === true) { 341 | $this->db->executeCommand('SADD', [$this->getRuleItemsKey($insertInRedis['ruleGuid']), $guid]); 342 | } 343 | $this->db->executeCommand('EXEC'); 344 | return true; 345 | 346 | } 347 | 348 | /** 349 | * @param Item $item item to insert in DB 350 | * @param string $guid guid generated 351 | * @return array Redis command 352 | * @since XXX 353 | */ 354 | private function prepareRedisItem($item, $guid) 355 | { 356 | $redisCleanItem = [$this->getItemKey($guid)]; 357 | $redisItem = [$this->getItemKey($guid), 358 | 'data', serialize($item->data), 359 | 'type', $item->type, 360 | 'createdAt', $item->createdAt, 361 | 'updatedAt', $item->updatedAt 362 | ]; 363 | 364 | $ruleGuid = $this->db->executeCommand('HGET', [$this->getRuleMappingKey(), $item->ruleName]); 365 | 366 | if ($ruleGuid !== null) { 367 | $redisItem[] = 'ruleGuid'; 368 | $redisItem[] = $ruleGuid; 369 | $redisCleanItem[] = 'ruleClass'; 370 | } elseif (class_exists($item->ruleName) || Yii::$container->has($item->ruleName)) { 371 | $redisItem[] = 'ruleClass'; 372 | $redisItem[] = $item->ruleName; 373 | $redisCleanItem[] = 'ruleGuid'; 374 | } 375 | 376 | if ($item->description !== null) { 377 | $redisItem[] = 'description'; 378 | $redisItem[] = $item->description; 379 | } else { 380 | $redisCleanItem[] = 'description'; 381 | } 382 | return [$redisItem, $redisCleanItem]; 383 | } 384 | 385 | 386 | /** 387 | * @inheritdoc 388 | */ 389 | protected function updateItem($name, $item) 390 | { 391 | $item->updatedAt = time(); 392 | 393 | $guid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $name]); 394 | 395 | $ruleGuid = $this->db->executeCommand('HGET', [$this->getRuleMappingKey(), $item->ruleName]); 396 | $newRule = $ruleGuid; 397 | if (($ruleGuid === null) && (empty($item->ruleName) === false)) { 398 | $newRule = $item->ruleName; 399 | } 400 | 401 | list($currentRuleGuid, $currentRuleClass, $currentType) = $this->db->executeCommand('HMGET', [$this->getItemKey($guid), 'ruleGuid', 'ruleClass', 'type']); 402 | 403 | $oldRule = ($currentRuleGuid === null) ? $currentRuleClass : $currentRuleGuid; 404 | $isUpdated = $newRule !== $oldRule; 405 | 406 | $this->db->executeCommand('MULTI'); 407 | if ($name !== $item->name) { 408 | $this->remap($name, $item->name, $guid, false); 409 | } 410 | 411 | list($updateItem, $updateEmptyItem) = $this->prepareRedisItem($item, $guid); 412 | 413 | if ($isUpdated && $currentRuleGuid !== null) { 414 | $this->db->executeCommand('SREM', [$this->getRuleItemsKey($currentRuleGuid), $guid]); 415 | } 416 | if ($isUpdated && $ruleGuid !== null) { 417 | $this->db->executeCommand('SADD', [$this->getRuleItemsKey($ruleGuid), $guid]); 418 | } 419 | if ($item->type !== $currentType) { 420 | $this->db->executeCommand('SREM', [$this->getTypeItemsKey($currentType), $guid]); 421 | $this->db->executeCommand('SADD', [$this->getTypeItemsKey($item->type), $guid]); 422 | } 423 | 424 | // update item 425 | $this->db->executeCommand('HMSET', $updateItem); 426 | // remove useless props 427 | if (count($updateEmptyItem) > 1) { 428 | $this->db->executeCommand('HDEL', $updateEmptyItem); 429 | } 430 | 431 | 432 | $this->db->executeCommand('EXEC'); 433 | return true; 434 | 435 | } 436 | 437 | /** 438 | * @param string $oldName old mapping name 439 | * @param string $newName new mapping name 440 | * @param string $guid unique ID 441 | * @since XXX 442 | */ 443 | private function remap($oldName, $newName, $guid, $isRule = false) 444 | { 445 | if ($isRule) { 446 | $mappingKey = $this->getRuleMappingKey(); 447 | $mappingGuidKey = $this->getRuleMappingGuidKey(); 448 | } else { 449 | $mappingKey = $this->getItemMappingKey(); 450 | $mappingGuidKey = $this->getItemMappingGuidKey(); 451 | } 452 | $this->db->executeCommand('HDEL', [$mappingKey, $oldName]); 453 | // add new mapping 454 | $this->db->executeCommand('HSET', [$mappingKey, $newName, $guid]); 455 | $this->db->executeCommand('HSET', [$mappingGuidKey, $guid, $newName]); 456 | } 457 | 458 | /** 459 | * @inheritdoc 460 | */ 461 | protected function removeItem($item) 462 | { 463 | $mappingKey = $this->getItemMappingKey(); 464 | 465 | $guid = $this->db->executeCommand('HGET', [$mappingKey, $item->name]); 466 | $ruleGuid = $this->db->executeCommand('HGET', [$this->getRuleMappingKey(), $item->ruleName]); 467 | 468 | $parentGuids = $this->db->executeCommand('SMEMBERS', [$this->getItemParentsKey($guid)]); 469 | $childrenGuids = $this->db->executeCommand('SMEMBERS', [$this->getItemChildrenKey($guid)]); 470 | 471 | $this->db->executeCommand('MULTI'); 472 | // delete mapping 473 | $this->db->executeCommand('HDEL', [$mappingKey, $item->name]); 474 | $this->db->executeCommand('HDEL', [$this->getItemMappingGuidKey(), $guid]); 475 | // delete rule <-> item link 476 | $this->db->executeCommand('SREM', [$this->getRuleItemsKey($ruleGuid), $guid]); 477 | $this->db->executeCommand('SREM', [$this->getTypeItemsKey($item->type), $guid]); 478 | // detach from hierarchy 479 | foreach($parentGuids as $parentGuid) { 480 | $this->db->executeCommand('SREM', [$this->getItemChildrenKey($parentGuid), $guid]); 481 | } 482 | // detach children 483 | foreach($childrenGuids as $childGuid) { 484 | $this->db->executeCommand('SREM', [$this->getItemParentsKey($childGuid), $guid]); 485 | } 486 | $this->db->executeCommand('DEL', [$this->getItemParentsKey($guid)]); 487 | $this->db->executeCommand('DEL', [$this->getItemChildrenKey($guid)]); 488 | // delete rule 489 | $this->db->executeCommand('DEL', [$this->getItemKey($guid)]); 490 | $this->db->executeCommand('EXEC'); 491 | return true; 492 | 493 | } 494 | 495 | /** 496 | * @inheritdoc 497 | */ 498 | protected function addRule($rule) 499 | { 500 | if(empty($rule->name) === true) { 501 | throw new InvalidParamException("Rule name must be defined"); 502 | } 503 | $ruleExists = (int)$this->db->executeCommand('HEXISTS', [$this->getRuleMappingKey(), $rule->name]); 504 | if ($ruleExists === 1) 505 | { 506 | throw new DuplicateKeyException("Rule '{$rule->name}' already defined"); 507 | } 508 | $guid = Guid::v4(); 509 | $time = time(); 510 | if ($rule->createdAt === null) { 511 | $rule->createdAt = $time; 512 | } 513 | if ($rule->updatedAt === null) { 514 | $rule->updatedAt = $time; 515 | } 516 | $this->db->executeCommand('MULTI'); 517 | $this->db->executeCommand('HSET', [$this->getRuleMappingKey(), $rule->name, $guid]); 518 | $this->db->executeCommand('HSET', [$this->getRuleMappingGuidKey(),$guid, $rule->name]); 519 | $this->db->executeCommand('HMSET', [$this->getRuleKey($guid), 520 | 'data', serialize($rule), 521 | 'createdAt', $rule->createdAt, 522 | 'updatedAt', $rule->updatedAt 523 | ]); 524 | 525 | $this->db->executeCommand('EXEC'); 526 | return true; 527 | 528 | } 529 | 530 | /** 531 | * @inheritdoc 532 | */ 533 | protected function updateRule($name, $rule) 534 | { 535 | $rule->updatedAt = time(); 536 | 537 | $guid = $this->db->executeCommand('HGET', [$this->getRuleMappingKey(), $name]); 538 | 539 | $this->db->executeCommand('MULTI'); 540 | if ($name !== $rule->name) { 541 | $this->remap($name, $rule->name, $guid, true); 542 | } 543 | $this->db->executeCommand('HMSET', [$this->getRuleKey($guid), 544 | 'data', serialize($rule), 545 | 'createdAt', $rule->createdAt, 546 | 'updatedAt', $rule->updatedAt 547 | ]); 548 | 549 | $this->db->executeCommand('EXEC'); 550 | return true; 551 | } 552 | 553 | /** 554 | * @inheritdoc 555 | */ 556 | protected function removeRule($rule) 557 | { 558 | $guid = $this->db->executeCommand('HGET', [$this->getRuleMappingKey(), $rule->name]); 559 | 560 | $ruleMembers = $this->db->executeCommand('SMEMBERS', [$this->getRuleItemsKey($guid)]); 561 | 562 | $this->db->executeCommand('MULTI'); 563 | // delete mapping 564 | $this->db->executeCommand('HDEL', [$this->getRuleMappingKey(), $rule->name]); 565 | $this->db->executeCommand('HDEL', [$this->getRuleMappingGuidKey(), $guid]); 566 | // detach items 567 | foreach($ruleMembers as $itemGuid) 568 | { 569 | $this->db->executeCommand('HDEL', [$this->getItemKey($itemGuid), 'ruleGuid']); 570 | } 571 | // delete rule <-> item link 572 | $this->db->executeCommand('DEL', [$this->getRuleItemsKey($guid)]); 573 | // delete rule 574 | $this->db->executeCommand('DEL', [$this->getRuleKey($guid)]); 575 | $this->db->executeCommand('EXEC'); 576 | return true; 577 | } 578 | 579 | /** 580 | * @inheritdoc 581 | */ 582 | public function getRules() 583 | { 584 | $ruleNames = $this->db->executeCommand('HKEYS', [$this->getRuleMappingKey()]); 585 | $rules = []; 586 | foreach ($ruleNames as $ruleName) 587 | { 588 | $rules[$ruleName] = $this->getRule($ruleName); 589 | } 590 | return $rules; 591 | } 592 | 593 | /** 594 | * @inheritdoc 595 | */ 596 | public function getRule($name) 597 | { 598 | $rule = null; 599 | $guid = $this->db->executeCommand('HGET', [$this->getRuleMappingKey(), $name]); 600 | if ($guid !== null) { 601 | $rule = $this->getRuleGuid($guid); 602 | } elseif(class_exists($name) === true) { 603 | $rule = new $name; 604 | } elseif(Yii::$container->has($name) === true) { 605 | $rule = Yii::$container->get($name); 606 | } 607 | return $rule; 608 | } 609 | 610 | /** 611 | * @param string $guid rule unique ID 612 | * @return Rule 613 | * @since XXX 614 | */ 615 | protected function getRuleGuid($guid) 616 | { 617 | $data = $this->db->executeCommand('HGET', [$this->getRuleKey($guid), 'data']); 618 | $rule = unserialize($data); 619 | return $rule; 620 | } 621 | 622 | /** 623 | * @inheritdoc 624 | */ 625 | public function addChild($parent, $child) 626 | { 627 | if ($parent->name === $child->name) { 628 | throw new InvalidParamException("Cannot add '{$parent->name}' as a child of itself."); 629 | } 630 | if ($parent instanceof Permission && $child instanceof Role) { 631 | throw new InvalidParamException('Cannot add a role as a child of a permission.'); 632 | } 633 | if ($this->detectLoop($parent, $child)) { 634 | throw new InvalidCallException("Cannot add '{$child->name}' as a child of '{$parent->name}'. A loop has been detected."); 635 | } 636 | 637 | list($parentGuid, $childGuid) = $this->db->executeCommand('HMGET', [$this->getItemMappingKey(), $parent->name, $child->name]); 638 | 639 | $this->db->executeCommand('MULTI'); 640 | $this->db->executeCommand('SADD', [$this->getItemParentsKey($childGuid), $parentGuid]); 641 | $this->db->executeCommand('SADD', [$this->getItemChildrenKey($parentGuid), $childGuid]); 642 | $this->db->executeCommand('EXEC'); 643 | return true; 644 | } 645 | 646 | /** 647 | * @inheritdoc 648 | */ 649 | public function removeChild($parent, $child) 650 | { 651 | list($parentGuid, $childGuid) = $this->db->executeCommand('HMGET', [$this->getItemMappingKey(), $parent->name, $child->name]); 652 | $this->db->executeCommand('MULTI'); 653 | $this->db->executeCommand('SREM', [$this->getItemParentsKey($childGuid), $parentGuid]); 654 | $this->db->executeCommand('SREM', [$this->getItemChildrenKey($parentGuid), $childGuid]); 655 | $this->db->executeCommand('EXEC'); 656 | return true; 657 | 658 | } 659 | 660 | /** 661 | * @inheritdoc 662 | */ 663 | public function removeChildren($parent) 664 | { 665 | $guid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $parent->name]); 666 | $childrenGuids = $this->db->executeCommand('SMEMBERS', [$this->getItemChildrenKey($guid)]); 667 | 668 | $this->db->executeCommand('MULTI'); 669 | foreach($childrenGuids as $childGuid) 670 | { 671 | $this->db->executeCommand('SREM', [$this->getItemParentsKey($childGuid), $guid]); 672 | } 673 | $this->db->executeCommand('DEL', [$this->getItemChildrenKey($guid)]); 674 | $this->db->executeCommand('EXEC'); 675 | return true; 676 | 677 | } 678 | 679 | /** 680 | * @inheritdoc 681 | */ 682 | public function getChildren($name) 683 | { 684 | $guid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $name]); 685 | return $this->getChildrenByGuid($guid); 686 | 687 | } 688 | 689 | /** 690 | * @param string $guid item guid 691 | * @return Item[] 692 | * @since XXX 693 | */ 694 | protected function getChildrenByGuid($guid) 695 | { 696 | $childrenGuids = $this->db->executeCommand('SMEMBERS', [$this->getItemChildrenKey($guid)]); 697 | $children = []; 698 | if (count($childrenGuids) > 0) { 699 | foreach($childrenGuids as $childGuid) { 700 | $children[] = $this->getItemByGuid($childGuid); 701 | } 702 | } 703 | return $children; 704 | } 705 | 706 | /** 707 | * @inheritdoc 708 | */ 709 | public function hasChild($parent, $child) 710 | { 711 | list($parentGuid, $childGuid) = $this->db->executeCommand('HMGET', [$this->getItemMappingKey(), $parent->name, $child->name]); 712 | $result = (int)$this->db->executeCommand('SISMEMBER', [$this->getItemChildrenKey($parentGuid), $childGuid]); 713 | 714 | return $result === 1; 715 | 716 | } 717 | 718 | /** 719 | * @inheritdoc 720 | */ 721 | public function revokeAll($userId) 722 | { 723 | if (empty($userId) === true) { 724 | return false; 725 | } 726 | $roleGuids = $this->db->executeCommand('ZRANGEBYSCORE', [$this->getUserAssignmentsKey($userId), '-inf', '+inf']); 727 | $this->db->executeCommand('MULTI'); 728 | if (count($roleGuids) > 0) { 729 | foreach ($roleGuids as $roleGuid) { 730 | $this->db->executeCommand('ZREM', [$this->getRoleAssignmentsKey($roleGuid), $userId]); 731 | } 732 | } 733 | $this->db->executeCommand('DEL', [$this->getUserAssignmentsKey($userId)]); 734 | $this->db->executeCommand('EXEC'); 735 | return true; 736 | 737 | } 738 | 739 | /** 740 | * @inheritdoc 741 | */ 742 | public function revoke($role, $userId) 743 | { 744 | if (empty($userId) === true) { 745 | return false; 746 | } 747 | $roleGuid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $role->name]); 748 | 749 | $this->db->executeCommand('MULTI'); 750 | $this->db->executeCommand('ZREM', [$this->getUserAssignmentsKey($userId), $roleGuid]); 751 | $this->db->executeCommand('ZREM', [$this->getRoleAssignmentsKey($roleGuid), $userId]); 752 | $this->db->executeCommand('EXEC'); 753 | return true; 754 | } 755 | 756 | /** 757 | * @inheritdoc 758 | */ 759 | public function removeAllRoles() 760 | { 761 | $this->removeAllItems(Item::TYPE_ROLE); 762 | } 763 | 764 | /** 765 | * @inheritdoc 766 | */ 767 | public function removeAllRules() 768 | { 769 | $rules = $this->getRules(); 770 | foreach($rules as $rule) { 771 | $this->removeRule($rule); 772 | } 773 | } 774 | 775 | /** 776 | * @inheritdoc 777 | */ 778 | public function removeAllPermissions() 779 | { 780 | $this->removeAllItems(Item::TYPE_PERMISSION); 781 | } 782 | 783 | /** 784 | * @inheritdoc 785 | */ 786 | public function removeAll() 787 | { 788 | $authKeys = []; 789 | $nextCursor = 0; 790 | do { 791 | list($nextCursor, $keys) = $this->db->executeCommand('SCAN', [$nextCursor, 'MATCH', $this->globalMatchKey]); 792 | $authKeys = array_merge($authKeys, $keys); 793 | 794 | } while($nextCursor != 0); 795 | 796 | if (count($authKeys) > 0) { 797 | $this->db->executeCommand('DEL', $authKeys); 798 | } 799 | } 800 | 801 | /** 802 | * @inheritdoc 803 | */ 804 | public function removeAllAssignments() 805 | { 806 | $roleAssignKey = $this->getRoleAssignmentsKey('*'); 807 | $userAssignKey = $this->getUserAssignmentsKey('*'); 808 | $assignmentKeys = []; 809 | 810 | $nextCursor = 0; 811 | do { 812 | list($nextCursor, $keys) = $this->db->executeCommand('SCAN', [$nextCursor, 'MATCH', $roleAssignKey]); 813 | $assignmentKeys = array_merge($assignmentKeys, $keys); 814 | 815 | } while($nextCursor != 0); 816 | 817 | $nextCursor = 0; 818 | do { 819 | list($nextCursor, $keys) = $this->db->executeCommand('SCAN', [$nextCursor, 'MATCH', $userAssignKey]); 820 | $assignmentKeys = array_merge($assignmentKeys, $keys); 821 | 822 | } while($nextCursor != 0); 823 | 824 | if (count($assignmentKeys) > 0) { 825 | $this->db->executeCommand('DEL', $assignmentKeys); 826 | } 827 | } 828 | 829 | /** 830 | * @param integer $type 831 | * @since XXX 832 | */ 833 | public function removeAllItems($type) 834 | { 835 | $items = $this->getItems($type); 836 | foreach ($items as $item) { 837 | $this->removeItem($item); 838 | } 839 | } 840 | 841 | /** 842 | * @inheritdoc 843 | */ 844 | public function getRolesByUser($userId) 845 | { 846 | if (!isset($userId) || $userId === '') { 847 | return []; 848 | } 849 | $roleGuids = $this->db->executeCommand('ZRANGEBYSCORE', [$this->getUserAssignmentsKey($userId), '-inf', '+inf']); 850 | $roles = []; 851 | if (count($roleGuids) > 0) { 852 | foreach ($roleGuids as $roleGuid) { 853 | $isRole = (int)$this->db->executeCommand('SISMEMBER', [$this->getTypeItemsKey(Item::TYPE_ROLE), $roleGuid]); 854 | if ($isRole === 1) { 855 | $item = $this->getItemByGuid($roleGuid); 856 | $roles[$item->name] = $item; 857 | } 858 | } 859 | } 860 | 861 | return $roles; 862 | } 863 | 864 | /** 865 | * @inheritdoc 866 | */ 867 | public function getUserIdsByRole($roleName) 868 | { 869 | if (empty($roleName)) { 870 | return []; 871 | } 872 | $roleGuid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $roleName]); 873 | $userIds = []; 874 | if ($roleGuid !== null) { 875 | $userIds = $this->db->executeCommand('ZRANGEBYSCORE', [$this->getRoleAssignmentsKey($roleGuid), '-inf', '+inf']); 876 | } 877 | return $userIds; 878 | 879 | } 880 | 881 | /** 882 | * @inheritdoc 883 | */ 884 | public function assign($role, $userId) 885 | { 886 | $assignment = new Assignment([ 887 | 'userId' => $userId, 888 | 'roleName' => $role->name, 889 | 'createdAt' => time(), 890 | ]); 891 | $roleGuid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $role->name]); 892 | 893 | $this->db->executeCommand('MULTI'); 894 | $this->db->executeCommand('ZADD', [$this->getUserAssignmentsKey($userId), $assignment->createdAt, $roleGuid]); 895 | $this->db->executeCommand('ZADD', [$this->getRoleAssignmentsKey($roleGuid), $assignment->createdAt, $userId]); 896 | $this->db->executeCommand('EXEC'); 897 | return $assignment; 898 | } 899 | 900 | /** 901 | * @inheritdoc 902 | */ 903 | public function getPermissionsByUser($userId) 904 | { 905 | $rolesGuids = $this->db->executeCommand('ZRANGEBYSCORE', [$this->getUserAssignmentsKey($userId), '-inf', '+inf']); 906 | $permissions = []; 907 | if (count($rolesGuids) > 0) { 908 | $permissionsGuid = []; 909 | foreach($rolesGuids as $roleGuid) { 910 | $isPerm = (int)$this->db->executeCommand('SISMEMBER', [$this->getTypeItemsKey(Item::TYPE_PERMISSION), $roleGuid]); 911 | if ($isPerm === 1) { 912 | $permissionsGuid[] = $roleGuid; 913 | } 914 | } 915 | foreach ($rolesGuids as $roleGuid) { 916 | list(, $permGuids) = $this->getChildrenRecursiveGuid($roleGuid, Item::TYPE_PERMISSION); 917 | $permissionsGuid = array_merge($permissionsGuid, $permGuids); 918 | } 919 | foreach($permissionsGuid as $permissionGuid) { 920 | $item = $this->getItemByGuid($permissionGuid); 921 | $permissions[$item->name] = $item; 922 | } 923 | } 924 | return $permissions; 925 | } 926 | 927 | /** 928 | * @inheritdoc 929 | */ 930 | public function getChildRoles($roleName) 931 | { 932 | $roleGuid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $roleName]); 933 | if (is_null($roleGuid)) { 934 | throw new InvalidParamException("Role \"$roleName\" not found."); 935 | } 936 | list(, $rolesGuid) = $this->getChildrenRecursiveGuid($roleGuid, Item::TYPE_ROLE); 937 | 938 | $roles[$roleName] = $this->getRole($roleName); 939 | foreach($rolesGuid as $roleGuid) { 940 | $item = $this->getItemByGuid($roleGuid); 941 | $roles[$item->name] = $item; 942 | } 943 | return $roles; 944 | } 945 | 946 | /** 947 | * @inheritdoc 948 | */ 949 | public function getPermissionsByRole($roleName) 950 | { 951 | $roleGuid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $roleName]); 952 | $permissions = []; 953 | list(, $permissionsGuid) = $this->getChildrenRecursiveGuid($roleGuid, Item::TYPE_PERMISSION); 954 | foreach($permissionsGuid as $permissionGuid) { 955 | $item = $this->getItemByGuid($permissionGuid); 956 | $permissions[$item->name] = $item; 957 | } 958 | return $permissions; 959 | } 960 | 961 | /** 962 | * @param string $itemGuid item unique ID 963 | * @param integer $type Item type 964 | * @return array 965 | * @since XXX 966 | */ 967 | protected function getChildrenRecursiveGuid($itemGuid, $type) 968 | { 969 | $childrenGuid = $this->db->executeCommand('SMEMBERS', [$this->getItemChildrenKey($itemGuid)]); 970 | $typedChildrenGuid = $this->db->executeCommand('SINTER', [$this->getItemChildrenKey($itemGuid), $this->getTypeItemsKey($type)]); 971 | foreach($childrenGuid as $childGuid) { 972 | list($subChildrenGuid, $subTypedChildrenGuid) = $this->getChildrenRecursiveGuid($childGuid, $type); 973 | $childrenGuid = array_merge($childrenGuid, $subChildrenGuid); 974 | $typedChildrenGuid = array_merge($typedChildrenGuid, $subTypedChildrenGuid); 975 | } 976 | return [$childrenGuid, $typedChildrenGuid]; 977 | } 978 | 979 | /** 980 | * @param Item $parent parent item 981 | * @param Item $child child item 982 | * @return bool 983 | * @since XXX 984 | */ 985 | protected function detectLoop(Item $parent, Item $child) 986 | { 987 | if ($child->name === $parent->name) { 988 | return true; 989 | } 990 | foreach ($this->getChildren($child->name) as $grandchild) { 991 | if ($this->detectLoop($parent, $grandchild)) { 992 | return true; 993 | } 994 | } 995 | return false; 996 | } 997 | 998 | /** 999 | * @param string $itemName item name 1000 | * @return array 1001 | * @since XXX 1002 | */ 1003 | public function getParents($itemName) 1004 | { 1005 | $itemGuid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $itemName]); 1006 | return $this->getParentsGuid($itemGuid); 1007 | } 1008 | 1009 | protected function getParentsGuid($itemGuid) 1010 | { 1011 | $parentsGuid = $this->db->executeCommand('SMEMBERS', [$this->getItemParentsKey($itemGuid)]); 1012 | $parents = []; 1013 | if (count($parentsGuid) > 0) { 1014 | array_unshift($parentsGuid, $this->getItemMappingGuidKey()); 1015 | $parents = $this->db->executeCommand('HMGET', $parentsGuid); 1016 | } 1017 | return $parents; 1018 | } 1019 | 1020 | /** 1021 | * @inheritdoc 1022 | */ 1023 | public function getAssignments($userId) 1024 | { 1025 | $roleGuids = $this->db->executeCommand('ZRANGEBYSCORE', [$this->getUserAssignmentsKey($userId), '-inf', '+inf', 'WITHSCORES']); 1026 | $assignments = []; 1027 | if (count($roleGuids) > 0) { 1028 | $guids = []; 1029 | $dates = []; 1030 | $nbRolesGuids = count($roleGuids); 1031 | for($i=0; $i < $nbRolesGuids; $i = $i + 2) { 1032 | $guids[] = $roleGuids[$i]; 1033 | $dates[] = $roleGuids[($i + 1)]; 1034 | } 1035 | array_unshift($guids, $this->getItemMappingGuidKey()); 1036 | $names = $this->db->executeCommand('HMGET', $guids); 1037 | foreach ($names as $i => $name) { 1038 | $assignments[$name] = new Assignment([ 1039 | 'userId' => $userId, 1040 | 'roleName' => $name, 1041 | 'createdAt' => $dates[$i], 1042 | ]); 1043 | } 1044 | } 1045 | 1046 | return $assignments; 1047 | 1048 | } 1049 | 1050 | /** 1051 | * @inheritdoc 1052 | */ 1053 | public function getAssignment($roleName, $userId) 1054 | { 1055 | $roleGuid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $roleName]); 1056 | $assignment = null; 1057 | if ($roleGuid !== null) { 1058 | $assignmentScore = $this->db->executeCommand('ZSCORE', [$this->getUserAssignmentsKey($userId), $roleGuid]); 1059 | if ($assignmentScore !== null) { 1060 | $assignment = new Assignment([ 1061 | 'userId' => $userId, 1062 | 'roleName' => $roleName, 1063 | 'createdAt' => $assignmentScore, 1064 | ]); 1065 | } 1066 | } 1067 | return $assignment; 1068 | } 1069 | 1070 | /** 1071 | * @inheritdoc 1072 | */ 1073 | public function checkAccess($userId, $permissionName, $params = []) 1074 | { 1075 | $assignments = $this->getAssignments($userId); 1076 | return $this->checkAccessRecursive($userId, $permissionName, $params, $assignments); 1077 | } 1078 | 1079 | 1080 | /** 1081 | * @param Item $parent parent item 1082 | * @param Item $child child item 1083 | * @return bool 1084 | * @since XXX 1085 | */ 1086 | public function canAddChild($parent, $child) 1087 | { 1088 | return !$this->detectLoop($parent, $child); 1089 | } 1090 | 1091 | /** 1092 | * @param string|integer $user user ID 1093 | * @param string $itemName current item name 1094 | * @param array $params parameters applied in rule 1095 | * @param Assignment[] $assignments 1096 | * @return bool 1097 | * @since XXX 1098 | * @throws \yii\base\InvalidConfigException 1099 | */ 1100 | protected function checkAccessRecursive($user, $itemName, $params, $assignments) 1101 | { 1102 | if (($item = $this->getItem($itemName)) === null) { 1103 | return false; 1104 | } 1105 | Yii::trace($item instanceof Role ? "Checking role: $itemName" : "Checking permission: $itemName", __METHOD__); 1106 | if (!$this->executeRule($user, $item, $params)) { 1107 | return false; 1108 | } 1109 | if (isset($assignments[$itemName]) || in_array($itemName, $this->defaultRoles)) { 1110 | return true; 1111 | } 1112 | $parents = $this->getParents($itemName); 1113 | foreach ($parents as $parent) { 1114 | if ($this->checkAccessRecursive($user, $parent, $params, $assignments)) { 1115 | return true; 1116 | } 1117 | } 1118 | return false; 1119 | } 1120 | 1121 | /** 1122 | * @param array $dataRow 1123 | * @return Permission|Role 1124 | * @since XXX 1125 | */ 1126 | protected function populateItem($dataRow) 1127 | { 1128 | $class = $dataRow['type'] == Item::TYPE_PERMISSION ? Permission::className() : Role::className(); 1129 | if (!isset($dataRow['data']) || ($data = @unserialize($dataRow['data'])) === false) { 1130 | $data = null; 1131 | } 1132 | 1133 | return new $class([ 1134 | 'name' => $dataRow['name'], 1135 | 'type' => $dataRow['type'], 1136 | 'description' => isset($dataRow['description']) ? $dataRow['description'] : null, 1137 | 'ruleName' => isset($dataRow['ruleName']) ? $dataRow['ruleName'] : null, 1138 | 'data' => $data, 1139 | 'createdAt' => $dataRow['createdAt'], 1140 | 'updatedAt' => $dataRow['updatedAt'], 1141 | ]); 1142 | } 1143 | } 1144 | --------------------------------------------------------------------------------