├── .all-contributorsrc ├── .gitattributes ├── .phplint.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE.md ├── TODO.md ├── composer.json ├── composer.lock ├── phpcs.xml.dist ├── phpstan.neon.dist └── src ├── Traits ├── Arrays.php ├── Collections.php ├── Functions.php ├── Objects.php ├── Sequence │ ├── Chain.php │ └── ChainWrapper.php ├── Strings.php └── Utilities.php └── __.php /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "php-lodash", 3 | "projectOwner": "", 4 | "files": [ 5 | "README.md" 6 | ], 7 | "imageSize": 100, 8 | "commit": false, 9 | "contributors": [ 10 | { 11 | "login": "Meabed", 12 | "name": "Mohamed Meabed", 13 | "avatar_url": "https://avatars0.githubusercontent.com/u/45731?v=3", 14 | "profile": "https://github.com/Meabed", 15 | "contributions": [ 16 | "code", 17 | "test", 18 | "talk" 19 | ] 20 | }, 21 | { 22 | "login": "ziishaned", 23 | "name": "Zeeshan Ahmad", 24 | "avatar_url": "https://avatars2.githubusercontent.com/u/16267321?v=3", 25 | "profile": "https://github.com/ziishaned", 26 | "contributions": [ 27 | "code", 28 | "bug", 29 | "test", 30 | "doc" 31 | ] 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Path-based git attributes 2 | # https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html 3 | * text=auto 4 | *.txt text 5 | 6 | # Ignore all test and documentation with "export-ignore". 7 | /.editorconfig export-ignore 8 | /.gitattributesexport-ignore 9 | /.gitignore export-ignore 10 | /.scrutinizer.yml export-ignore 11 | /.styleci.yml export-ignore 12 | /.travis.yml export-ignore 13 | /.github export-ignore 14 | /docs export-ignore 15 | /phpunit.xml.dist export-ignore 16 | /tests export-ignore 17 | /Gruntfile.js export-ignore 18 | /package.json export-ignore 19 | /README.md export-ignore 20 | /CONTRIBUTING.md export-ignore 21 | -------------------------------------------------------------------------------- /.phplint.yml: -------------------------------------------------------------------------------- 1 | path: ./ 2 | jobs: 10 3 | cache: ./build/phplint-cache 4 | extensions: 5 | - php 6 | exclude: 7 | - vendor 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `:package_name` will be documented in this file. 4 | 5 | Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles. 6 | 7 | ## NEXT - YYYY-MM-DD 8 | 9 | ### Added 10 | - Nothing 11 | 12 | ### Deprecated 13 | - Nothing 14 | 15 | ### Fixed 16 | - Nothing 17 | 18 | ### Removed 19 | - Nothing 20 | 21 | ### Security 22 | - Nothing 23 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to make participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at `:author_email`. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 me.io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | ## TODO 2 | 3 | - [ ] Documentation 4 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "me-io/php-lodash", 3 | "type": "library", 4 | "version": "2.0.0", 5 | "description": "A full-on PHP manipulation utility-belt that provides support for the usual functional.", 6 | "keywords": [ 7 | "__", 8 | "lodash", 9 | "bottomline", 10 | "library", 11 | "utility", 12 | "functions" 13 | ], 14 | "license": "MIT", 15 | "minimum-stability": "dev", 16 | "prefer-stable": true, 17 | "require": { 18 | "php": ">=7.1" 19 | }, 20 | "require-dev": { 21 | "phpunit/phpunit": "^7.5", 22 | "squizlabs/php_codesniffer": "^3.4", 23 | "overtrue/phplint": "^1.1", 24 | "phpstan/phpstan": "^0.11" 25 | }, 26 | "autoload": { 27 | "files": [ 28 | "src/__.php" 29 | ], 30 | "psr-4": { 31 | "__\\": "src/" 32 | } 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "Tests\\": "tests/" 37 | } 38 | }, 39 | "scripts": { 40 | "update-dev": "composer update", 41 | "install-dev": "composer install --no-interaction", 42 | "update-prod": "composer update --no-dev", 43 | "install-prod": "composer install --no-dev --no-interaction", 44 | "stan": "phpstan analyse src", 45 | "test": "phpunit", 46 | "test-cov": "phpunit --coverage-text --coverage-clover=coverage.xml", 47 | "test-html": "phpunit --coverage-text --coverage-clover=coverage.xml --coverage-html=./report/", 48 | "lint": "phplint", 49 | "check-style": "phpcs src tests", 50 | "fix-style": "phpcbf src tests" 51 | }, 52 | "extra": { 53 | "branch-alias": { 54 | "dev-master": "2.0.x-dev" 55 | } 56 | }, 57 | "config": { 58 | "optimize-autoloader": true, 59 | "preferred-install": "dist", 60 | "sort-packages": true, 61 | "process-timeout": 1000000 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /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#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "69539d8aca6ee20a2a331c8834290c6b", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "composer/xdebug-handler", 12 | "version": "1.3.1", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/composer/xdebug-handler.git", 16 | "reference": "dc523135366eb68f22268d069ea7749486458562" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/dc523135366eb68f22268d069ea7749486458562", 21 | "reference": "dc523135366eb68f22268d069ea7749486458562", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "php": "^5.3.2 || ^7.0", 26 | "psr/log": "^1.0" 27 | }, 28 | "require-dev": { 29 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" 30 | }, 31 | "type": "library", 32 | "autoload": { 33 | "psr-4": { 34 | "Composer\\XdebugHandler\\": "src" 35 | } 36 | }, 37 | "notification-url": "https://packagist.org/downloads/", 38 | "license": [ 39 | "MIT" 40 | ], 41 | "authors": [ 42 | { 43 | "name": "John Stevenson", 44 | "email": "john-stevenson@blueyonder.co.uk" 45 | } 46 | ], 47 | "description": "Restarts a process without xdebug.", 48 | "keywords": [ 49 | "Xdebug", 50 | "performance" 51 | ], 52 | "time": "2018-11-29T10:59:02+00:00" 53 | }, 54 | { 55 | "name": "doctrine/instantiator", 56 | "version": "1.1.0", 57 | "source": { 58 | "type": "git", 59 | "url": "https://github.com/doctrine/instantiator.git", 60 | "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" 61 | }, 62 | "dist": { 63 | "type": "zip", 64 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", 65 | "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", 66 | "shasum": "" 67 | }, 68 | "require": { 69 | "php": "^7.1" 70 | }, 71 | "require-dev": { 72 | "athletic/athletic": "~0.1.8", 73 | "ext-pdo": "*", 74 | "ext-phar": "*", 75 | "phpunit/phpunit": "^6.2.3", 76 | "squizlabs/php_codesniffer": "^3.0.2" 77 | }, 78 | "type": "library", 79 | "extra": { 80 | "branch-alias": { 81 | "dev-master": "1.2.x-dev" 82 | } 83 | }, 84 | "autoload": { 85 | "psr-4": { 86 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 87 | } 88 | }, 89 | "notification-url": "https://packagist.org/downloads/", 90 | "license": [ 91 | "MIT" 92 | ], 93 | "authors": [ 94 | { 95 | "name": "Marco Pivetta", 96 | "email": "ocramius@gmail.com", 97 | "homepage": "http://ocramius.github.com/" 98 | } 99 | ], 100 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 101 | "homepage": "https://github.com/doctrine/instantiator", 102 | "keywords": [ 103 | "constructor", 104 | "instantiate" 105 | ], 106 | "time": "2017-07-22T11:58:36+00:00" 107 | }, 108 | { 109 | "name": "jean85/pretty-package-versions", 110 | "version": "1.2", 111 | "source": { 112 | "type": "git", 113 | "url": "https://github.com/Jean85/pretty-package-versions.git", 114 | "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48" 115 | }, 116 | "dist": { 117 | "type": "zip", 118 | "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/75c7effcf3f77501d0e0caa75111aff4daa0dd48", 119 | "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48", 120 | "shasum": "" 121 | }, 122 | "require": { 123 | "ocramius/package-versions": "^1.2.0", 124 | "php": "^7.0" 125 | }, 126 | "require-dev": { 127 | "phpunit/phpunit": "^6.0" 128 | }, 129 | "type": "library", 130 | "extra": { 131 | "branch-alias": { 132 | "dev-master": "1.x-dev" 133 | } 134 | }, 135 | "autoload": { 136 | "psr-4": { 137 | "Jean85\\": "src/" 138 | } 139 | }, 140 | "notification-url": "https://packagist.org/downloads/", 141 | "license": [ 142 | "MIT" 143 | ], 144 | "authors": [ 145 | { 146 | "name": "Alessandro Lai", 147 | "email": "alessandro.lai85@gmail.com" 148 | } 149 | ], 150 | "description": "A wrapper for ocramius/package-versions to get pretty versions strings", 151 | "keywords": [ 152 | "composer", 153 | "package", 154 | "release", 155 | "versions" 156 | ], 157 | "time": "2018-06-13T13:22:40+00:00" 158 | }, 159 | { 160 | "name": "myclabs/deep-copy", 161 | "version": "1.8.1", 162 | "source": { 163 | "type": "git", 164 | "url": "https://github.com/myclabs/DeepCopy.git", 165 | "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" 166 | }, 167 | "dist": { 168 | "type": "zip", 169 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", 170 | "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", 171 | "shasum": "" 172 | }, 173 | "require": { 174 | "php": "^7.1" 175 | }, 176 | "replace": { 177 | "myclabs/deep-copy": "self.version" 178 | }, 179 | "require-dev": { 180 | "doctrine/collections": "^1.0", 181 | "doctrine/common": "^2.6", 182 | "phpunit/phpunit": "^7.1" 183 | }, 184 | "type": "library", 185 | "autoload": { 186 | "psr-4": { 187 | "DeepCopy\\": "src/DeepCopy/" 188 | }, 189 | "files": [ 190 | "src/DeepCopy/deep_copy.php" 191 | ] 192 | }, 193 | "notification-url": "https://packagist.org/downloads/", 194 | "license": [ 195 | "MIT" 196 | ], 197 | "description": "Create deep copies (clones) of your objects", 198 | "keywords": [ 199 | "clone", 200 | "copy", 201 | "duplicate", 202 | "object", 203 | "object graph" 204 | ], 205 | "time": "2018-06-11T23:09:50+00:00" 206 | }, 207 | { 208 | "name": "nette/bootstrap", 209 | "version": "v2.4.6", 210 | "source": { 211 | "type": "git", 212 | "url": "https://github.com/nette/bootstrap.git", 213 | "reference": "268816e3f1bb7426c3a4ceec2bd38a036b532543" 214 | }, 215 | "dist": { 216 | "type": "zip", 217 | "url": "https://api.github.com/repos/nette/bootstrap/zipball/268816e3f1bb7426c3a4ceec2bd38a036b532543", 218 | "reference": "268816e3f1bb7426c3a4ceec2bd38a036b532543", 219 | "shasum": "" 220 | }, 221 | "require": { 222 | "nette/di": "~2.4.7", 223 | "nette/utils": "~2.4", 224 | "php": ">=5.6.0" 225 | }, 226 | "conflict": { 227 | "nette/nette": "<2.2" 228 | }, 229 | "require-dev": { 230 | "latte/latte": "~2.2", 231 | "nette/application": "~2.3", 232 | "nette/caching": "~2.3", 233 | "nette/database": "~2.3", 234 | "nette/forms": "~2.3", 235 | "nette/http": "~2.4.0", 236 | "nette/mail": "~2.3", 237 | "nette/robot-loader": "^2.4.2 || ^3.0", 238 | "nette/safe-stream": "~2.2", 239 | "nette/security": "~2.3", 240 | "nette/tester": "~2.0", 241 | "tracy/tracy": "^2.4.1" 242 | }, 243 | "suggest": { 244 | "nette/robot-loader": "to use Configurator::createRobotLoader()", 245 | "tracy/tracy": "to use Configurator::enableTracy()" 246 | }, 247 | "type": "library", 248 | "extra": { 249 | "branch-alias": { 250 | "dev-master": "2.4-dev" 251 | } 252 | }, 253 | "autoload": { 254 | "classmap": [ 255 | "src/" 256 | ] 257 | }, 258 | "notification-url": "https://packagist.org/downloads/", 259 | "license": [ 260 | "BSD-3-Clause", 261 | "GPL-2.0", 262 | "GPL-3.0" 263 | ], 264 | "authors": [ 265 | { 266 | "name": "David Grudl", 267 | "homepage": "https://davidgrudl.com" 268 | }, 269 | { 270 | "name": "Nette Community", 271 | "homepage": "https://nette.org/contributors" 272 | } 273 | ], 274 | "description": "🅱 Nette Bootstrap: the simple way to configure and bootstrap your Nette application.", 275 | "homepage": "https://nette.org", 276 | "keywords": [ 277 | "bootstrapping", 278 | "configurator", 279 | "nette" 280 | ], 281 | "time": "2018-05-17T12:52:20+00:00" 282 | }, 283 | { 284 | "name": "nette/di", 285 | "version": "v2.4.14", 286 | "source": { 287 | "type": "git", 288 | "url": "https://github.com/nette/di.git", 289 | "reference": "923da3e2c0aa53162ef455472c0ac7787b096c5a" 290 | }, 291 | "dist": { 292 | "type": "zip", 293 | "url": "https://api.github.com/repos/nette/di/zipball/923da3e2c0aa53162ef455472c0ac7787b096c5a", 294 | "reference": "923da3e2c0aa53162ef455472c0ac7787b096c5a", 295 | "shasum": "" 296 | }, 297 | "require": { 298 | "ext-tokenizer": "*", 299 | "nette/neon": "^2.3.3 || ~3.0.0", 300 | "nette/php-generator": "^2.6.1 || ~3.0.0", 301 | "nette/utils": "^2.4.3 || ~3.0.0", 302 | "php": ">=5.6.0" 303 | }, 304 | "conflict": { 305 | "nette/bootstrap": "<2.4", 306 | "nette/nette": "<2.2" 307 | }, 308 | "require-dev": { 309 | "nette/tester": "^2.0", 310 | "tracy/tracy": "^2.3" 311 | }, 312 | "type": "library", 313 | "extra": { 314 | "branch-alias": { 315 | "dev-master": "2.4-dev" 316 | } 317 | }, 318 | "autoload": { 319 | "classmap": [ 320 | "src/" 321 | ] 322 | }, 323 | "notification-url": "https://packagist.org/downloads/", 324 | "license": [ 325 | "BSD-3-Clause", 326 | "GPL-2.0", 327 | "GPL-3.0" 328 | ], 329 | "authors": [ 330 | { 331 | "name": "David Grudl", 332 | "homepage": "https://davidgrudl.com" 333 | }, 334 | { 335 | "name": "Nette Community", 336 | "homepage": "https://nette.org/contributors" 337 | } 338 | ], 339 | "description": "💎 Nette Dependency Injection Container: Flexible, compiled and full-featured DIC with perfectly usable autowiring and support for all new PHP 7.1 features.", 340 | "homepage": "https://nette.org", 341 | "keywords": [ 342 | "compiled", 343 | "di", 344 | "dic", 345 | "factory", 346 | "ioc", 347 | "nette", 348 | "static" 349 | ], 350 | "time": "2018-09-17T15:47:40+00:00" 351 | }, 352 | { 353 | "name": "nette/finder", 354 | "version": "v2.4.2", 355 | "source": { 356 | "type": "git", 357 | "url": "https://github.com/nette/finder.git", 358 | "reference": "ee951a656cb8ac622e5dd33474a01fd2470505a0" 359 | }, 360 | "dist": { 361 | "type": "zip", 362 | "url": "https://api.github.com/repos/nette/finder/zipball/ee951a656cb8ac622e5dd33474a01fd2470505a0", 363 | "reference": "ee951a656cb8ac622e5dd33474a01fd2470505a0", 364 | "shasum": "" 365 | }, 366 | "require": { 367 | "nette/utils": "~2.4", 368 | "php": ">=5.6.0" 369 | }, 370 | "conflict": { 371 | "nette/nette": "<2.2" 372 | }, 373 | "require-dev": { 374 | "nette/tester": "~2.0", 375 | "tracy/tracy": "^2.3" 376 | }, 377 | "type": "library", 378 | "extra": { 379 | "branch-alias": { 380 | "dev-master": "2.4-dev" 381 | } 382 | }, 383 | "autoload": { 384 | "classmap": [ 385 | "src/" 386 | ] 387 | }, 388 | "notification-url": "https://packagist.org/downloads/", 389 | "license": [ 390 | "BSD-3-Clause", 391 | "GPL-2.0", 392 | "GPL-3.0" 393 | ], 394 | "authors": [ 395 | { 396 | "name": "David Grudl", 397 | "homepage": "https://davidgrudl.com" 398 | }, 399 | { 400 | "name": "Nette Community", 401 | "homepage": "https://nette.org/contributors" 402 | } 403 | ], 404 | "description": "🔍 Nette Finder: find files and directories with an intuitive API.", 405 | "homepage": "https://nette.org", 406 | "keywords": [ 407 | "filesystem", 408 | "glob", 409 | "iterator", 410 | "nette" 411 | ], 412 | "time": "2018-06-28T11:49:23+00:00" 413 | }, 414 | { 415 | "name": "nette/neon", 416 | "version": "v2.4.3", 417 | "source": { 418 | "type": "git", 419 | "url": "https://github.com/nette/neon.git", 420 | "reference": "5e72b1dd3e2d34f0863c5561139a19df6a1ef398" 421 | }, 422 | "dist": { 423 | "type": "zip", 424 | "url": "https://api.github.com/repos/nette/neon/zipball/5e72b1dd3e2d34f0863c5561139a19df6a1ef398", 425 | "reference": "5e72b1dd3e2d34f0863c5561139a19df6a1ef398", 426 | "shasum": "" 427 | }, 428 | "require": { 429 | "ext-iconv": "*", 430 | "ext-json": "*", 431 | "php": ">=5.6.0" 432 | }, 433 | "require-dev": { 434 | "nette/tester": "~2.0", 435 | "tracy/tracy": "^2.3" 436 | }, 437 | "type": "library", 438 | "extra": { 439 | "branch-alias": { 440 | "dev-master": "2.4-dev" 441 | } 442 | }, 443 | "autoload": { 444 | "classmap": [ 445 | "src/" 446 | ] 447 | }, 448 | "notification-url": "https://packagist.org/downloads/", 449 | "license": [ 450 | "BSD-3-Clause", 451 | "GPL-2.0", 452 | "GPL-3.0" 453 | ], 454 | "authors": [ 455 | { 456 | "name": "David Grudl", 457 | "homepage": "https://davidgrudl.com" 458 | }, 459 | { 460 | "name": "Nette Community", 461 | "homepage": "https://nette.org/contributors" 462 | } 463 | ], 464 | "description": "🍸 Nette NEON: encodes and decodes NEON file format.", 465 | "homepage": "http://ne-on.org", 466 | "keywords": [ 467 | "export", 468 | "import", 469 | "neon", 470 | "nette", 471 | "yaml" 472 | ], 473 | "time": "2018-03-21T12:12:21+00:00" 474 | }, 475 | { 476 | "name": "nette/php-generator", 477 | "version": "v3.0.5", 478 | "source": { 479 | "type": "git", 480 | "url": "https://github.com/nette/php-generator.git", 481 | "reference": "ea90209c2e8a7cd087b2742ca553c047a8df5eff" 482 | }, 483 | "dist": { 484 | "type": "zip", 485 | "url": "https://api.github.com/repos/nette/php-generator/zipball/ea90209c2e8a7cd087b2742ca553c047a8df5eff", 486 | "reference": "ea90209c2e8a7cd087b2742ca553c047a8df5eff", 487 | "shasum": "" 488 | }, 489 | "require": { 490 | "nette/utils": "^2.4.2 || ~3.0.0", 491 | "php": ">=7.0" 492 | }, 493 | "conflict": { 494 | "nette/nette": "<2.2" 495 | }, 496 | "require-dev": { 497 | "nette/tester": "^2.0", 498 | "tracy/tracy": "^2.3" 499 | }, 500 | "type": "library", 501 | "extra": { 502 | "branch-alias": { 503 | "dev-master": "3.0-dev" 504 | } 505 | }, 506 | "autoload": { 507 | "classmap": [ 508 | "src/" 509 | ] 510 | }, 511 | "notification-url": "https://packagist.org/downloads/", 512 | "license": [ 513 | "BSD-3-Clause", 514 | "GPL-2.0", 515 | "GPL-3.0" 516 | ], 517 | "authors": [ 518 | { 519 | "name": "David Grudl", 520 | "homepage": "https://davidgrudl.com" 521 | }, 522 | { 523 | "name": "Nette Community", 524 | "homepage": "https://nette.org/contributors" 525 | } 526 | ], 527 | "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 7.2 features.", 528 | "homepage": "https://nette.org", 529 | "keywords": [ 530 | "code", 531 | "nette", 532 | "php", 533 | "scaffolding" 534 | ], 535 | "time": "2018-08-09T14:32:27+00:00" 536 | }, 537 | { 538 | "name": "nette/robot-loader", 539 | "version": "v3.1.0", 540 | "source": { 541 | "type": "git", 542 | "url": "https://github.com/nette/robot-loader.git", 543 | "reference": "fc76c70e740b10f091e502b2e393d0be912f38d4" 544 | }, 545 | "dist": { 546 | "type": "zip", 547 | "url": "https://api.github.com/repos/nette/robot-loader/zipball/fc76c70e740b10f091e502b2e393d0be912f38d4", 548 | "reference": "fc76c70e740b10f091e502b2e393d0be912f38d4", 549 | "shasum": "" 550 | }, 551 | "require": { 552 | "ext-tokenizer": "*", 553 | "nette/finder": "^2.3 || ^3.0", 554 | "nette/utils": "^2.4 || ^3.0", 555 | "php": ">=5.6.0" 556 | }, 557 | "conflict": { 558 | "nette/nette": "<2.2" 559 | }, 560 | "require-dev": { 561 | "nette/tester": "^2.0", 562 | "tracy/tracy": "^2.3" 563 | }, 564 | "type": "library", 565 | "extra": { 566 | "branch-alias": { 567 | "dev-master": "3.1-dev" 568 | } 569 | }, 570 | "autoload": { 571 | "classmap": [ 572 | "src/" 573 | ] 574 | }, 575 | "notification-url": "https://packagist.org/downloads/", 576 | "license": [ 577 | "BSD-3-Clause", 578 | "GPL-2.0", 579 | "GPL-3.0" 580 | ], 581 | "authors": [ 582 | { 583 | "name": "David Grudl", 584 | "homepage": "https://davidgrudl.com" 585 | }, 586 | { 587 | "name": "Nette Community", 588 | "homepage": "https://nette.org/contributors" 589 | } 590 | ], 591 | "description": "🍀 Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.", 592 | "homepage": "https://nette.org", 593 | "keywords": [ 594 | "autoload", 595 | "class", 596 | "interface", 597 | "nette", 598 | "trait" 599 | ], 600 | "time": "2018-08-13T14:19:06+00:00" 601 | }, 602 | { 603 | "name": "nette/utils", 604 | "version": "v2.5.3", 605 | "source": { 606 | "type": "git", 607 | "url": "https://github.com/nette/utils.git", 608 | "reference": "17b9f76f2abd0c943adfb556e56f2165460b15ce" 609 | }, 610 | "dist": { 611 | "type": "zip", 612 | "url": "https://api.github.com/repos/nette/utils/zipball/17b9f76f2abd0c943adfb556e56f2165460b15ce", 613 | "reference": "17b9f76f2abd0c943adfb556e56f2165460b15ce", 614 | "shasum": "" 615 | }, 616 | "require": { 617 | "php": ">=5.6.0" 618 | }, 619 | "conflict": { 620 | "nette/nette": "<2.2" 621 | }, 622 | "require-dev": { 623 | "nette/tester": "~2.0", 624 | "tracy/tracy": "^2.3" 625 | }, 626 | "suggest": { 627 | "ext-gd": "to use Image", 628 | "ext-iconv": "to use Strings::webalize() and toAscii()", 629 | "ext-intl": "for script transliteration in Strings::webalize() and toAscii()", 630 | "ext-json": "to use Nette\\Utils\\Json", 631 | "ext-mbstring": "to use Strings::lower() etc...", 632 | "ext-xml": "to use Strings::length() etc. when mbstring is not available" 633 | }, 634 | "type": "library", 635 | "extra": { 636 | "branch-alias": { 637 | "dev-master": "2.5-dev" 638 | } 639 | }, 640 | "autoload": { 641 | "classmap": [ 642 | "src/" 643 | ], 644 | "files": [ 645 | "src/loader.php" 646 | ] 647 | }, 648 | "notification-url": "https://packagist.org/downloads/", 649 | "license": [ 650 | "BSD-3-Clause", 651 | "GPL-2.0", 652 | "GPL-3.0" 653 | ], 654 | "authors": [ 655 | { 656 | "name": "David Grudl", 657 | "homepage": "https://davidgrudl.com" 658 | }, 659 | { 660 | "name": "Nette Community", 661 | "homepage": "https://nette.org/contributors" 662 | } 663 | ], 664 | "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", 665 | "homepage": "https://nette.org", 666 | "keywords": [ 667 | "array", 668 | "core", 669 | "datetime", 670 | "images", 671 | "json", 672 | "nette", 673 | "paginator", 674 | "password", 675 | "slugify", 676 | "string", 677 | "unicode", 678 | "utf-8", 679 | "utility", 680 | "validation" 681 | ], 682 | "time": "2018-09-18T10:22:16+00:00" 683 | }, 684 | { 685 | "name": "nikic/php-parser", 686 | "version": "v4.2.0", 687 | "source": { 688 | "type": "git", 689 | "url": "https://github.com/nikic/PHP-Parser.git", 690 | "reference": "594bcae1fc0bccd3993d2f0d61a018e26ac2865a" 691 | }, 692 | "dist": { 693 | "type": "zip", 694 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/594bcae1fc0bccd3993d2f0d61a018e26ac2865a", 695 | "reference": "594bcae1fc0bccd3993d2f0d61a018e26ac2865a", 696 | "shasum": "" 697 | }, 698 | "require": { 699 | "ext-tokenizer": "*", 700 | "php": ">=7.0" 701 | }, 702 | "require-dev": { 703 | "phpunit/phpunit": "^6.5 || ^7.0" 704 | }, 705 | "bin": [ 706 | "bin/php-parse" 707 | ], 708 | "type": "library", 709 | "extra": { 710 | "branch-alias": { 711 | "dev-master": "4.2-dev" 712 | } 713 | }, 714 | "autoload": { 715 | "psr-4": { 716 | "PhpParser\\": "lib/PhpParser" 717 | } 718 | }, 719 | "notification-url": "https://packagist.org/downloads/", 720 | "license": [ 721 | "BSD-3-Clause" 722 | ], 723 | "authors": [ 724 | { 725 | "name": "Nikita Popov" 726 | } 727 | ], 728 | "description": "A PHP parser written in PHP", 729 | "keywords": [ 730 | "parser", 731 | "php" 732 | ], 733 | "time": "2019-01-12T16:31:37+00:00" 734 | }, 735 | { 736 | "name": "ocramius/package-versions", 737 | "version": "1.3.0", 738 | "source": { 739 | "type": "git", 740 | "url": "https://github.com/Ocramius/PackageVersions.git", 741 | "reference": "4489d5002c49d55576fa0ba786f42dbb009be46f" 742 | }, 743 | "dist": { 744 | "type": "zip", 745 | "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/4489d5002c49d55576fa0ba786f42dbb009be46f", 746 | "reference": "4489d5002c49d55576fa0ba786f42dbb009be46f", 747 | "shasum": "" 748 | }, 749 | "require": { 750 | "composer-plugin-api": "^1.0.0", 751 | "php": "^7.1.0" 752 | }, 753 | "require-dev": { 754 | "composer/composer": "^1.6.3", 755 | "ext-zip": "*", 756 | "infection/infection": "^0.7.1", 757 | "phpunit/phpunit": "^7.0.0" 758 | }, 759 | "type": "composer-plugin", 760 | "extra": { 761 | "class": "PackageVersions\\Installer", 762 | "branch-alias": { 763 | "dev-master": "2.0.x-dev" 764 | } 765 | }, 766 | "autoload": { 767 | "psr-4": { 768 | "PackageVersions\\": "src/PackageVersions" 769 | } 770 | }, 771 | "notification-url": "https://packagist.org/downloads/", 772 | "license": [ 773 | "MIT" 774 | ], 775 | "authors": [ 776 | { 777 | "name": "Marco Pivetta", 778 | "email": "ocramius@gmail.com" 779 | } 780 | ], 781 | "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", 782 | "time": "2018-02-05T13:05:30+00:00" 783 | }, 784 | { 785 | "name": "overtrue/phplint", 786 | "version": "1.1.9", 787 | "source": { 788 | "type": "git", 789 | "url": "https://github.com/overtrue/phplint.git", 790 | "reference": "dab041512195a6bf52401a66b65dc5b19e4d09ea" 791 | }, 792 | "dist": { 793 | "type": "zip", 794 | "url": "https://api.github.com/repos/overtrue/phplint/zipball/dab041512195a6bf52401a66b65dc5b19e4d09ea", 795 | "reference": "dab041512195a6bf52401a66b65dc5b19e4d09ea", 796 | "shasum": "" 797 | }, 798 | "require": { 799 | "ext-json": "*", 800 | "php": ">=5.5.9", 801 | "symfony/console": "^3.2|^4.0", 802 | "symfony/finder": "^3.0|^4.0", 803 | "symfony/process": "^3.0|^4.0", 804 | "symfony/yaml": "^3.0|^4.0" 805 | }, 806 | "require-dev": { 807 | "jakub-onderka/php-console-highlighter": "^0.3.2" 808 | }, 809 | "bin": [ 810 | "bin/phplint" 811 | ], 812 | "type": "library", 813 | "autoload": { 814 | "psr-4": { 815 | "Overtrue\\PHPLint\\": "src/" 816 | } 817 | }, 818 | "notification-url": "https://packagist.org/downloads/", 819 | "license": [ 820 | "MIT" 821 | ], 822 | "authors": [ 823 | { 824 | "name": "overtrue", 825 | "email": "anzhengchao@gmail.com" 826 | } 827 | ], 828 | "description": "a php syntax check tool.", 829 | "keywords": [ 830 | "check", 831 | "lint", 832 | "phplint", 833 | "syntax" 834 | ], 835 | "time": "2019-01-04T12:59:53+00:00" 836 | }, 837 | { 838 | "name": "phar-io/manifest", 839 | "version": "1.0.3", 840 | "source": { 841 | "type": "git", 842 | "url": "https://github.com/phar-io/manifest.git", 843 | "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" 844 | }, 845 | "dist": { 846 | "type": "zip", 847 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", 848 | "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", 849 | "shasum": "" 850 | }, 851 | "require": { 852 | "ext-dom": "*", 853 | "ext-phar": "*", 854 | "phar-io/version": "^2.0", 855 | "php": "^5.6 || ^7.0" 856 | }, 857 | "type": "library", 858 | "extra": { 859 | "branch-alias": { 860 | "dev-master": "1.0.x-dev" 861 | } 862 | }, 863 | "autoload": { 864 | "classmap": [ 865 | "src/" 866 | ] 867 | }, 868 | "notification-url": "https://packagist.org/downloads/", 869 | "license": [ 870 | "BSD-3-Clause" 871 | ], 872 | "authors": [ 873 | { 874 | "name": "Arne Blankerts", 875 | "email": "arne@blankerts.de", 876 | "role": "Developer" 877 | }, 878 | { 879 | "name": "Sebastian Heuer", 880 | "email": "sebastian@phpeople.de", 881 | "role": "Developer" 882 | }, 883 | { 884 | "name": "Sebastian Bergmann", 885 | "email": "sebastian@phpunit.de", 886 | "role": "Developer" 887 | } 888 | ], 889 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", 890 | "time": "2018-07-08T19:23:20+00:00" 891 | }, 892 | { 893 | "name": "phar-io/version", 894 | "version": "2.0.1", 895 | "source": { 896 | "type": "git", 897 | "url": "https://github.com/phar-io/version.git", 898 | "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" 899 | }, 900 | "dist": { 901 | "type": "zip", 902 | "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", 903 | "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", 904 | "shasum": "" 905 | }, 906 | "require": { 907 | "php": "^5.6 || ^7.0" 908 | }, 909 | "type": "library", 910 | "autoload": { 911 | "classmap": [ 912 | "src/" 913 | ] 914 | }, 915 | "notification-url": "https://packagist.org/downloads/", 916 | "license": [ 917 | "BSD-3-Clause" 918 | ], 919 | "authors": [ 920 | { 921 | "name": "Arne Blankerts", 922 | "email": "arne@blankerts.de", 923 | "role": "Developer" 924 | }, 925 | { 926 | "name": "Sebastian Heuer", 927 | "email": "sebastian@phpeople.de", 928 | "role": "Developer" 929 | }, 930 | { 931 | "name": "Sebastian Bergmann", 932 | "email": "sebastian@phpunit.de", 933 | "role": "Developer" 934 | } 935 | ], 936 | "description": "Library for handling version information and constraints", 937 | "time": "2018-07-08T19:19:57+00:00" 938 | }, 939 | { 940 | "name": "phpdocumentor/reflection-common", 941 | "version": "1.0.1", 942 | "source": { 943 | "type": "git", 944 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 945 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" 946 | }, 947 | "dist": { 948 | "type": "zip", 949 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 950 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 951 | "shasum": "" 952 | }, 953 | "require": { 954 | "php": ">=5.5" 955 | }, 956 | "require-dev": { 957 | "phpunit/phpunit": "^4.6" 958 | }, 959 | "type": "library", 960 | "extra": { 961 | "branch-alias": { 962 | "dev-master": "1.0.x-dev" 963 | } 964 | }, 965 | "autoload": { 966 | "psr-4": { 967 | "phpDocumentor\\Reflection\\": [ 968 | "src" 969 | ] 970 | } 971 | }, 972 | "notification-url": "https://packagist.org/downloads/", 973 | "license": [ 974 | "MIT" 975 | ], 976 | "authors": [ 977 | { 978 | "name": "Jaap van Otterdijk", 979 | "email": "opensource@ijaap.nl" 980 | } 981 | ], 982 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 983 | "homepage": "http://www.phpdoc.org", 984 | "keywords": [ 985 | "FQSEN", 986 | "phpDocumentor", 987 | "phpdoc", 988 | "reflection", 989 | "static analysis" 990 | ], 991 | "time": "2017-09-11T18:02:19+00:00" 992 | }, 993 | { 994 | "name": "phpdocumentor/reflection-docblock", 995 | "version": "4.3.0", 996 | "source": { 997 | "type": "git", 998 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 999 | "reference": "94fd0001232e47129dd3504189fa1c7225010d08" 1000 | }, 1001 | "dist": { 1002 | "type": "zip", 1003 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", 1004 | "reference": "94fd0001232e47129dd3504189fa1c7225010d08", 1005 | "shasum": "" 1006 | }, 1007 | "require": { 1008 | "php": "^7.0", 1009 | "phpdocumentor/reflection-common": "^1.0.0", 1010 | "phpdocumentor/type-resolver": "^0.4.0", 1011 | "webmozart/assert": "^1.0" 1012 | }, 1013 | "require-dev": { 1014 | "doctrine/instantiator": "~1.0.5", 1015 | "mockery/mockery": "^1.0", 1016 | "phpunit/phpunit": "^6.4" 1017 | }, 1018 | "type": "library", 1019 | "extra": { 1020 | "branch-alias": { 1021 | "dev-master": "4.x-dev" 1022 | } 1023 | }, 1024 | "autoload": { 1025 | "psr-4": { 1026 | "phpDocumentor\\Reflection\\": [ 1027 | "src/" 1028 | ] 1029 | } 1030 | }, 1031 | "notification-url": "https://packagist.org/downloads/", 1032 | "license": [ 1033 | "MIT" 1034 | ], 1035 | "authors": [ 1036 | { 1037 | "name": "Mike van Riel", 1038 | "email": "me@mikevanriel.com" 1039 | } 1040 | ], 1041 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 1042 | "time": "2017-11-30T07:14:17+00:00" 1043 | }, 1044 | { 1045 | "name": "phpdocumentor/type-resolver", 1046 | "version": "0.4.0", 1047 | "source": { 1048 | "type": "git", 1049 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 1050 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" 1051 | }, 1052 | "dist": { 1053 | "type": "zip", 1054 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", 1055 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", 1056 | "shasum": "" 1057 | }, 1058 | "require": { 1059 | "php": "^5.5 || ^7.0", 1060 | "phpdocumentor/reflection-common": "^1.0" 1061 | }, 1062 | "require-dev": { 1063 | "mockery/mockery": "^0.9.4", 1064 | "phpunit/phpunit": "^5.2||^4.8.24" 1065 | }, 1066 | "type": "library", 1067 | "extra": { 1068 | "branch-alias": { 1069 | "dev-master": "1.0.x-dev" 1070 | } 1071 | }, 1072 | "autoload": { 1073 | "psr-4": { 1074 | "phpDocumentor\\Reflection\\": [ 1075 | "src/" 1076 | ] 1077 | } 1078 | }, 1079 | "notification-url": "https://packagist.org/downloads/", 1080 | "license": [ 1081 | "MIT" 1082 | ], 1083 | "authors": [ 1084 | { 1085 | "name": "Mike van Riel", 1086 | "email": "me@mikevanriel.com" 1087 | } 1088 | ], 1089 | "time": "2017-07-14T14:27:02+00:00" 1090 | }, 1091 | { 1092 | "name": "phpspec/prophecy", 1093 | "version": "1.8.0", 1094 | "source": { 1095 | "type": "git", 1096 | "url": "https://github.com/phpspec/prophecy.git", 1097 | "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" 1098 | }, 1099 | "dist": { 1100 | "type": "zip", 1101 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", 1102 | "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", 1103 | "shasum": "" 1104 | }, 1105 | "require": { 1106 | "doctrine/instantiator": "^1.0.2", 1107 | "php": "^5.3|^7.0", 1108 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", 1109 | "sebastian/comparator": "^1.1|^2.0|^3.0", 1110 | "sebastian/recursion-context": "^1.0|^2.0|^3.0" 1111 | }, 1112 | "require-dev": { 1113 | "phpspec/phpspec": "^2.5|^3.2", 1114 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" 1115 | }, 1116 | "type": "library", 1117 | "extra": { 1118 | "branch-alias": { 1119 | "dev-master": "1.8.x-dev" 1120 | } 1121 | }, 1122 | "autoload": { 1123 | "psr-0": { 1124 | "Prophecy\\": "src/" 1125 | } 1126 | }, 1127 | "notification-url": "https://packagist.org/downloads/", 1128 | "license": [ 1129 | "MIT" 1130 | ], 1131 | "authors": [ 1132 | { 1133 | "name": "Konstantin Kudryashov", 1134 | "email": "ever.zet@gmail.com", 1135 | "homepage": "http://everzet.com" 1136 | }, 1137 | { 1138 | "name": "Marcello Duarte", 1139 | "email": "marcello.duarte@gmail.com" 1140 | } 1141 | ], 1142 | "description": "Highly opinionated mocking framework for PHP 5.3+", 1143 | "homepage": "https://github.com/phpspec/prophecy", 1144 | "keywords": [ 1145 | "Double", 1146 | "Dummy", 1147 | "fake", 1148 | "mock", 1149 | "spy", 1150 | "stub" 1151 | ], 1152 | "time": "2018-08-05T17:53:17+00:00" 1153 | }, 1154 | { 1155 | "name": "phpstan/phpdoc-parser", 1156 | "version": "0.3.1", 1157 | "source": { 1158 | "type": "git", 1159 | "url": "https://github.com/phpstan/phpdoc-parser.git", 1160 | "reference": "2cc49f47c69b023eaf05b48e6529389893b13d74" 1161 | }, 1162 | "dist": { 1163 | "type": "zip", 1164 | "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/2cc49f47c69b023eaf05b48e6529389893b13d74", 1165 | "reference": "2cc49f47c69b023eaf05b48e6529389893b13d74", 1166 | "shasum": "" 1167 | }, 1168 | "require": { 1169 | "php": "~7.1" 1170 | }, 1171 | "require-dev": { 1172 | "consistence/coding-standard": "^2.0.0", 1173 | "jakub-onderka/php-parallel-lint": "^0.9.2", 1174 | "phing/phing": "^2.16.0", 1175 | "phpstan/phpstan": "^0.10", 1176 | "phpunit/phpunit": "^6.3", 1177 | "slevomat/coding-standard": "^3.3.0", 1178 | "symfony/process": "^3.4 || ^4.0" 1179 | }, 1180 | "type": "library", 1181 | "extra": { 1182 | "branch-alias": { 1183 | "dev-master": "0.3-dev" 1184 | } 1185 | }, 1186 | "autoload": { 1187 | "psr-4": { 1188 | "PHPStan\\PhpDocParser\\": [ 1189 | "src/" 1190 | ] 1191 | } 1192 | }, 1193 | "notification-url": "https://packagist.org/downloads/", 1194 | "license": [ 1195 | "MIT" 1196 | ], 1197 | "description": "PHPDoc parser with support for nullable, intersection and generic types", 1198 | "time": "2019-01-14T12:26:23+00:00" 1199 | }, 1200 | { 1201 | "name": "phpstan/phpstan", 1202 | "version": "0.11.1", 1203 | "source": { 1204 | "type": "git", 1205 | "url": "https://github.com/phpstan/phpstan.git", 1206 | "reference": "a138b8a2731b2c19f1dffa2f1411984a638fe977" 1207 | }, 1208 | "dist": { 1209 | "type": "zip", 1210 | "url": "https://api.github.com/repos/phpstan/phpstan/zipball/a138b8a2731b2c19f1dffa2f1411984a638fe977", 1211 | "reference": "a138b8a2731b2c19f1dffa2f1411984a638fe977", 1212 | "shasum": "" 1213 | }, 1214 | "require": { 1215 | "composer/xdebug-handler": "^1.3.0", 1216 | "jean85/pretty-package-versions": "^1.0.3", 1217 | "nette/bootstrap": "^2.4 || ^3.0", 1218 | "nette/di": "^2.4.7 || ^3.0", 1219 | "nette/robot-loader": "^3.0.1", 1220 | "nette/utils": "^2.4.5 || ^3.0", 1221 | "nikic/php-parser": "^4.0.2", 1222 | "php": "~7.1", 1223 | "phpstan/phpdoc-parser": "^0.3", 1224 | "symfony/console": "~3.2 || ~4.0", 1225 | "symfony/finder": "~3.2 || ~4.0" 1226 | }, 1227 | "conflict": { 1228 | "symfony/console": "3.4.16 || 4.1.5" 1229 | }, 1230 | "require-dev": { 1231 | "brianium/paratest": "^2.0", 1232 | "consistence/coding-standard": "^3.5", 1233 | "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", 1234 | "ext-intl": "*", 1235 | "ext-mysqli": "*", 1236 | "ext-soap": "*", 1237 | "ext-zip": "*", 1238 | "jakub-onderka/php-parallel-lint": "^1.0", 1239 | "localheinz/composer-normalize": "^1.1.0", 1240 | "phing/phing": "^2.16.0", 1241 | "phpstan/phpstan-deprecation-rules": "^0.11", 1242 | "phpstan/phpstan-php-parser": "^0.11", 1243 | "phpstan/phpstan-phpunit": "^0.11", 1244 | "phpstan/phpstan-strict-rules": "^0.11", 1245 | "phpunit/phpunit": "^7.0", 1246 | "slevomat/coding-standard": "^4.7.2", 1247 | "squizlabs/php_codesniffer": "^3.3.2" 1248 | }, 1249 | "bin": [ 1250 | "bin/phpstan" 1251 | ], 1252 | "type": "library", 1253 | "extra": { 1254 | "branch-alias": { 1255 | "dev-master": "0.11-dev" 1256 | } 1257 | }, 1258 | "autoload": { 1259 | "psr-4": { 1260 | "PHPStan\\": [ 1261 | "src/", 1262 | "build/PHPStan" 1263 | ] 1264 | } 1265 | }, 1266 | "notification-url": "https://packagist.org/downloads/", 1267 | "license": [ 1268 | "MIT" 1269 | ], 1270 | "description": "PHPStan - PHP Static Analysis Tool", 1271 | "time": "2019-01-19T20:23:08+00:00" 1272 | }, 1273 | { 1274 | "name": "phpunit/php-code-coverage", 1275 | "version": "6.1.4", 1276 | "source": { 1277 | "type": "git", 1278 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 1279 | "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" 1280 | }, 1281 | "dist": { 1282 | "type": "zip", 1283 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", 1284 | "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", 1285 | "shasum": "" 1286 | }, 1287 | "require": { 1288 | "ext-dom": "*", 1289 | "ext-xmlwriter": "*", 1290 | "php": "^7.1", 1291 | "phpunit/php-file-iterator": "^2.0", 1292 | "phpunit/php-text-template": "^1.2.1", 1293 | "phpunit/php-token-stream": "^3.0", 1294 | "sebastian/code-unit-reverse-lookup": "^1.0.1", 1295 | "sebastian/environment": "^3.1 || ^4.0", 1296 | "sebastian/version": "^2.0.1", 1297 | "theseer/tokenizer": "^1.1" 1298 | }, 1299 | "require-dev": { 1300 | "phpunit/phpunit": "^7.0" 1301 | }, 1302 | "suggest": { 1303 | "ext-xdebug": "^2.6.0" 1304 | }, 1305 | "type": "library", 1306 | "extra": { 1307 | "branch-alias": { 1308 | "dev-master": "6.1-dev" 1309 | } 1310 | }, 1311 | "autoload": { 1312 | "classmap": [ 1313 | "src/" 1314 | ] 1315 | }, 1316 | "notification-url": "https://packagist.org/downloads/", 1317 | "license": [ 1318 | "BSD-3-Clause" 1319 | ], 1320 | "authors": [ 1321 | { 1322 | "name": "Sebastian Bergmann", 1323 | "email": "sebastian@phpunit.de", 1324 | "role": "lead" 1325 | } 1326 | ], 1327 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 1328 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 1329 | "keywords": [ 1330 | "coverage", 1331 | "testing", 1332 | "xunit" 1333 | ], 1334 | "time": "2018-10-31T16:06:48+00:00" 1335 | }, 1336 | { 1337 | "name": "phpunit/php-file-iterator", 1338 | "version": "2.0.2", 1339 | "source": { 1340 | "type": "git", 1341 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 1342 | "reference": "050bedf145a257b1ff02746c31894800e5122946" 1343 | }, 1344 | "dist": { 1345 | "type": "zip", 1346 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", 1347 | "reference": "050bedf145a257b1ff02746c31894800e5122946", 1348 | "shasum": "" 1349 | }, 1350 | "require": { 1351 | "php": "^7.1" 1352 | }, 1353 | "require-dev": { 1354 | "phpunit/phpunit": "^7.1" 1355 | }, 1356 | "type": "library", 1357 | "extra": { 1358 | "branch-alias": { 1359 | "dev-master": "2.0.x-dev" 1360 | } 1361 | }, 1362 | "autoload": { 1363 | "classmap": [ 1364 | "src/" 1365 | ] 1366 | }, 1367 | "notification-url": "https://packagist.org/downloads/", 1368 | "license": [ 1369 | "BSD-3-Clause" 1370 | ], 1371 | "authors": [ 1372 | { 1373 | "name": "Sebastian Bergmann", 1374 | "email": "sebastian@phpunit.de", 1375 | "role": "lead" 1376 | } 1377 | ], 1378 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 1379 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 1380 | "keywords": [ 1381 | "filesystem", 1382 | "iterator" 1383 | ], 1384 | "time": "2018-09-13T20:33:42+00:00" 1385 | }, 1386 | { 1387 | "name": "phpunit/php-text-template", 1388 | "version": "1.2.1", 1389 | "source": { 1390 | "type": "git", 1391 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 1392 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 1393 | }, 1394 | "dist": { 1395 | "type": "zip", 1396 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 1397 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 1398 | "shasum": "" 1399 | }, 1400 | "require": { 1401 | "php": ">=5.3.3" 1402 | }, 1403 | "type": "library", 1404 | "autoload": { 1405 | "classmap": [ 1406 | "src/" 1407 | ] 1408 | }, 1409 | "notification-url": "https://packagist.org/downloads/", 1410 | "license": [ 1411 | "BSD-3-Clause" 1412 | ], 1413 | "authors": [ 1414 | { 1415 | "name": "Sebastian Bergmann", 1416 | "email": "sebastian@phpunit.de", 1417 | "role": "lead" 1418 | } 1419 | ], 1420 | "description": "Simple template engine.", 1421 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 1422 | "keywords": [ 1423 | "template" 1424 | ], 1425 | "time": "2015-06-21T13:50:34+00:00" 1426 | }, 1427 | { 1428 | "name": "phpunit/php-timer", 1429 | "version": "2.0.0", 1430 | "source": { 1431 | "type": "git", 1432 | "url": "https://github.com/sebastianbergmann/php-timer.git", 1433 | "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f" 1434 | }, 1435 | "dist": { 1436 | "type": "zip", 1437 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f", 1438 | "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f", 1439 | "shasum": "" 1440 | }, 1441 | "require": { 1442 | "php": "^7.1" 1443 | }, 1444 | "require-dev": { 1445 | "phpunit/phpunit": "^7.0" 1446 | }, 1447 | "type": "library", 1448 | "extra": { 1449 | "branch-alias": { 1450 | "dev-master": "2.0-dev" 1451 | } 1452 | }, 1453 | "autoload": { 1454 | "classmap": [ 1455 | "src/" 1456 | ] 1457 | }, 1458 | "notification-url": "https://packagist.org/downloads/", 1459 | "license": [ 1460 | "BSD-3-Clause" 1461 | ], 1462 | "authors": [ 1463 | { 1464 | "name": "Sebastian Bergmann", 1465 | "email": "sebastian@phpunit.de", 1466 | "role": "lead" 1467 | } 1468 | ], 1469 | "description": "Utility class for timing", 1470 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 1471 | "keywords": [ 1472 | "timer" 1473 | ], 1474 | "time": "2018-02-01T13:07:23+00:00" 1475 | }, 1476 | { 1477 | "name": "phpunit/php-token-stream", 1478 | "version": "3.0.1", 1479 | "source": { 1480 | "type": "git", 1481 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 1482 | "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18" 1483 | }, 1484 | "dist": { 1485 | "type": "zip", 1486 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18", 1487 | "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18", 1488 | "shasum": "" 1489 | }, 1490 | "require": { 1491 | "ext-tokenizer": "*", 1492 | "php": "^7.1" 1493 | }, 1494 | "require-dev": { 1495 | "phpunit/phpunit": "^7.0" 1496 | }, 1497 | "type": "library", 1498 | "extra": { 1499 | "branch-alias": { 1500 | "dev-master": "3.0-dev" 1501 | } 1502 | }, 1503 | "autoload": { 1504 | "classmap": [ 1505 | "src/" 1506 | ] 1507 | }, 1508 | "notification-url": "https://packagist.org/downloads/", 1509 | "license": [ 1510 | "BSD-3-Clause" 1511 | ], 1512 | "authors": [ 1513 | { 1514 | "name": "Sebastian Bergmann", 1515 | "email": "sebastian@phpunit.de" 1516 | } 1517 | ], 1518 | "description": "Wrapper around PHP's tokenizer extension.", 1519 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 1520 | "keywords": [ 1521 | "tokenizer" 1522 | ], 1523 | "time": "2018-10-30T05:52:18+00:00" 1524 | }, 1525 | { 1526 | "name": "phpunit/phpunit", 1527 | "version": "7.5.2", 1528 | "source": { 1529 | "type": "git", 1530 | "url": "https://github.com/sebastianbergmann/phpunit.git", 1531 | "reference": "7c89093bd00f7d5ddf0ab81dee04f801416b4944" 1532 | }, 1533 | "dist": { 1534 | "type": "zip", 1535 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7c89093bd00f7d5ddf0ab81dee04f801416b4944", 1536 | "reference": "7c89093bd00f7d5ddf0ab81dee04f801416b4944", 1537 | "shasum": "" 1538 | }, 1539 | "require": { 1540 | "doctrine/instantiator": "^1.1", 1541 | "ext-dom": "*", 1542 | "ext-json": "*", 1543 | "ext-libxml": "*", 1544 | "ext-mbstring": "*", 1545 | "ext-xml": "*", 1546 | "myclabs/deep-copy": "^1.7", 1547 | "phar-io/manifest": "^1.0.2", 1548 | "phar-io/version": "^2.0", 1549 | "php": "^7.1", 1550 | "phpspec/prophecy": "^1.7", 1551 | "phpunit/php-code-coverage": "^6.0.7", 1552 | "phpunit/php-file-iterator": "^2.0.1", 1553 | "phpunit/php-text-template": "^1.2.1", 1554 | "phpunit/php-timer": "^2.0", 1555 | "sebastian/comparator": "^3.0", 1556 | "sebastian/diff": "^3.0", 1557 | "sebastian/environment": "^4.0", 1558 | "sebastian/exporter": "^3.1", 1559 | "sebastian/global-state": "^2.0", 1560 | "sebastian/object-enumerator": "^3.0.3", 1561 | "sebastian/resource-operations": "^2.0", 1562 | "sebastian/version": "^2.0.1" 1563 | }, 1564 | "conflict": { 1565 | "phpunit/phpunit-mock-objects": "*" 1566 | }, 1567 | "require-dev": { 1568 | "ext-pdo": "*" 1569 | }, 1570 | "suggest": { 1571 | "ext-soap": "*", 1572 | "ext-xdebug": "*", 1573 | "phpunit/php-invoker": "^2.0" 1574 | }, 1575 | "bin": [ 1576 | "phpunit" 1577 | ], 1578 | "type": "library", 1579 | "extra": { 1580 | "branch-alias": { 1581 | "dev-master": "7.5-dev" 1582 | } 1583 | }, 1584 | "autoload": { 1585 | "classmap": [ 1586 | "src/" 1587 | ] 1588 | }, 1589 | "notification-url": "https://packagist.org/downloads/", 1590 | "license": [ 1591 | "BSD-3-Clause" 1592 | ], 1593 | "authors": [ 1594 | { 1595 | "name": "Sebastian Bergmann", 1596 | "email": "sebastian@phpunit.de", 1597 | "role": "lead" 1598 | } 1599 | ], 1600 | "description": "The PHP Unit Testing framework.", 1601 | "homepage": "https://phpunit.de/", 1602 | "keywords": [ 1603 | "phpunit", 1604 | "testing", 1605 | "xunit" 1606 | ], 1607 | "time": "2019-01-15T08:19:08+00:00" 1608 | }, 1609 | { 1610 | "name": "psr/log", 1611 | "version": "1.1.0", 1612 | "source": { 1613 | "type": "git", 1614 | "url": "https://github.com/php-fig/log.git", 1615 | "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" 1616 | }, 1617 | "dist": { 1618 | "type": "zip", 1619 | "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", 1620 | "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", 1621 | "shasum": "" 1622 | }, 1623 | "require": { 1624 | "php": ">=5.3.0" 1625 | }, 1626 | "type": "library", 1627 | "extra": { 1628 | "branch-alias": { 1629 | "dev-master": "1.0.x-dev" 1630 | } 1631 | }, 1632 | "autoload": { 1633 | "psr-4": { 1634 | "Psr\\Log\\": "Psr/Log/" 1635 | } 1636 | }, 1637 | "notification-url": "https://packagist.org/downloads/", 1638 | "license": [ 1639 | "MIT" 1640 | ], 1641 | "authors": [ 1642 | { 1643 | "name": "PHP-FIG", 1644 | "homepage": "http://www.php-fig.org/" 1645 | } 1646 | ], 1647 | "description": "Common interface for logging libraries", 1648 | "homepage": "https://github.com/php-fig/log", 1649 | "keywords": [ 1650 | "log", 1651 | "psr", 1652 | "psr-3" 1653 | ], 1654 | "time": "2018-11-20T15:27:04+00:00" 1655 | }, 1656 | { 1657 | "name": "sebastian/code-unit-reverse-lookup", 1658 | "version": "1.0.1", 1659 | "source": { 1660 | "type": "git", 1661 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 1662 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" 1663 | }, 1664 | "dist": { 1665 | "type": "zip", 1666 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 1667 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 1668 | "shasum": "" 1669 | }, 1670 | "require": { 1671 | "php": "^5.6 || ^7.0" 1672 | }, 1673 | "require-dev": { 1674 | "phpunit/phpunit": "^5.7 || ^6.0" 1675 | }, 1676 | "type": "library", 1677 | "extra": { 1678 | "branch-alias": { 1679 | "dev-master": "1.0.x-dev" 1680 | } 1681 | }, 1682 | "autoload": { 1683 | "classmap": [ 1684 | "src/" 1685 | ] 1686 | }, 1687 | "notification-url": "https://packagist.org/downloads/", 1688 | "license": [ 1689 | "BSD-3-Clause" 1690 | ], 1691 | "authors": [ 1692 | { 1693 | "name": "Sebastian Bergmann", 1694 | "email": "sebastian@phpunit.de" 1695 | } 1696 | ], 1697 | "description": "Looks up which function or method a line of code belongs to", 1698 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 1699 | "time": "2017-03-04T06:30:41+00:00" 1700 | }, 1701 | { 1702 | "name": "sebastian/comparator", 1703 | "version": "3.0.2", 1704 | "source": { 1705 | "type": "git", 1706 | "url": "https://github.com/sebastianbergmann/comparator.git", 1707 | "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" 1708 | }, 1709 | "dist": { 1710 | "type": "zip", 1711 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", 1712 | "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", 1713 | "shasum": "" 1714 | }, 1715 | "require": { 1716 | "php": "^7.1", 1717 | "sebastian/diff": "^3.0", 1718 | "sebastian/exporter": "^3.1" 1719 | }, 1720 | "require-dev": { 1721 | "phpunit/phpunit": "^7.1" 1722 | }, 1723 | "type": "library", 1724 | "extra": { 1725 | "branch-alias": { 1726 | "dev-master": "3.0-dev" 1727 | } 1728 | }, 1729 | "autoload": { 1730 | "classmap": [ 1731 | "src/" 1732 | ] 1733 | }, 1734 | "notification-url": "https://packagist.org/downloads/", 1735 | "license": [ 1736 | "BSD-3-Clause" 1737 | ], 1738 | "authors": [ 1739 | { 1740 | "name": "Jeff Welch", 1741 | "email": "whatthejeff@gmail.com" 1742 | }, 1743 | { 1744 | "name": "Volker Dusch", 1745 | "email": "github@wallbash.com" 1746 | }, 1747 | { 1748 | "name": "Bernhard Schussek", 1749 | "email": "bschussek@2bepublished.at" 1750 | }, 1751 | { 1752 | "name": "Sebastian Bergmann", 1753 | "email": "sebastian@phpunit.de" 1754 | } 1755 | ], 1756 | "description": "Provides the functionality to compare PHP values for equality", 1757 | "homepage": "https://github.com/sebastianbergmann/comparator", 1758 | "keywords": [ 1759 | "comparator", 1760 | "compare", 1761 | "equality" 1762 | ], 1763 | "time": "2018-07-12T15:12:46+00:00" 1764 | }, 1765 | { 1766 | "name": "sebastian/diff", 1767 | "version": "3.0.1", 1768 | "source": { 1769 | "type": "git", 1770 | "url": "https://github.com/sebastianbergmann/diff.git", 1771 | "reference": "366541b989927187c4ca70490a35615d3fef2dce" 1772 | }, 1773 | "dist": { 1774 | "type": "zip", 1775 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/366541b989927187c4ca70490a35615d3fef2dce", 1776 | "reference": "366541b989927187c4ca70490a35615d3fef2dce", 1777 | "shasum": "" 1778 | }, 1779 | "require": { 1780 | "php": "^7.1" 1781 | }, 1782 | "require-dev": { 1783 | "phpunit/phpunit": "^7.0", 1784 | "symfony/process": "^2 || ^3.3 || ^4" 1785 | }, 1786 | "type": "library", 1787 | "extra": { 1788 | "branch-alias": { 1789 | "dev-master": "3.0-dev" 1790 | } 1791 | }, 1792 | "autoload": { 1793 | "classmap": [ 1794 | "src/" 1795 | ] 1796 | }, 1797 | "notification-url": "https://packagist.org/downloads/", 1798 | "license": [ 1799 | "BSD-3-Clause" 1800 | ], 1801 | "authors": [ 1802 | { 1803 | "name": "Kore Nordmann", 1804 | "email": "mail@kore-nordmann.de" 1805 | }, 1806 | { 1807 | "name": "Sebastian Bergmann", 1808 | "email": "sebastian@phpunit.de" 1809 | } 1810 | ], 1811 | "description": "Diff implementation", 1812 | "homepage": "https://github.com/sebastianbergmann/diff", 1813 | "keywords": [ 1814 | "diff", 1815 | "udiff", 1816 | "unidiff", 1817 | "unified diff" 1818 | ], 1819 | "time": "2018-06-10T07:54:39+00:00" 1820 | }, 1821 | { 1822 | "name": "sebastian/environment", 1823 | "version": "4.0.1", 1824 | "source": { 1825 | "type": "git", 1826 | "url": "https://github.com/sebastianbergmann/environment.git", 1827 | "reference": "febd209a219cea7b56ad799b30ebbea34b71eb8f" 1828 | }, 1829 | "dist": { 1830 | "type": "zip", 1831 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/febd209a219cea7b56ad799b30ebbea34b71eb8f", 1832 | "reference": "febd209a219cea7b56ad799b30ebbea34b71eb8f", 1833 | "shasum": "" 1834 | }, 1835 | "require": { 1836 | "php": "^7.1" 1837 | }, 1838 | "require-dev": { 1839 | "phpunit/phpunit": "^7.4" 1840 | }, 1841 | "type": "library", 1842 | "extra": { 1843 | "branch-alias": { 1844 | "dev-master": "4.0-dev" 1845 | } 1846 | }, 1847 | "autoload": { 1848 | "classmap": [ 1849 | "src/" 1850 | ] 1851 | }, 1852 | "notification-url": "https://packagist.org/downloads/", 1853 | "license": [ 1854 | "BSD-3-Clause" 1855 | ], 1856 | "authors": [ 1857 | { 1858 | "name": "Sebastian Bergmann", 1859 | "email": "sebastian@phpunit.de" 1860 | } 1861 | ], 1862 | "description": "Provides functionality to handle HHVM/PHP environments", 1863 | "homepage": "http://www.github.com/sebastianbergmann/environment", 1864 | "keywords": [ 1865 | "Xdebug", 1866 | "environment", 1867 | "hhvm" 1868 | ], 1869 | "time": "2018-11-25T09:31:21+00:00" 1870 | }, 1871 | { 1872 | "name": "sebastian/exporter", 1873 | "version": "3.1.0", 1874 | "source": { 1875 | "type": "git", 1876 | "url": "https://github.com/sebastianbergmann/exporter.git", 1877 | "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" 1878 | }, 1879 | "dist": { 1880 | "type": "zip", 1881 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", 1882 | "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", 1883 | "shasum": "" 1884 | }, 1885 | "require": { 1886 | "php": "^7.0", 1887 | "sebastian/recursion-context": "^3.0" 1888 | }, 1889 | "require-dev": { 1890 | "ext-mbstring": "*", 1891 | "phpunit/phpunit": "^6.0" 1892 | }, 1893 | "type": "library", 1894 | "extra": { 1895 | "branch-alias": { 1896 | "dev-master": "3.1.x-dev" 1897 | } 1898 | }, 1899 | "autoload": { 1900 | "classmap": [ 1901 | "src/" 1902 | ] 1903 | }, 1904 | "notification-url": "https://packagist.org/downloads/", 1905 | "license": [ 1906 | "BSD-3-Clause" 1907 | ], 1908 | "authors": [ 1909 | { 1910 | "name": "Jeff Welch", 1911 | "email": "whatthejeff@gmail.com" 1912 | }, 1913 | { 1914 | "name": "Volker Dusch", 1915 | "email": "github@wallbash.com" 1916 | }, 1917 | { 1918 | "name": "Bernhard Schussek", 1919 | "email": "bschussek@2bepublished.at" 1920 | }, 1921 | { 1922 | "name": "Sebastian Bergmann", 1923 | "email": "sebastian@phpunit.de" 1924 | }, 1925 | { 1926 | "name": "Adam Harvey", 1927 | "email": "aharvey@php.net" 1928 | } 1929 | ], 1930 | "description": "Provides the functionality to export PHP variables for visualization", 1931 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 1932 | "keywords": [ 1933 | "export", 1934 | "exporter" 1935 | ], 1936 | "time": "2017-04-03T13:19:02+00:00" 1937 | }, 1938 | { 1939 | "name": "sebastian/global-state", 1940 | "version": "2.0.0", 1941 | "source": { 1942 | "type": "git", 1943 | "url": "https://github.com/sebastianbergmann/global-state.git", 1944 | "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" 1945 | }, 1946 | "dist": { 1947 | "type": "zip", 1948 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", 1949 | "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", 1950 | "shasum": "" 1951 | }, 1952 | "require": { 1953 | "php": "^7.0" 1954 | }, 1955 | "require-dev": { 1956 | "phpunit/phpunit": "^6.0" 1957 | }, 1958 | "suggest": { 1959 | "ext-uopz": "*" 1960 | }, 1961 | "type": "library", 1962 | "extra": { 1963 | "branch-alias": { 1964 | "dev-master": "2.0-dev" 1965 | } 1966 | }, 1967 | "autoload": { 1968 | "classmap": [ 1969 | "src/" 1970 | ] 1971 | }, 1972 | "notification-url": "https://packagist.org/downloads/", 1973 | "license": [ 1974 | "BSD-3-Clause" 1975 | ], 1976 | "authors": [ 1977 | { 1978 | "name": "Sebastian Bergmann", 1979 | "email": "sebastian@phpunit.de" 1980 | } 1981 | ], 1982 | "description": "Snapshotting of global state", 1983 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1984 | "keywords": [ 1985 | "global state" 1986 | ], 1987 | "time": "2017-04-27T15:39:26+00:00" 1988 | }, 1989 | { 1990 | "name": "sebastian/object-enumerator", 1991 | "version": "3.0.3", 1992 | "source": { 1993 | "type": "git", 1994 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1995 | "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" 1996 | }, 1997 | "dist": { 1998 | "type": "zip", 1999 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", 2000 | "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", 2001 | "shasum": "" 2002 | }, 2003 | "require": { 2004 | "php": "^7.0", 2005 | "sebastian/object-reflector": "^1.1.1", 2006 | "sebastian/recursion-context": "^3.0" 2007 | }, 2008 | "require-dev": { 2009 | "phpunit/phpunit": "^6.0" 2010 | }, 2011 | "type": "library", 2012 | "extra": { 2013 | "branch-alias": { 2014 | "dev-master": "3.0.x-dev" 2015 | } 2016 | }, 2017 | "autoload": { 2018 | "classmap": [ 2019 | "src/" 2020 | ] 2021 | }, 2022 | "notification-url": "https://packagist.org/downloads/", 2023 | "license": [ 2024 | "BSD-3-Clause" 2025 | ], 2026 | "authors": [ 2027 | { 2028 | "name": "Sebastian Bergmann", 2029 | "email": "sebastian@phpunit.de" 2030 | } 2031 | ], 2032 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 2033 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 2034 | "time": "2017-08-03T12:35:26+00:00" 2035 | }, 2036 | { 2037 | "name": "sebastian/object-reflector", 2038 | "version": "1.1.1", 2039 | "source": { 2040 | "type": "git", 2041 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 2042 | "reference": "773f97c67f28de00d397be301821b06708fca0be" 2043 | }, 2044 | "dist": { 2045 | "type": "zip", 2046 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", 2047 | "reference": "773f97c67f28de00d397be301821b06708fca0be", 2048 | "shasum": "" 2049 | }, 2050 | "require": { 2051 | "php": "^7.0" 2052 | }, 2053 | "require-dev": { 2054 | "phpunit/phpunit": "^6.0" 2055 | }, 2056 | "type": "library", 2057 | "extra": { 2058 | "branch-alias": { 2059 | "dev-master": "1.1-dev" 2060 | } 2061 | }, 2062 | "autoload": { 2063 | "classmap": [ 2064 | "src/" 2065 | ] 2066 | }, 2067 | "notification-url": "https://packagist.org/downloads/", 2068 | "license": [ 2069 | "BSD-3-Clause" 2070 | ], 2071 | "authors": [ 2072 | { 2073 | "name": "Sebastian Bergmann", 2074 | "email": "sebastian@phpunit.de" 2075 | } 2076 | ], 2077 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 2078 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 2079 | "time": "2017-03-29T09:07:27+00:00" 2080 | }, 2081 | { 2082 | "name": "sebastian/recursion-context", 2083 | "version": "3.0.0", 2084 | "source": { 2085 | "type": "git", 2086 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 2087 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" 2088 | }, 2089 | "dist": { 2090 | "type": "zip", 2091 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", 2092 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", 2093 | "shasum": "" 2094 | }, 2095 | "require": { 2096 | "php": "^7.0" 2097 | }, 2098 | "require-dev": { 2099 | "phpunit/phpunit": "^6.0" 2100 | }, 2101 | "type": "library", 2102 | "extra": { 2103 | "branch-alias": { 2104 | "dev-master": "3.0.x-dev" 2105 | } 2106 | }, 2107 | "autoload": { 2108 | "classmap": [ 2109 | "src/" 2110 | ] 2111 | }, 2112 | "notification-url": "https://packagist.org/downloads/", 2113 | "license": [ 2114 | "BSD-3-Clause" 2115 | ], 2116 | "authors": [ 2117 | { 2118 | "name": "Jeff Welch", 2119 | "email": "whatthejeff@gmail.com" 2120 | }, 2121 | { 2122 | "name": "Sebastian Bergmann", 2123 | "email": "sebastian@phpunit.de" 2124 | }, 2125 | { 2126 | "name": "Adam Harvey", 2127 | "email": "aharvey@php.net" 2128 | } 2129 | ], 2130 | "description": "Provides functionality to recursively process PHP variables", 2131 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 2132 | "time": "2017-03-03T06:23:57+00:00" 2133 | }, 2134 | { 2135 | "name": "sebastian/resource-operations", 2136 | "version": "2.0.1", 2137 | "source": { 2138 | "type": "git", 2139 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 2140 | "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" 2141 | }, 2142 | "dist": { 2143 | "type": "zip", 2144 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", 2145 | "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", 2146 | "shasum": "" 2147 | }, 2148 | "require": { 2149 | "php": "^7.1" 2150 | }, 2151 | "type": "library", 2152 | "extra": { 2153 | "branch-alias": { 2154 | "dev-master": "2.0-dev" 2155 | } 2156 | }, 2157 | "autoload": { 2158 | "classmap": [ 2159 | "src/" 2160 | ] 2161 | }, 2162 | "notification-url": "https://packagist.org/downloads/", 2163 | "license": [ 2164 | "BSD-3-Clause" 2165 | ], 2166 | "authors": [ 2167 | { 2168 | "name": "Sebastian Bergmann", 2169 | "email": "sebastian@phpunit.de" 2170 | } 2171 | ], 2172 | "description": "Provides a list of PHP built-in functions that operate on resources", 2173 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 2174 | "time": "2018-10-04T04:07:39+00:00" 2175 | }, 2176 | { 2177 | "name": "sebastian/version", 2178 | "version": "2.0.1", 2179 | "source": { 2180 | "type": "git", 2181 | "url": "https://github.com/sebastianbergmann/version.git", 2182 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" 2183 | }, 2184 | "dist": { 2185 | "type": "zip", 2186 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", 2187 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", 2188 | "shasum": "" 2189 | }, 2190 | "require": { 2191 | "php": ">=5.6" 2192 | }, 2193 | "type": "library", 2194 | "extra": { 2195 | "branch-alias": { 2196 | "dev-master": "2.0.x-dev" 2197 | } 2198 | }, 2199 | "autoload": { 2200 | "classmap": [ 2201 | "src/" 2202 | ] 2203 | }, 2204 | "notification-url": "https://packagist.org/downloads/", 2205 | "license": [ 2206 | "BSD-3-Clause" 2207 | ], 2208 | "authors": [ 2209 | { 2210 | "name": "Sebastian Bergmann", 2211 | "email": "sebastian@phpunit.de", 2212 | "role": "lead" 2213 | } 2214 | ], 2215 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 2216 | "homepage": "https://github.com/sebastianbergmann/version", 2217 | "time": "2016-10-03T07:35:21+00:00" 2218 | }, 2219 | { 2220 | "name": "squizlabs/php_codesniffer", 2221 | "version": "3.4.0", 2222 | "source": { 2223 | "type": "git", 2224 | "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", 2225 | "reference": "379deb987e26c7cd103a7b387aea178baec96e48" 2226 | }, 2227 | "dist": { 2228 | "type": "zip", 2229 | "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/379deb987e26c7cd103a7b387aea178baec96e48", 2230 | "reference": "379deb987e26c7cd103a7b387aea178baec96e48", 2231 | "shasum": "" 2232 | }, 2233 | "require": { 2234 | "ext-simplexml": "*", 2235 | "ext-tokenizer": "*", 2236 | "ext-xmlwriter": "*", 2237 | "php": ">=5.4.0" 2238 | }, 2239 | "require-dev": { 2240 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" 2241 | }, 2242 | "bin": [ 2243 | "bin/phpcs", 2244 | "bin/phpcbf" 2245 | ], 2246 | "type": "library", 2247 | "extra": { 2248 | "branch-alias": { 2249 | "dev-master": "3.x-dev" 2250 | } 2251 | }, 2252 | "notification-url": "https://packagist.org/downloads/", 2253 | "license": [ 2254 | "BSD-3-Clause" 2255 | ], 2256 | "authors": [ 2257 | { 2258 | "name": "Greg Sherwood", 2259 | "role": "lead" 2260 | } 2261 | ], 2262 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", 2263 | "homepage": "http://www.squizlabs.com/php-codesniffer", 2264 | "keywords": [ 2265 | "phpcs", 2266 | "standards" 2267 | ], 2268 | "time": "2018-12-19T23:57:18+00:00" 2269 | }, 2270 | { 2271 | "name": "symfony/console", 2272 | "version": "v4.2.2", 2273 | "source": { 2274 | "type": "git", 2275 | "url": "https://github.com/symfony/console.git", 2276 | "reference": "b0a03c1bb0fcbe288629956cf2f1dd3f1dc97522" 2277 | }, 2278 | "dist": { 2279 | "type": "zip", 2280 | "url": "https://api.github.com/repos/symfony/console/zipball/b0a03c1bb0fcbe288629956cf2f1dd3f1dc97522", 2281 | "reference": "b0a03c1bb0fcbe288629956cf2f1dd3f1dc97522", 2282 | "shasum": "" 2283 | }, 2284 | "require": { 2285 | "php": "^7.1.3", 2286 | "symfony/contracts": "^1.0", 2287 | "symfony/polyfill-mbstring": "~1.0" 2288 | }, 2289 | "conflict": { 2290 | "symfony/dependency-injection": "<3.4", 2291 | "symfony/process": "<3.3" 2292 | }, 2293 | "require-dev": { 2294 | "psr/log": "~1.0", 2295 | "symfony/config": "~3.4|~4.0", 2296 | "symfony/dependency-injection": "~3.4|~4.0", 2297 | "symfony/event-dispatcher": "~3.4|~4.0", 2298 | "symfony/lock": "~3.4|~4.0", 2299 | "symfony/process": "~3.4|~4.0" 2300 | }, 2301 | "suggest": { 2302 | "psr/log-implementation": "For using the console logger", 2303 | "symfony/event-dispatcher": "", 2304 | "symfony/lock": "", 2305 | "symfony/process": "" 2306 | }, 2307 | "type": "library", 2308 | "extra": { 2309 | "branch-alias": { 2310 | "dev-master": "4.2-dev" 2311 | } 2312 | }, 2313 | "autoload": { 2314 | "psr-4": { 2315 | "Symfony\\Component\\Console\\": "" 2316 | }, 2317 | "exclude-from-classmap": [ 2318 | "/Tests/" 2319 | ] 2320 | }, 2321 | "notification-url": "https://packagist.org/downloads/", 2322 | "license": [ 2323 | "MIT" 2324 | ], 2325 | "authors": [ 2326 | { 2327 | "name": "Fabien Potencier", 2328 | "email": "fabien@symfony.com" 2329 | }, 2330 | { 2331 | "name": "Symfony Community", 2332 | "homepage": "https://symfony.com/contributors" 2333 | } 2334 | ], 2335 | "description": "Symfony Console Component", 2336 | "homepage": "https://symfony.com", 2337 | "time": "2019-01-04T15:13:53+00:00" 2338 | }, 2339 | { 2340 | "name": "symfony/contracts", 2341 | "version": "v1.0.2", 2342 | "source": { 2343 | "type": "git", 2344 | "url": "https://github.com/symfony/contracts.git", 2345 | "reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf" 2346 | }, 2347 | "dist": { 2348 | "type": "zip", 2349 | "url": "https://api.github.com/repos/symfony/contracts/zipball/1aa7ab2429c3d594dd70689604b5cf7421254cdf", 2350 | "reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf", 2351 | "shasum": "" 2352 | }, 2353 | "require": { 2354 | "php": "^7.1.3" 2355 | }, 2356 | "require-dev": { 2357 | "psr/cache": "^1.0", 2358 | "psr/container": "^1.0" 2359 | }, 2360 | "suggest": { 2361 | "psr/cache": "When using the Cache contracts", 2362 | "psr/container": "When using the Service contracts", 2363 | "symfony/cache-contracts-implementation": "", 2364 | "symfony/service-contracts-implementation": "", 2365 | "symfony/translation-contracts-implementation": "" 2366 | }, 2367 | "type": "library", 2368 | "extra": { 2369 | "branch-alias": { 2370 | "dev-master": "1.0-dev" 2371 | } 2372 | }, 2373 | "autoload": { 2374 | "psr-4": { 2375 | "Symfony\\Contracts\\": "" 2376 | }, 2377 | "exclude-from-classmap": [ 2378 | "**/Tests/" 2379 | ] 2380 | }, 2381 | "notification-url": "https://packagist.org/downloads/", 2382 | "license": [ 2383 | "MIT" 2384 | ], 2385 | "authors": [ 2386 | { 2387 | "name": "Nicolas Grekas", 2388 | "email": "p@tchwork.com" 2389 | }, 2390 | { 2391 | "name": "Symfony Community", 2392 | "homepage": "https://symfony.com/contributors" 2393 | } 2394 | ], 2395 | "description": "A set of abstractions extracted out of the Symfony components", 2396 | "homepage": "https://symfony.com", 2397 | "keywords": [ 2398 | "abstractions", 2399 | "contracts", 2400 | "decoupling", 2401 | "interfaces", 2402 | "interoperability", 2403 | "standards" 2404 | ], 2405 | "time": "2018-12-05T08:06:11+00:00" 2406 | }, 2407 | { 2408 | "name": "symfony/finder", 2409 | "version": "v4.2.2", 2410 | "source": { 2411 | "type": "git", 2412 | "url": "https://github.com/symfony/finder.git", 2413 | "reference": "9094d69e8c6ee3fe186a0ec5a4f1401e506071ce" 2414 | }, 2415 | "dist": { 2416 | "type": "zip", 2417 | "url": "https://api.github.com/repos/symfony/finder/zipball/9094d69e8c6ee3fe186a0ec5a4f1401e506071ce", 2418 | "reference": "9094d69e8c6ee3fe186a0ec5a4f1401e506071ce", 2419 | "shasum": "" 2420 | }, 2421 | "require": { 2422 | "php": "^7.1.3" 2423 | }, 2424 | "type": "library", 2425 | "extra": { 2426 | "branch-alias": { 2427 | "dev-master": "4.2-dev" 2428 | } 2429 | }, 2430 | "autoload": { 2431 | "psr-4": { 2432 | "Symfony\\Component\\Finder\\": "" 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 Finder Component", 2453 | "homepage": "https://symfony.com", 2454 | "time": "2019-01-03T09:07:35+00:00" 2455 | }, 2456 | { 2457 | "name": "symfony/polyfill-ctype", 2458 | "version": "v1.10.0", 2459 | "source": { 2460 | "type": "git", 2461 | "url": "https://github.com/symfony/polyfill-ctype.git", 2462 | "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" 2463 | }, 2464 | "dist": { 2465 | "type": "zip", 2466 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", 2467 | "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", 2468 | "shasum": "" 2469 | }, 2470 | "require": { 2471 | "php": ">=5.3.3" 2472 | }, 2473 | "suggest": { 2474 | "ext-ctype": "For best performance" 2475 | }, 2476 | "type": "library", 2477 | "extra": { 2478 | "branch-alias": { 2479 | "dev-master": "1.9-dev" 2480 | } 2481 | }, 2482 | "autoload": { 2483 | "psr-4": { 2484 | "Symfony\\Polyfill\\Ctype\\": "" 2485 | }, 2486 | "files": [ 2487 | "bootstrap.php" 2488 | ] 2489 | }, 2490 | "notification-url": "https://packagist.org/downloads/", 2491 | "license": [ 2492 | "MIT" 2493 | ], 2494 | "authors": [ 2495 | { 2496 | "name": "Symfony Community", 2497 | "homepage": "https://symfony.com/contributors" 2498 | }, 2499 | { 2500 | "name": "Gert de Pagter", 2501 | "email": "backendtea@gmail.com" 2502 | } 2503 | ], 2504 | "description": "Symfony polyfill for ctype functions", 2505 | "homepage": "https://symfony.com", 2506 | "keywords": [ 2507 | "compatibility", 2508 | "ctype", 2509 | "polyfill", 2510 | "portable" 2511 | ], 2512 | "time": "2018-08-06T14:22:27+00:00" 2513 | }, 2514 | { 2515 | "name": "symfony/polyfill-mbstring", 2516 | "version": "v1.10.0", 2517 | "source": { 2518 | "type": "git", 2519 | "url": "https://github.com/symfony/polyfill-mbstring.git", 2520 | "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" 2521 | }, 2522 | "dist": { 2523 | "type": "zip", 2524 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", 2525 | "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", 2526 | "shasum": "" 2527 | }, 2528 | "require": { 2529 | "php": ">=5.3.3" 2530 | }, 2531 | "suggest": { 2532 | "ext-mbstring": "For best performance" 2533 | }, 2534 | "type": "library", 2535 | "extra": { 2536 | "branch-alias": { 2537 | "dev-master": "1.9-dev" 2538 | } 2539 | }, 2540 | "autoload": { 2541 | "psr-4": { 2542 | "Symfony\\Polyfill\\Mbstring\\": "" 2543 | }, 2544 | "files": [ 2545 | "bootstrap.php" 2546 | ] 2547 | }, 2548 | "notification-url": "https://packagist.org/downloads/", 2549 | "license": [ 2550 | "MIT" 2551 | ], 2552 | "authors": [ 2553 | { 2554 | "name": "Nicolas Grekas", 2555 | "email": "p@tchwork.com" 2556 | }, 2557 | { 2558 | "name": "Symfony Community", 2559 | "homepage": "https://symfony.com/contributors" 2560 | } 2561 | ], 2562 | "description": "Symfony polyfill for the Mbstring extension", 2563 | "homepage": "https://symfony.com", 2564 | "keywords": [ 2565 | "compatibility", 2566 | "mbstring", 2567 | "polyfill", 2568 | "portable", 2569 | "shim" 2570 | ], 2571 | "time": "2018-09-21T13:07:52+00:00" 2572 | }, 2573 | { 2574 | "name": "symfony/process", 2575 | "version": "v4.2.2", 2576 | "source": { 2577 | "type": "git", 2578 | "url": "https://github.com/symfony/process.git", 2579 | "reference": "ea043ab5d8ed13b467a9087d81cb876aee7f689a" 2580 | }, 2581 | "dist": { 2582 | "type": "zip", 2583 | "url": "https://api.github.com/repos/symfony/process/zipball/ea043ab5d8ed13b467a9087d81cb876aee7f689a", 2584 | "reference": "ea043ab5d8ed13b467a9087d81cb876aee7f689a", 2585 | "shasum": "" 2586 | }, 2587 | "require": { 2588 | "php": "^7.1.3" 2589 | }, 2590 | "type": "library", 2591 | "extra": { 2592 | "branch-alias": { 2593 | "dev-master": "4.2-dev" 2594 | } 2595 | }, 2596 | "autoload": { 2597 | "psr-4": { 2598 | "Symfony\\Component\\Process\\": "" 2599 | }, 2600 | "exclude-from-classmap": [ 2601 | "/Tests/" 2602 | ] 2603 | }, 2604 | "notification-url": "https://packagist.org/downloads/", 2605 | "license": [ 2606 | "MIT" 2607 | ], 2608 | "authors": [ 2609 | { 2610 | "name": "Fabien Potencier", 2611 | "email": "fabien@symfony.com" 2612 | }, 2613 | { 2614 | "name": "Symfony Community", 2615 | "homepage": "https://symfony.com/contributors" 2616 | } 2617 | ], 2618 | "description": "Symfony Process Component", 2619 | "homepage": "https://symfony.com", 2620 | "time": "2019-01-03T14:48:52+00:00" 2621 | }, 2622 | { 2623 | "name": "symfony/yaml", 2624 | "version": "v4.2.2", 2625 | "source": { 2626 | "type": "git", 2627 | "url": "https://github.com/symfony/yaml.git", 2628 | "reference": "d0aa6c0ea484087927b49fd513383a7d36190ca6" 2629 | }, 2630 | "dist": { 2631 | "type": "zip", 2632 | "url": "https://api.github.com/repos/symfony/yaml/zipball/d0aa6c0ea484087927b49fd513383a7d36190ca6", 2633 | "reference": "d0aa6c0ea484087927b49fd513383a7d36190ca6", 2634 | "shasum": "" 2635 | }, 2636 | "require": { 2637 | "php": "^7.1.3", 2638 | "symfony/polyfill-ctype": "~1.8" 2639 | }, 2640 | "conflict": { 2641 | "symfony/console": "<3.4" 2642 | }, 2643 | "require-dev": { 2644 | "symfony/console": "~3.4|~4.0" 2645 | }, 2646 | "suggest": { 2647 | "symfony/console": "For validating YAML files using the lint command" 2648 | }, 2649 | "type": "library", 2650 | "extra": { 2651 | "branch-alias": { 2652 | "dev-master": "4.2-dev" 2653 | } 2654 | }, 2655 | "autoload": { 2656 | "psr-4": { 2657 | "Symfony\\Component\\Yaml\\": "" 2658 | }, 2659 | "exclude-from-classmap": [ 2660 | "/Tests/" 2661 | ] 2662 | }, 2663 | "notification-url": "https://packagist.org/downloads/", 2664 | "license": [ 2665 | "MIT" 2666 | ], 2667 | "authors": [ 2668 | { 2669 | "name": "Fabien Potencier", 2670 | "email": "fabien@symfony.com" 2671 | }, 2672 | { 2673 | "name": "Symfony Community", 2674 | "homepage": "https://symfony.com/contributors" 2675 | } 2676 | ], 2677 | "description": "Symfony Yaml Component", 2678 | "homepage": "https://symfony.com", 2679 | "time": "2019-01-03T09:07:35+00:00" 2680 | }, 2681 | { 2682 | "name": "theseer/tokenizer", 2683 | "version": "1.1.0", 2684 | "source": { 2685 | "type": "git", 2686 | "url": "https://github.com/theseer/tokenizer.git", 2687 | "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" 2688 | }, 2689 | "dist": { 2690 | "type": "zip", 2691 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", 2692 | "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", 2693 | "shasum": "" 2694 | }, 2695 | "require": { 2696 | "ext-dom": "*", 2697 | "ext-tokenizer": "*", 2698 | "ext-xmlwriter": "*", 2699 | "php": "^7.0" 2700 | }, 2701 | "type": "library", 2702 | "autoload": { 2703 | "classmap": [ 2704 | "src/" 2705 | ] 2706 | }, 2707 | "notification-url": "https://packagist.org/downloads/", 2708 | "license": [ 2709 | "BSD-3-Clause" 2710 | ], 2711 | "authors": [ 2712 | { 2713 | "name": "Arne Blankerts", 2714 | "email": "arne@blankerts.de", 2715 | "role": "Developer" 2716 | } 2717 | ], 2718 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", 2719 | "time": "2017-04-07T12:08:54+00:00" 2720 | }, 2721 | { 2722 | "name": "webmozart/assert", 2723 | "version": "1.4.0", 2724 | "source": { 2725 | "type": "git", 2726 | "url": "https://github.com/webmozart/assert.git", 2727 | "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" 2728 | }, 2729 | "dist": { 2730 | "type": "zip", 2731 | "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", 2732 | "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", 2733 | "shasum": "" 2734 | }, 2735 | "require": { 2736 | "php": "^5.3.3 || ^7.0", 2737 | "symfony/polyfill-ctype": "^1.8" 2738 | }, 2739 | "require-dev": { 2740 | "phpunit/phpunit": "^4.6", 2741 | "sebastian/version": "^1.0.1" 2742 | }, 2743 | "type": "library", 2744 | "extra": { 2745 | "branch-alias": { 2746 | "dev-master": "1.3-dev" 2747 | } 2748 | }, 2749 | "autoload": { 2750 | "psr-4": { 2751 | "Webmozart\\Assert\\": "src/" 2752 | } 2753 | }, 2754 | "notification-url": "https://packagist.org/downloads/", 2755 | "license": [ 2756 | "MIT" 2757 | ], 2758 | "authors": [ 2759 | { 2760 | "name": "Bernhard Schussek", 2761 | "email": "bschussek@gmail.com" 2762 | } 2763 | ], 2764 | "description": "Assertions to validate method input/output with nice error messages.", 2765 | "keywords": [ 2766 | "assert", 2767 | "check", 2768 | "validate" 2769 | ], 2770 | "time": "2018-12-25T11:19:39+00:00" 2771 | } 2772 | ], 2773 | "aliases": [], 2774 | "minimum-stability": "dev", 2775 | "stability-flags": [], 2776 | "prefer-stable": true, 2777 | "prefer-lowest": false, 2778 | "platform": { 2779 | "php": ">=7.1" 2780 | }, 2781 | "platform-dev": [] 2782 | } 2783 | -------------------------------------------------------------------------------- /phpcs.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | The coding standard of php-lodash package 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /phpstan.neon.dist: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 5 3 | paths: 4 | - src 5 | - tests 6 | reportUnmatchedIgnoredErrors: false 7 | ignoreErrors: 8 | - '#Array has 2 duplicate keys with value#' 9 | -------------------------------------------------------------------------------- /src/Traits/Arrays.php: -------------------------------------------------------------------------------- 1 | > [1, 2, 3, 4] 14 | * 15 | * @param array $array original array 16 | * @param mixed $value new item or value to append 17 | * 18 | * @return array 19 | */ 20 | public static function append(array $array = [], $value = null): array 21 | { 22 | $array[] = $value; 23 | 24 | return $array; 25 | } 26 | 27 | /** 28 | * Creates an array with all falsey values removed. The values false, null, 0, "", undefined, and NaN are all 29 | * falsey. 30 | * 31 | * @usage __::compact([0, 1, false, 2, '', 3]); 32 | * >> [1, 2, 3] 33 | * 34 | * @param array $array array to compact 35 | * 36 | * @return array 37 | */ 38 | public static function compact(array $array = []): array 39 | { 40 | $result = []; 41 | 42 | foreach ($array as $value) { 43 | if ($value) { 44 | $result[] = $value; 45 | } 46 | } 47 | 48 | return $result; 49 | } 50 | 51 | 52 | /** 53 | * base flatten 54 | * 55 | * @param array $array 56 | * @param bool $shallow 57 | * @param bool $strict 58 | * @param int $startIndex 59 | * 60 | * @return array 61 | */ 62 | public static function baseFlatten( 63 | array $array, 64 | bool $shallow = false, 65 | bool $strict = true, 66 | int $startIndex = 0 67 | ): array { 68 | $idx = 0; 69 | $output = []; 70 | 71 | foreach ($array as $index => $value) { 72 | if (is_array($value)) { 73 | if (!$shallow) { 74 | $value = static::baseFlatten($value, $shallow, $strict); 75 | } 76 | $j = 0; 77 | $len = count($value); 78 | while ($j < $len) { 79 | $output[$idx++] = $value[$j++]; 80 | } 81 | } else { 82 | if (!$strict) { 83 | $output[$idx++] = $value; 84 | } 85 | } 86 | } 87 | 88 | return $output; 89 | } 90 | 91 | /** 92 | * Flattens a multidimensional array. If you pass shallow, the array will only be flattened a single level. 93 | * 94 | * @usage __::flatten([1, 2, [3, [4]]], [flatten]); 95 | * >> [1, 2, 3, 4] 96 | * 97 | * @param array $array 98 | * @param bool $shallow 99 | * 100 | * @return array 101 | */ 102 | public static function flatten(array $array, bool $shallow = false): array 103 | { 104 | return static::baseFlatten($array, $shallow, false); 105 | } 106 | 107 | /** 108 | * Patches array by xpath. 109 | * 110 | * @usage __::patch( 111 | * ['addr' => ['country' => 'US', 'zip' => 12345]], 112 | * ['/addr/country' => 'CA','/addr/zip' => 54321] 113 | * ); 114 | ** >> ['addr' => ['country' => 'CA', 'zip' => 54321]] 115 | * 116 | * @param array $array The array to patch 117 | * @param array $patches List of new xpath-value pairs 118 | * @param string $parent 119 | * 120 | * @return array Returns patched array 121 | */ 122 | public static function patch(array $array, array $patches, string $parent = ''): array 123 | { 124 | foreach ($array as $key => $value) { 125 | $z = $parent . '/' . $key; 126 | 127 | if (isset($patches[$z])) { 128 | $array[$key] = $patches[$z]; 129 | unset($patches[$z]); 130 | 131 | if (!count($patches)) { 132 | break; 133 | } 134 | } 135 | 136 | if (is_array($value)) { 137 | $array[$key] = static::patch($value, $patches, $z); 138 | } 139 | } 140 | 141 | return $array; 142 | } 143 | 144 | /** 145 | * Prepend item or value to an array 146 | * 147 | * @usage __::prepend([1, 2, 3], 4); 148 | * >> [4, 1, 2, 3] 149 | * 150 | * @param array $array 151 | * @param mixed $value 152 | * 153 | * @return array 154 | */ 155 | public static function prepend(array $array = [], $value = null): array 156 | { 157 | array_unshift($array, $value); 158 | 159 | return $array; 160 | } 161 | 162 | /** 163 | * Generate range of values based on start , end and step 164 | * 165 | * @usage __::range(1, 10, 2); 166 | ** >> [1, 3, 5, 7, 9] 167 | * 168 | * @param int|null $start range start 169 | * @param int|null $stop range end 170 | * @param int $step range step value 171 | * 172 | * @return array range of values 173 | */ 174 | public static function range($start = null, $stop = null, int $step = 1): array 175 | { 176 | if ($stop == null && $start != null) { 177 | $stop = $start; 178 | $start = 1; 179 | } 180 | 181 | return range($start, $stop, $step); 182 | } 183 | 184 | /** 185 | * Generate array of repeated values 186 | * 187 | * @usage __::repeat('foo', 3); 188 | ** >> ['foo', 'foo', 'foo'] 189 | * 190 | * @param string $object The object to repeat. 191 | * @param int $times ow many times has to be repeated. 192 | * 193 | * @return array Returns a new array of filled values. 194 | * 195 | */ 196 | public static function repeat($object = '', int $times = null): array 197 | { 198 | $times = abs($times); 199 | if ($times == null) { 200 | return []; 201 | } 202 | 203 | return array_fill(0, $times, $object); 204 | } 205 | 206 | /** 207 | * Creates an array of elements split into groups the length of size. If array can't be split evenly, the final 208 | * chunk will be the remaining elements. 209 | * 210 | * @usage __::chunk([1, 2, 3, 4, 5], 3); 211 | * >> [[1, 2, 3], [4, 5]] 212 | * 213 | * @param array $array original array 214 | * @param int $size the chunk size 215 | * @param bool $preserveKeys When set to TRUE keys will be preserved. Default is FALSE which will reindex the 216 | * chunk numerically 217 | * 218 | * @return array 219 | */ 220 | public static function chunk(array $array, int $size = 1, bool $preserveKeys = false): array 221 | { 222 | return array_chunk($array, $size, $preserveKeys); 223 | } 224 | 225 | /** 226 | * Creates a slice of array with n elements dropped from the beginning. 227 | * 228 | * @usage __::drop([0, 1, 3], 2); 229 | * >> [3] 230 | * 231 | * @param array $input The array to query. 232 | * @param int $number The number of elements to drop. 233 | * 234 | * @return array 235 | */ 236 | public static function drop(array $input, int $number = 1): array 237 | { 238 | return array_slice($input, $number); 239 | } 240 | 241 | /** 242 | * Shuffle an array ensuring no item remains in the same position. 243 | * 244 | * @usage __::randomize([1, 2, 3]); 245 | * >> [2, 3, 1] 246 | * 247 | * @param array $array original array 248 | * 249 | * @return array 250 | */ 251 | public static function randomize(array $array): array 252 | { 253 | for ($i = 0, $c = count($array); $i < $c - 1; $i++) { 254 | $j = rand($i + 1, $c - 1); 255 | list($array[$i], $array[$j]) = [$array[$j], $array[$i]]; 256 | } 257 | 258 | return $array; 259 | } 260 | 261 | /** 262 | * Search for the index of a value in an array. 263 | * 264 | * @usage __::search(['a', 'b', 'c'], 'b') 265 | * >> 1 266 | * 267 | * @param array $array 268 | * @param string $value 269 | * 270 | * @return mixed 271 | */ 272 | public static function search(array $array, string $value) 273 | { 274 | return array_search($value, $array, true); 275 | } 276 | 277 | /** 278 | * Check if an item is in an array. 279 | * 280 | * @usage __::contains(['a', 'b', 'c'], 'b') 281 | * >> true 282 | * 283 | * @param array $array 284 | * @param string $value 285 | * 286 | * @return bool 287 | */ 288 | public static function contains(array $array, string $value): bool 289 | { 290 | return in_array($value, $array, true); 291 | } 292 | 293 | /** 294 | * Returns the average value of an array. 295 | * 296 | * @usage __::average([1, 2, 3]) 297 | * >> 2 298 | * 299 | * @param array $array The source array 300 | * @param int $decimals The number of decimals to return 301 | * 302 | * @return float The average value 303 | */ 304 | public static function average(array $array, int $decimals = 0): float 305 | { 306 | return round((array_sum($array) / count($array)), $decimals); 307 | } 308 | 309 | /** 310 | * Get the size of an array. 311 | * 312 | * @usage __::size([1, 2, 3]) 313 | * >> 3 314 | * 315 | * @param array $array 316 | * 317 | * @return int 318 | */ 319 | public static function size(array $array) 320 | { 321 | return count($array); 322 | } 323 | 324 | /** 325 | * Clean all falsy values from an array. 326 | * 327 | * @usage __::clean([true, false, 0, 1, 'string', '']) 328 | * >> [true, 1, 'string'] 329 | * 330 | * @param array $array 331 | * 332 | * @return mixed 333 | */ 334 | public static function clean(array $array) 335 | { 336 | return __::filter($array, function ($value) { 337 | return (bool)$value; 338 | }); 339 | } 340 | 341 | /** 342 | * Get a random string from an array. 343 | * 344 | * @usage __::random([1, 2, 3]) 345 | * >> Returns 1, 2 or 3 346 | * 347 | * @param array $array 348 | * @param integer $take 349 | * 350 | * @return mixed 351 | */ 352 | public static function random(array $array, $take = null) 353 | { 354 | if (!$take) { 355 | return $array[array_rand($array)]; 356 | } 357 | shuffle($array); 358 | 359 | return __::first($array, $take); 360 | } 361 | 362 | 363 | /** 364 | * Return an array with all elements found in both input arrays. 365 | * 366 | * @usage __::intersection(["green", "red", "blue"], ["green", "yellow", "red"]) 367 | * >> ["green", "red"] 368 | * 369 | * @param array $a 370 | * @param array $b 371 | * 372 | * @return array 373 | */ 374 | public static function intersection(array $a, array $b): array 375 | { 376 | $a = (array)$a; 377 | $b = (array)$b; 378 | 379 | return array_values(array_intersect($a, $b)); 380 | } 381 | 382 | /** 383 | * Return a boolean flag which indicates whether the two input arrays have any common elements. 384 | * 385 | * @usage __::intersects(["green", "red", "blue"], ["green", "yellow", "red"]) 386 | * >> true 387 | * 388 | * @param array $a 389 | * @param array $b 390 | * 391 | * @return bool 392 | */ 393 | public static function intersects(array $a, array $b): bool 394 | { 395 | $a = (array)$a; 396 | $b = (array)$b; 397 | 398 | return count(self::intersection($a, $b)) > 0; 399 | } 400 | 401 | /** 402 | * Exclude the last X elements from an array 403 | * 404 | * @usage __::initial([1, 2, 3], 1); 405 | * >> [1, 2] 406 | * 407 | * @param array $array 408 | * @param int $to 409 | * 410 | * @return mixed 411 | */ 412 | public static function initial(array $array, int $to = 1) 413 | { 414 | $slice = count($array) - $to; 415 | 416 | return __::first($array, $slice); 417 | } 418 | 419 | /** 420 | * Exclude the first X elements from an array 421 | * 422 | * @usage __::rest([1, 2, 3], 2); 423 | * >> [3] 424 | * 425 | * @param array $array 426 | * @param int $from 427 | * 428 | * @return array 429 | */ 430 | public static function rest(array $array, int $from = 1): array 431 | { 432 | return array_splice($array, $from); 433 | } 434 | 435 | /** 436 | * Sort an array by key. 437 | * 438 | * @usage __::sortKeys(['z' => 0, 'b' => 1, 'r' => 2]) 439 | * >> ['b' => 1, 'r' => 2, 'z' => 0] 440 | * 441 | * @param array $array 442 | * @param string $direction 443 | * 444 | * @return mixed 445 | */ 446 | public static function sortKeys(array $array, string $direction = 'ASC') 447 | { 448 | $direction = (strtolower($direction) === 'desc') ? SORT_DESC : SORT_ASC; 449 | if ($direction === SORT_ASC) { 450 | ksort($array); 451 | } else { 452 | krsort($array); 453 | } 454 | 455 | return $array; 456 | } 457 | 458 | /** 459 | * Remove unwanted values from array 460 | * 461 | * @param array $array 462 | * @param array|string $remove 463 | * @param bool $preserveKeys , set true if you want to preserve the keys. by default false 464 | * 465 | * @usage _::without([1,5=>3,2 => 4,5],2) 466 | * 467 | * @return array 468 | */ 469 | public static function without(array $array, $remove, $preserveKeys = false): array 470 | { 471 | $remove = !is_array($remove) ? [$remove] : $remove; 472 | $result = []; 473 | foreach ($array as $key => $value) { 474 | if (in_array($value, $remove)) { 475 | continue; 476 | } 477 | 478 | if ($preserveKeys) { 479 | $result[$key] = $value; 480 | } else { 481 | $result[] = $value; 482 | } 483 | } 484 | 485 | return $result; 486 | } 487 | } 488 | -------------------------------------------------------------------------------- /src/Traits/Collections.php: -------------------------------------------------------------------------------- 1 | $value) { 26 | if (call_user_func($closure, $value)) { 27 | $result[] = $value; 28 | } 29 | } 30 | 31 | return $result; 32 | } 33 | 34 | return __::compact($array); 35 | } 36 | 37 | /** 38 | * Gets the first element of an array. Passing n returns the first n elements. 39 | * 40 | * @usage __::first([1, 2, 3]); 41 | * >> 1 42 | * 43 | * @param array $array of values 44 | * @param int|null $take number of values to return 45 | * 46 | * @return mixed 47 | */ 48 | public static function first(array $array, $take = null) 49 | { 50 | if (!$take) { 51 | return array_shift($array); 52 | } 53 | 54 | return array_splice($array, 0, $take); 55 | } 56 | 57 | /** 58 | * Get item of an array by index, accepting nested index 59 | * 60 | * @usage __::get(['foo' => ['bar' => 'ter']], 'foo.bar'); 61 | * >> 'ter' 62 | * 63 | * @param array|object $collection array of values 64 | * @param null|string $key key or index 65 | * @param mixed $default default value to return if index not exist 66 | * 67 | * @return mixed 68 | */ 69 | public static function get($collection = [], $key = null, $default = null) 70 | { 71 | if (__::isNull($key)) { 72 | return $collection; 73 | } 74 | 75 | if (!__::isObject($collection) && isset($collection[$key])) { 76 | return $collection[$key]; 77 | } 78 | 79 | foreach (explode('.', $key) as $segment) { 80 | if (__::isObject($collection)) { 81 | if (!isset($collection->{$segment})) { 82 | return $default instanceof Closure ? $default() : $default; 83 | } else { 84 | $collection = $collection->{$segment}; 85 | } 86 | } else { 87 | if (!isset($collection[$segment])) { 88 | return $default instanceof Closure ? $default() : $default; 89 | } else { 90 | $collection = $collection[$segment]; 91 | } 92 | } 93 | } 94 | 95 | return $collection; 96 | } 97 | 98 | /** 99 | * Get last item(s) of an array 100 | * 101 | * @usage __::last([1, 2, 3, 4, 5], 2); 102 | * >> [4, 5] 103 | * 104 | * @param array $array array of values 105 | * @param int|null $take number of returned values 106 | * 107 | * @return mixed 108 | */ 109 | public static function last(array $array, $take = null) 110 | { 111 | if (!$take) { 112 | return array_pop($array); 113 | } 114 | 115 | return array_splice($array, -$take); 116 | } 117 | 118 | /** 119 | * Returns an array of values by mapping each in collection through the iterateFn. The iterateFn is invoked with 120 | * three arguments: (value, index|key, collection). 121 | * 122 | * @usage __::map([1, 2, 3], function($n) { 123 | * return $n * 3; 124 | * }); 125 | * >> [3, 6, 9] 126 | * 127 | * @param array|object $collection The collection of values to map over. 128 | * @param \Closure $iterateFn The function to apply on each value. 129 | * 130 | * @return array 131 | */ 132 | public static function map($collection, Closure $iterateFn): array 133 | { 134 | $result = []; 135 | 136 | __::doForEach($collection, function ($value, $key, $collection) use (&$result, $iterateFn) { 137 | $result[] = $iterateFn($value, $key, $collection); 138 | }); 139 | 140 | return $result; 141 | } 142 | 143 | /** 144 | * Returns the maximum value from the collection. If passed an iterator, max will return max value returned by the 145 | * iterator. 146 | * 147 | * @usage __::max([1, 2, 3]); 148 | * >> 3 149 | * 150 | * @param array $array The array to iterate over 151 | * 152 | * @return mixed Returns the maximum value 153 | */ 154 | public static function max(array $array = []) 155 | { 156 | return max($array); 157 | } 158 | 159 | /** 160 | * Returns the minimum value from the collection. If passed an iterator, min will return min value returned by the 161 | * iterator. 162 | * 163 | * @usage __::min([1, 2, 3]); 164 | * >> 1 165 | * 166 | * @param array $array array of values 167 | * 168 | * @return mixed 169 | */ 170 | public static function min(array $array = []) 171 | { 172 | return min($array); 173 | } 174 | 175 | /** 176 | * Returns an array of values belonging to a given property of each item in a collection. 177 | * 178 | * @usage $a = [ 179 | * ['foo' => 'bar', 'bis' => 'ter' ], 180 | * ['foo' => 'bar2', 'bis' => 'ter2'], 181 | * ]; 182 | * 183 | * __::pluck($a, 'foo'); 184 | * >> ['bar', 'bar2'] 185 | * 186 | * @param array|object $collection array or object that can be converted to array 187 | * @param string $property property name 188 | * 189 | * @return array 190 | */ 191 | public static function pluck($collection, string $property): array 192 | { 193 | $result = array_map(function ($value) use ($property) { 194 | if (is_array($value) && isset($value[$property])) { 195 | return $value[$property]; 196 | } elseif (is_object($value) && isset($value->{$property})) { 197 | return $value->{$property}; 198 | } 199 | foreach (__::split($property, '.') as $segment) { 200 | if (is_object($value)) { 201 | if (isset($value->{$segment})) { 202 | $value = $value->{$segment}; 203 | } else { 204 | return null; 205 | } 206 | } else { 207 | if (isset($value[$segment])) { 208 | $value = $value[$segment]; 209 | } else { 210 | return null; 211 | } 212 | } 213 | } 214 | 215 | return $value; 216 | }, (array)$collection); 217 | 218 | return array_values($result); 219 | } 220 | 221 | 222 | /** 223 | * Return data matching specific key value condition 224 | * 225 | * @usage __::where($a, ['age' => 16]); 226 | * >> [['name' => 'maciej', 'age' => 16]] 227 | * 228 | * @param array $array array of values 229 | * @param array $key condition in format of ['KEY'=>'VALUE'] 230 | * @param bool $keepKeys keep original keys 231 | * 232 | * @return array 233 | */ 234 | public static function where(array $array = [], array $key = [], bool $keepKeys = false): array 235 | { 236 | $result = []; 237 | 238 | foreach ($array as $k => $v) { 239 | $not = false; 240 | 241 | foreach ($key as $j => $w) { 242 | if (__::isArray($w)) { 243 | $inKV = $v[$j] ?? []; 244 | if (count(array_intersect_assoc($w, $inKV)) == 0) { 245 | $not = true; 246 | break; 247 | } 248 | } else { 249 | if (!isset($v[$j]) || $v[$j] != $w) { 250 | $not = true; 251 | break; 252 | } 253 | } 254 | } 255 | 256 | if ($not == false) { 257 | if ($keepKeys) { 258 | $result[$k] = $v; 259 | } else { 260 | $result[] = $v; 261 | } 262 | } 263 | } 264 | 265 | return $result; 266 | } 267 | 268 | /** 269 | * Combines and merge collections provided with each others. 270 | * 271 | * If the collections have common keys, then the last passed keys override the 272 | * previous. If numerical indexes are passed, then last passed indexes override 273 | * the previous. 274 | * 275 | * For a recursive merge, see __::merge. 276 | * 277 | * @usage __::assign(['color' => ['favorite' => 'red', 5], 3], [10, 'color' => ['favorite' => 'green', 'blue']]); 278 | * >> ['color' => ['favorite' => 'green', 'blue'], 10] 279 | * 280 | * @param array|object $collection1 Collection to assign to. 281 | * @param array|object $collection2 Other collections to assign 282 | * 283 | * @return array|object Assigned collection. 284 | */ 285 | public static function assign($collection1, $collection2) 286 | { 287 | return __::reduceRight(func_get_args(), function ($source, $result) { 288 | __::doForEach($source, function ($sourceValue, $key) use (&$result) { 289 | $result = __::set($result, $key, $sourceValue); 290 | }); 291 | 292 | return $result; 293 | }, []); 294 | } 295 | 296 | /** 297 | * Reduces $collection to a value which is the $accumulator result of running each 298 | * element in $collection - from right to left - thru $iterateFn, where each 299 | * successive invocation is supplied the return value of the previous. 300 | * 301 | * If $accumulator is not given, the first element of $collection is used as the 302 | * initial value. 303 | * 304 | * The $iterateFn is invoked with four arguments: 305 | * ($accumulator, $value, $index|$key, $collection). 306 | * 307 | * @usage __::reduceRight(['a', 'b', 'c'], function ($word, $char) { 308 | * return $word . $char; 309 | * }, ''); 310 | * >> 'cba' 311 | * 312 | * @param array|object $collection The collection to iterate over. 313 | * @param \Closure $iterateFn The function invoked per iteration. 314 | * @param mixed $accumulator 315 | * 316 | * @return array|mixed|null (*): Returns the accumulated value. 317 | */ 318 | public static function reduceRight($collection, Closure $iterateFn, $accumulator = null) 319 | { 320 | if ($accumulator === null) { 321 | $accumulator = array_pop($collection); 322 | } 323 | 324 | __::doForEachRight( 325 | $collection, 326 | function ($value, $key, $collection) use (&$accumulator, $iterateFn) { 327 | $accumulator = $iterateFn($accumulator, $value, $key, $collection); 328 | } 329 | ); 330 | 331 | return $accumulator; 332 | } 333 | 334 | /** 335 | * Iterate over elements of the collection, from right to left, and invokes iterate 336 | * for each element. 337 | * 338 | * The iterate is invoked with three arguments: (value, index|key, collection). 339 | * Iterate functions may exit iteration early by explicitly returning false. 340 | * 341 | * @usage __::doForEachRight([1, 2, 3], function ($value) { print_r($value) }); 342 | * >> (Side effect: print 3, 2, 1) 343 | * 344 | * @param array|object $collection The collection to iterate over. 345 | * @param \Closure $iterateFn The function to call for each value. 346 | * 347 | * @return boolean 348 | */ 349 | public static function doForEachRight($collection, Closure $iterateFn) 350 | { 351 | __::doForEach(__::iteratorReverse($collection), $iterateFn); 352 | return true; 353 | } 354 | 355 | /** 356 | * Iterate over elements of the collection and invokes iterate for each element. 357 | * 358 | * The iterate is invoked with three arguments: (value, index|key, collection). 359 | * Iterate functions may exit iteration early by explicitly returning false. 360 | * 361 | * @usage __::doForEach([1, 2, 3], function ($value) { print_r($value) }); 362 | * >> (Side effect: print 1, 2, 3) 363 | * 364 | * @param array|object $collection The collection to iterate over. 365 | * @param \Closure $iterateFn The function to call for each value 366 | * 367 | * @return boolean 368 | */ 369 | public static function doForEach($collection, Closure $iterateFn) 370 | { 371 | foreach ($collection as $key => $value) { 372 | if ($iterateFn($value, $key, $collection) === false) { 373 | break; 374 | } 375 | } 376 | return true; 377 | } 378 | 379 | /** 380 | * @param array $iterable 381 | * 382 | * @return \Generator 383 | */ 384 | public static function iteratorReverse($iterable) 385 | { 386 | for (end($iterable); ($key = key($iterable)) !== null; prev($iterable)) { 387 | yield $key => current($iterable); 388 | } 389 | } 390 | 391 | /** 392 | * Return a new collection with the item set at index to given value. 393 | * Index can be a path of nested indexes. 394 | * 395 | * If a portion of path doesn't exist, it's created. Arrays are created for missing 396 | * index in an array; objects are created for missing property in an object. 397 | * 398 | * @usage __::set(['foo' => ['bar' => 'ter']], 'foo.baz.ber', 'fer'); 399 | * >> '['foo' => ['bar' => 'ter', 'baz' => ['ber' => 'fer']]]' 400 | * 401 | * @param array|object $collection collection of values 402 | * @param string|int|null $path key or index 403 | * @param mixed $value the value to set at position $key 404 | * 405 | * @throws \Exception if the path consists of a non collection and strict is set to false 406 | * 407 | * @return array|object the new collection with the item set 408 | */ 409 | public static function set($collection, $path, $value = null) 410 | { 411 | if ($path === null) { 412 | return $collection; 413 | } 414 | $portions = __::split($path, '.', 2); 415 | $key = $portions[0]; 416 | if (count($portions) === 1) { 417 | return __::universalSet($collection, $key, $value); 418 | } 419 | // Here we manage the case where the portion of the path points to nothing, 420 | // or to a value that does not match the type of the source collection 421 | // (e.g. the path portion 'foo.bar' points to an integer value, while we 422 | // want to set a string at 'foo.bar.fun'. We first set an object or array 423 | // - following the current collection type - to 'for.bar' before setting 424 | // 'foo.bar.fun' to the specified value). 425 | if (!__::has($collection, $key) 426 | || (__::isObject($collection) && !__::isObject(__::get($collection, $key))) 427 | || (__::isArray($collection) && !__::isArray(__::get($collection, $key))) 428 | ) { 429 | $collection = __::universalSet($collection, $key, __::isObject($collection) ? new stdClass : []); 430 | } 431 | 432 | return __::universalSet($collection, $key, __::set(__::get($collection, $key), $portions[1], $value)); 433 | } 434 | 435 | /** 436 | * @param mixed $collection 437 | * @param mixed $key 438 | * @param mixed $value 439 | * 440 | * @return mixed 441 | */ 442 | public static function universalSet($collection, $key, $value) 443 | { 444 | $set_object = function ($object, $key, $value) { 445 | $newObject = clone $object; 446 | $newObject->$key = $value; 447 | 448 | return $newObject; 449 | }; 450 | $set_array = function ($array, $key, $value) { 451 | $array[$key] = $value; 452 | 453 | return $array; 454 | }; 455 | $setter = __::isObject($collection) ? $set_object : $set_array; 456 | 457 | return call_user_func_array($setter, [$collection, $key, $value]); 458 | } 459 | 460 | /** 461 | * Returns if $input contains all requested $keys. If $strict is true it also checks if $input exclusively contains 462 | * the given $keys. 463 | * 464 | * @usage __::hasKeys(['foo' => 'bar', 'foz' => 'baz'], ['foo', 'foz']); 465 | * >> true 466 | * 467 | * @param array $collection of key values pairs 468 | * @param array $keys collection of keys to look for 469 | * @param boolean $strict to exclusively check 470 | * 471 | * @return boolean 472 | */ 473 | public static function hasKeys($collection = [], array $keys = [], bool $strict = false): bool 474 | { 475 | $keyCount = count($keys); 476 | if ($strict && count($collection) !== $keyCount) { 477 | return false; 478 | } 479 | 480 | return __::every( 481 | __::map($keys, function ($key) use ($collection) { 482 | return __::has($collection, $key); 483 | }), 484 | function ($v) { 485 | return $v === true; 486 | } 487 | ); 488 | } 489 | 490 | /** 491 | * Return true if $collection contains the requested $key. 492 | * 493 | * In constraint to isset(), __::has() returns true if the key exists but is null. 494 | * 495 | * @usage __::has(['foo' => ['bar' => 'num'], 'foz' => 'baz'], 'foo.bar'); 496 | * >> true 497 | * 498 | * __::hasKeys((object) ['foo' => 'bar', 'foz' => 'baz'], 'bar'); 499 | * >> false 500 | * 501 | * @param array|object $collection of key values pairs 502 | * @param string $path Path to look for. 503 | * 504 | * @return boolean 505 | */ 506 | public static function has($collection, $path): bool 507 | { 508 | $portions = __::split($path, '.', 2); 509 | $key = $portions[0]; 510 | 511 | if (count($portions) === 1) { 512 | return array_key_exists($key, (array)$collection); 513 | } 514 | 515 | return __::has(__::get($collection, $key), $portions[1]); 516 | } 517 | 518 | /** 519 | * Combines and concat collections provided with each others. 520 | * 521 | * If the collections have common keys, then the values are appended in an array. 522 | * If numerical indexes are passed, then values are appended. 523 | * 524 | * For a recursive merge, see __::merge. 525 | * 526 | * @usage __::concat(['color' => ['favorite' => 'red', 5], 3], [10, 'color' => ['favorite' => 'green', 'blue']]); 527 | * >> ['color' => ['favorite' => ['green'], 5, 'blue'], 3, 10] 528 | * 529 | * @param array|object $collection1 Collection to assign to. 530 | * @param array|object $collection2 Other collections to assign. 531 | * 532 | * @return array|object Assigned collection. 533 | */ 534 | public static function concat($collection1, $collection2) 535 | { 536 | $isObject = __::isObject($collection1); 537 | 538 | $args = __::map(func_get_args(), function ($arg) { 539 | return (array)$arg; 540 | }); 541 | 542 | $merged = call_user_func_array('array_merge', $args); 543 | 544 | return $isObject ? (object)$merged : $merged; 545 | } 546 | 547 | /** 548 | * Recursively combines and concat collections provided with each others. 549 | * 550 | * If the collections have common keys, then the values are appended in an array. 551 | * If numerical indexes are passed, then values are appended. 552 | * 553 | * For a non-recursive concat, see __::concat. 554 | * 555 | * @usage __::concatDeep(['color' => ['favorite' => 'red', 5], 3], [10, 'color' => ['favorite' => 'green', 556 | * 'blue']]); 557 | * >> ['color' => ['favorite' => ['red', 'green'], 5, 'blue'], 3, 10] 558 | * 559 | * @param array|object $collection1 First collection to concatDeep. 560 | * @param array|object $collection2 other collections to concatDeep. 561 | * 562 | * @return array|object Concatenated collection. 563 | */ 564 | public static function concatDeep($collection1, $collection2) 565 | { 566 | return __::reduceRight(func_get_args(), function ($source, $result) { 567 | __::doForEach($source, function ($sourceValue, $key) use (&$result) { 568 | if (!__::has($result, $key)) { 569 | $result = __::set($result, $key, $sourceValue); 570 | } else { 571 | if (is_numeric($key)) { 572 | $result = __::concat($result, [$sourceValue]); 573 | } else { 574 | $resultValue = __::get($result, $key); 575 | $result = __::set($result, $key, __::concatDeep( 576 | __::isCollection($resultValue) ? $resultValue : (array)$resultValue, 577 | __::isCollection($sourceValue) ? $sourceValue : (array)$sourceValue 578 | )); 579 | } 580 | } 581 | }); 582 | 583 | return $result; 584 | }, []); 585 | } 586 | 587 | /** 588 | * Flattens a complex collection by mapping each ending leafs value to a key consisting of all previous indexes. 589 | * 590 | * @usage __::ease(['foo' => ['bar' => 'ter'], 'baz' => ['b', 'z']]); 591 | * >> '['foo.bar' => 'ter', 'baz.0' => 'b', , 'baz.1' => 'z']' 592 | * 593 | * @param array $collection array of values 594 | * @param string $glue glue between key path 595 | * 596 | * @return array flatten collection 597 | */ 598 | public static function ease(array $collection, string $glue = '.'): array 599 | { 600 | $map = []; 601 | __::internalEase($map, $collection, $glue); 602 | 603 | return $map; 604 | } 605 | 606 | /** 607 | * Inner function for collections::ease 608 | * 609 | * @param array $map 610 | * @param array $array 611 | * @param string $glue 612 | * @param string $prefix 613 | */ 614 | private static function internalEase(array &$map, array $array, string $glue, string $prefix = '') 615 | { 616 | foreach ($array as $index => $value) { 617 | if (is_array($value)) { 618 | __::internalEase($map, $value, $glue, $prefix . $index . $glue); 619 | } else { 620 | $map[$prefix . $index] = $value; 621 | } 622 | } 623 | } 624 | 625 | /** 626 | * Checks if predicate returns truthy for all elements of collection. 627 | * 628 | * Iteration is stopped once predicate returns falsey. 629 | * The predicate is invoked with three arguments: (value, index|key, collection). 630 | * 631 | * @usage __::every([1, 3, 4], function ($v) { return is_int($v); }); 632 | * >> true 633 | * 634 | * @param array|object $collection The collection to iterate over. 635 | * @param \Closure $iterateFn The function to call for each value. 636 | * 637 | * @return bool 638 | */ 639 | public static function every($collection, Closure $iterateFn): bool 640 | { 641 | $truthy = true; 642 | 643 | __::doForEach( 644 | $collection, 645 | function ($value, $key, $collection) use (&$truthy, $iterateFn) { 646 | $truthy = $truthy && $iterateFn($value, $key, $collection); 647 | if (!$truthy) { 648 | return false; 649 | } 650 | } 651 | ); 652 | 653 | return $truthy; 654 | } 655 | 656 | /** 657 | * Returns an associative array where the keys are values of $key. 658 | * 659 | * @author Chauncey McAskill 660 | * @link https://gist.github.com/mcaskill/baaee44487653e1afc0d array_group_by() function. 661 | * 662 | * @usage __::groupBy([ 663 | * ['state' => 'IN', 'city' => 'Indianapolis', 'object' => 'School bus'], 664 | * ['state' => 'CA', 'city' => 'San Diego', 'object' => 'Light bulb'], 665 | * ['state' => 'CA', 'city' => 'Mountain View', 'object' => 'Space pen'], 666 | * ], 'state'); 667 | * >> [ 668 | * 'IN' => [ 669 | * ['state' => 'IN', 'city' => 'Indianapolis', 'object' => 'School bus'], 670 | * ['state' => 'CA', 'city' => 'San Diego', 'object' => 'Light bulb'], 671 | * ], 672 | * 'CA' => [ 673 | * ['state' => 'CA', 'city' => 'Mountain View', 'object' => 'Space pen'] 674 | * ] 675 | * ] 676 | * 677 | * 678 | * __::groupBy([ 679 | * ['state' => 'IN', 'city' => 'Indianapolis', 'object' => 'School bus'], 680 | * ['state' => 'IN', 'city' => 'Indianapolis', 'object' => 'Manhole'], 681 | * ['state' => 'CA', 'city' => 'San Diego', 'object' => 'Light bulb'], 682 | * ], 683 | * function ($value) { 684 | * return $value->city; 685 | * } 686 | * ); 687 | * >> [ 688 | * 'Indianapolis' => [ 689 | * ['state' => 'IN', 'city' => 'Indianapolis', 'object' => 'School bus'], 690 | * ['state' => 'IN', 'city' => 'Indianapolis', 'object' => 'Manhole'], 691 | * ], 692 | * 'San Diego' => [ 693 | * ['state' => 'CA', 'city' => 'San Diego', 'object' => 'Light bulb'], 694 | * ] 695 | * ] 696 | * 697 | * @param array $array 698 | * @param mixed $key 699 | * 700 | * @return array 701 | */ 702 | public static function groupBy(array $array, $key): array 703 | { 704 | if (!is_bool($key) && !is_scalar($key) && !is_callable($key)) { 705 | return $array; 706 | } 707 | $grouped = []; 708 | foreach ($array as $value) { 709 | $groupKey = null; 710 | if (is_callable($key)) { 711 | $groupKey = call_user_func($key, $value); 712 | } elseif (is_object($value) && property_exists($value, (string)$key)) { 713 | $groupKey = $value->{$key}; 714 | } elseif (is_array($value) && isset($value[$key])) { 715 | $groupKey = $value[$key]; 716 | } 717 | if ($groupKey === null) { 718 | continue; 719 | } 720 | $grouped[$groupKey][] = $value; 721 | } 722 | if (($argCnt = func_num_args()) > 2) { 723 | $args = func_get_args(); 724 | foreach ($grouped as $_key => $value) { 725 | $params = array_merge([$value], array_slice($args, 2, $argCnt)); 726 | $grouped[$_key] = call_user_func_array('\__::groupBy', $params); 727 | } 728 | } 729 | 730 | return $grouped; 731 | } 732 | 733 | /** 734 | * Check if value is an empty array or object. We consider any non enumerable as empty. 735 | * 736 | * @usage __::isEmpty([]); 737 | * >> true 738 | * 739 | * @param mixed $value The value to check for emptiness. 740 | * 741 | * @return bool 742 | */ 743 | public static function isEmpty($value): bool 744 | { 745 | return (!__::isArray($value) && !__::isObject($value)) || count((array)$value) === 0; 746 | } 747 | 748 | /** 749 | * Transforms the keys in a collection by running each key through the iterator 750 | * 751 | * @param array $array array of values 752 | * @param \Closure $closure closure to map the keys 753 | * 754 | * @throws \Exception if closure doesn't return a valid key that can be used in PHP array 755 | * 756 | * @return array 757 | */ 758 | public static function mapKeys(array $array, Closure $closure = null): array 759 | { 760 | if (is_null($closure)) { 761 | $closure = '__::identity'; 762 | } 763 | $resultArray = []; 764 | foreach ($array as $key => $value) { 765 | $newKey = call_user_func_array($closure, [$key, $value, $array]); 766 | // key must be a number or string 767 | if (!is_numeric($newKey) && !is_string($newKey)) { 768 | throw new Exception('closure must returns a number or string'); 769 | } 770 | $resultArray[$newKey] = $value; 771 | } 772 | 773 | return $resultArray; 774 | } 775 | 776 | /** 777 | * Transforms the values in a collection by running each value through the iterator 778 | * 779 | * @param array $array array of values 780 | * @param \Closure $closure closure to map the values 781 | * 782 | * @return array 783 | */ 784 | public static function mapValues(array $array, Closure $closure = null): array 785 | { 786 | if (is_null($closure)) { 787 | $closure = '__::identity'; 788 | } 789 | $resultArray = []; 790 | foreach ($array as $key => $value) { 791 | $resultArray[$key] = call_user_func_array($closure, [$value, $key, $array]); 792 | } 793 | 794 | return $resultArray; 795 | } 796 | 797 | /** 798 | * Recursively combines and merge collections provided with each others. 799 | * 800 | * If the collections have common keys, then the last passed keys override the previous. 801 | * If numerical indexes are passed, then last passed indexes override the previous. 802 | * 803 | * For a non-recursive merge, see __::merge. 804 | * 805 | * @usage __::merge(['color' => ['favorite' => 'red', 'model' => 3, 5], 3], [10, 'color' => ['favorite' => 'green', 806 | * 'blue']]); 807 | * >> ['color' => ['favorite' => 'green', 'model' => 3, 'blue'], 10] 808 | * 809 | * @param array|object $collection1 First collection to merge. 810 | * @param array|object $collection2 Other collections to merge. 811 | * 812 | * @return array|object Concatenated collection. 813 | */ 814 | public static function merge($collection1, $collection2) 815 | { 816 | return __::reduceRight(func_get_args(), function ($source, $result) { 817 | __::doForEach($source, function ($sourceValue, $key) use (&$result) { 818 | $value = $sourceValue; 819 | if (__::isCollection($value)) { 820 | $value = __::merge(__::get($result, $key), $sourceValue); 821 | } 822 | $result = __::set($result, $key, $value); 823 | }); 824 | 825 | return $result; 826 | }, []); 827 | } 828 | 829 | /** 830 | * Returns an array having only keys present in the given path list. Values for missing keys values will be filled 831 | * with provided default value. 832 | * 833 | * @usage __::pick(['a' => 1, 'b' => ['c' => 3, 'd' => 4]], ['a', 'b.d']); 834 | * >> ['a' => 1, 'b' => ['d' => 4]] 835 | * 836 | * @param array|object $collection The collection to iterate over. 837 | * @param array $paths array paths to pick 838 | * @param null $default 839 | * 840 | * @return array|object 841 | */ 842 | public static function pick($collection = [], array $paths = [], $default = null) 843 | { 844 | return __::reduce($paths, function ($results, $path) use ($collection, $default) { 845 | return __::set($results, $path, __::get($collection, $path, $default)); 846 | }, __::isObject($collection) ? new stdClass() : []); 847 | } 848 | 849 | /** 850 | * Reduces $collection to a value which is the $accumulator result of running each 851 | * element in $collection thru $iterateFn, where each successive invocation is supplied 852 | * the return value of the previous. 853 | * 854 | * If $accumulator is not given, the first element of $collection is used as the 855 | * initial value. 856 | * 857 | * The $iterateFn is invoked with four arguments: 858 | * ($accumulator, $value, $index|$key, $collection). 859 | * 860 | * @usage __::reduce([1, 2], function ($sum, $number) { 861 | * return $sum + $number; 862 | * }, 0); 863 | * >> 3 864 | * 865 | * $a = [ 866 | * ['state' => 'IN', 'city' => 'Indianapolis', 'object' => 'School bus'], 867 | * ['state' => 'IN', 'city' => 'Indianapolis', 'object' => 'Manhole'], 868 | * ['state' => 'IN', 'city' => 'Plainfield', 'object' => 'Basketball'], 869 | * ['state' => 'CA', 'city' => 'San Diego', 'object' => 'Light bulb'], 870 | * ['state' => 'CA', 'city' => 'Mountain View', 'object' => 'Space pen'], 871 | * ]; 872 | * $iterateFn = function ($accumulator, $value) { 873 | * if (isset($accumulator[$value['city']])) 874 | * $accumulator[$value['city']]++; 875 | * else 876 | * $accumulator[$value['city']] = 1; 877 | * return $accumulator; 878 | * }; 879 | * __::reduce($c, $iterateFn, []); 880 | * >> [ 881 | * 'Indianapolis' => 2, 882 | * 'Plainfield' => 1, 883 | * 'San Diego' => 1, 884 | * 'Mountain View' => 1, 885 | * ] 886 | * 887 | * $object = new \stdClass(); 888 | * $object->a = 1; 889 | * $object->b = 2; 890 | * $object->c = 1; 891 | * __::reduce($object, function ($result, $value, $key) { 892 | * if (!isset($result[$value])) 893 | * $result[$value] = []; 894 | * $result[$value][] = $key; 895 | * return $result; 896 | * }, []) 897 | * >> [ 898 | * '1' => ['a', 'c'], 899 | * '2' => ['b'] 900 | * ] 901 | * 902 | * @param array $collection The collection to iterate over. 903 | * @param \Closure $iterateFn The function invoked per iteration. 904 | * @param array|null $accumulator 905 | * 906 | * @return array|mixed|null (*): Returns the accumulated value. 907 | */ 908 | public static function reduce($collection, Closure $iterateFn, $accumulator = null) 909 | { 910 | if ($accumulator === null) { 911 | $accumulator = array_shift($collection); 912 | } 913 | __::doForEach( 914 | $collection, 915 | function ($value, $key, $collection) use (&$accumulator, $iterateFn) { 916 | $accumulator = $iterateFn($accumulator, $value, $key, $collection); 917 | } 918 | ); 919 | 920 | return $accumulator; 921 | } 922 | 923 | /** 924 | * Builds a multidimensional collection out of a hash map using the key as indicator where to put the value. 925 | * 926 | * @usage __::unease(['foo.bar' => 'ter', 'baz.0' => 'b', , 'baz.1' => 'z']); 927 | * >> '['foo' => ['bar' => 'ter'], 'baz' => ['b', 'z']]' 928 | * 929 | * @param array $collection hash map of values 930 | * @param string $separator the glue used in the keys 931 | * 932 | * @return array 933 | * @throws \Exception 934 | */ 935 | public static function unease(array $collection, string $separator = '.'): array 936 | { 937 | $nonDefaultSeparator = $separator !== '.'; 938 | $map = []; 939 | 940 | foreach ($collection as $key => $value) { 941 | $map = __::set( 942 | $map, 943 | $nonDefaultSeparator ? str_replace($separator, '.', $key) : $key, 944 | $value 945 | ); 946 | } 947 | 948 | return $map; 949 | } 950 | } 951 | -------------------------------------------------------------------------------- /src/Traits/Functions.php: -------------------------------------------------------------------------------- 1 | > 'jakies-zdanie-z-duza-iloscia-obcych-znakow' 17 | * 18 | * @param string $str string to generate slug from 19 | * @param array $options method options which includes: delimiter, limit, lowercase, replacements, transliterate 20 | * 21 | * @return string 22 | */ 23 | public static function slug(string $str, array $options = []): string 24 | { 25 | // Make sure string is in UTF-8 and strip invalid UTF-8 characters 26 | $str = mb_convert_encoding((string)$str, 'UTF-8', mb_list_encodings()); 27 | 28 | $defaults = [ 29 | 'delimiter' => '-', 30 | 'limit' => null, 31 | 'lowercase' => true, 32 | 'replacements' => [], 33 | 'transliterate' => true, 34 | ]; 35 | 36 | // Merge options 37 | $options = array_merge($defaults, $options); 38 | 39 | $char_map = [ 40 | // Latin 41 | 'À' => 'A', 42 | 'Á' => 'A', 43 | 'Â' => 'A', 44 | 'Ã' => 'A', 45 | 'Ä' => 'A', 46 | 'Å' => 'A', 47 | 'Æ' => 'AE', 48 | 'Ç' => 'C', 49 | 'È' => 'E', 50 | 'É' => 'E', 51 | 'Ê' => 'E', 52 | 'Ë' => 'E', 53 | 'Ì' => 'I', 54 | 'Í' => 'I', 55 | 'Î' => 'I', 56 | 'Ï' => 'I', 57 | 'Ð' => 'D', 58 | 'Ñ' => 'N', 59 | 'Ò' => 'O', 60 | 'Ó' => 'O', 61 | 'Ô' => 'O', 62 | 'Õ' => 'O', 63 | 'Ö' => 'O', 64 | 'Ő' => 'O', 65 | 'Ø' => 'O', 66 | 'Ù' => 'U', 67 | 'Ú' => 'U', 68 | 'Û' => 'U', 69 | 'Ü' => 'U', 70 | 'Ű' => 'U', 71 | 'Ý' => 'Y', 72 | 'Þ' => 'TH', 73 | 'ß' => 'ss', 74 | 'à' => 'a', 75 | 'á' => 'a', 76 | 'â' => 'a', 77 | 'ã' => 'a', 78 | 'ä' => 'a', 79 | 'å' => 'a', 80 | 'æ' => 'ae', 81 | 'ç' => 'c', 82 | 'è' => 'e', 83 | 'é' => 'e', 84 | 'ê' => 'e', 85 | 'ë' => 'e', 86 | 'ì' => 'i', 87 | 'í' => 'i', 88 | 'î' => 'i', 89 | 'ï' => 'i', 90 | 'ð' => 'd', 91 | 'ñ' => 'n', 92 | 'ò' => 'o', 93 | 'ó' => 'o', 94 | 'ô' => 'o', 95 | 'õ' => 'o', 96 | 'ö' => 'o', 97 | 'ő' => 'o', 98 | 'ø' => 'o', 99 | 'ù' => 'u', 100 | 'ú' => 'u', 101 | 'û' => 'u', 102 | 'ü' => 'u', 103 | 'ű' => 'u', 104 | 'ý' => 'y', 105 | 'þ' => 'th', 106 | 'ÿ' => 'y', 107 | 108 | // Latin symbols 109 | '©' => '(c)', 110 | 111 | // Greek 112 | 'Α' => 'A', 113 | 'Β' => 'B', 114 | 'Γ' => 'G', 115 | 'Δ' => 'D', 116 | 'Ε' => 'E', 117 | 'Ζ' => 'Z', 118 | 'Η' => 'H', 119 | 'Θ' => '8', 120 | 'Ι' => 'I', 121 | 'Κ' => 'K', 122 | 'Λ' => 'L', 123 | 'Μ' => 'M', 124 | 'Ν' => 'N', 125 | 'Ξ' => '3', 126 | 'Ο' => 'O', 127 | 'Π' => 'P', 128 | 'Ρ' => 'R', 129 | 'Σ' => 'S', 130 | 'Τ' => 'T', 131 | 'Υ' => 'Y', 132 | 'Φ' => 'F', 133 | 'Χ' => 'X', 134 | 'Ψ' => 'PS', 135 | 'Ω' => 'W', 136 | 'Ά' => 'A', 137 | 'Έ' => 'E', 138 | 'Ί' => 'I', 139 | 'Ό' => 'O', 140 | 'Ύ' => 'Y', 141 | 'Ή' => 'H', 142 | 'Ώ' => 'W', 143 | 'Ϊ' => 'I', 144 | 'Ϋ' => 'Y', 145 | 'α' => 'a', 146 | 'β' => 'b', 147 | 'γ' => 'g', 148 | 'δ' => 'd', 149 | 'ε' => 'e', 150 | 'ζ' => 'z', 151 | 'η' => 'h', 152 | 'θ' => '8', 153 | 'ι' => 'i', 154 | 'κ' => 'k', 155 | 'λ' => 'l', 156 | 'μ' => 'm', 157 | 'ν' => 'n', 158 | 'ξ' => '3', 159 | 'ο' => 'o', 160 | 'π' => 'p', 161 | 'ρ' => 'r', 162 | 'σ' => 's', 163 | 'τ' => 't', 164 | 'υ' => 'y', 165 | 'φ' => 'f', 166 | 'χ' => 'x', 167 | 'ψ' => 'ps', 168 | 'ω' => 'w', 169 | 'ά' => 'a', 170 | 'έ' => 'e', 171 | 'ί' => 'i', 172 | 'ό' => 'o', 173 | 'ύ' => 'y', 174 | 'ή' => 'h', 175 | 'ώ' => 'w', 176 | 'ς' => 's', 177 | 'ϊ' => 'i', 178 | 'ΰ' => 'y', 179 | 'ϋ' => 'y', 180 | 'ΐ' => 'i', 181 | 182 | // Turkish 183 | 'Ş' => 'S', 184 | 'İ' => 'I', 185 | 'Ç' => 'C', 186 | 'Ü' => 'U', 187 | 'Ö' => 'O', 188 | 'Ğ' => 'G', 189 | 'ş' => 's', 190 | 'ı' => 'i', 191 | 'ç' => 'c', 192 | 'ü' => 'u', 193 | 'ö' => 'o', 194 | 'ğ' => 'g', 195 | 196 | // Russian 197 | 'А' => 'A', 198 | 'Б' => 'B', 199 | 'В' => 'V', 200 | 'Г' => 'G', 201 | 'Д' => 'D', 202 | 'Е' => 'E', 203 | 'Ё' => 'Yo', 204 | 'Ж' => 'Zh', 205 | 'З' => 'Z', 206 | 'И' => 'I', 207 | 'Й' => 'J', 208 | 'К' => 'K', 209 | 'Л' => 'L', 210 | 'М' => 'M', 211 | 'Н' => 'N', 212 | 'О' => 'O', 213 | 'П' => 'P', 214 | 'Р' => 'R', 215 | 'С' => 'S', 216 | 'Т' => 'T', 217 | 'У' => 'U', 218 | 'Ф' => 'F', 219 | 'Х' => 'H', 220 | 'Ц' => 'C', 221 | 'Ч' => 'Ch', 222 | 'Ш' => 'Sh', 223 | 'Щ' => 'Sh', 224 | 'Ъ' => '', 225 | 'Ы' => 'Y', 226 | 'Ь' => '', 227 | 'Э' => 'E', 228 | 'Ю' => 'Yu', 229 | 'Я' => 'Ya', 230 | 'а' => 'a', 231 | 'б' => 'b', 232 | 'в' => 'v', 233 | 'г' => 'g', 234 | 'д' => 'd', 235 | 'е' => 'e', 236 | 'ё' => 'yo', 237 | 'ж' => 'zh', 238 | 'з' => 'z', 239 | 'и' => 'i', 240 | 'й' => 'j', 241 | 'к' => 'k', 242 | 'л' => 'l', 243 | 'м' => 'm', 244 | 'н' => 'n', 245 | 'о' => 'o', 246 | 'п' => 'p', 247 | 'р' => 'r', 248 | 'с' => 's', 249 | 'т' => 't', 250 | 'у' => 'u', 251 | 'ф' => 'f', 252 | 'х' => 'h', 253 | 'ц' => 'c', 254 | 'ч' => 'ch', 255 | 'ш' => 'sh', 256 | 'щ' => 'sh', 257 | 'ъ' => '', 258 | 'ы' => 'y', 259 | 'ь' => '', 260 | 'э' => 'e', 261 | 'ю' => 'yu', 262 | 'я' => 'ya', 263 | 264 | // Ukrainian 265 | 'Є' => 'Ye', 266 | 'І' => 'I', 267 | 'Ї' => 'Yi', 268 | 'Ґ' => 'G', 269 | 'є' => 'ye', 270 | 'і' => 'i', 271 | 'ї' => 'yi', 272 | 'ґ' => 'g', 273 | 274 | // Czech 275 | 'Č' => 'C', 276 | 'Ď' => 'D', 277 | 'Ě' => 'E', 278 | 'Ň' => 'N', 279 | 'Ř' => 'R', 280 | 'Š' => 'S', 281 | 'Ť' => 'T', 282 | 'Ů' => 'U', 283 | 'Ž' => 'Z', 284 | 'č' => 'c', 285 | 'ď' => 'd', 286 | 'ě' => 'e', 287 | 'ň' => 'n', 288 | 'ř' => 'r', 289 | 'š' => 's', 290 | 'ť' => 't', 291 | 'ů' => 'u', 292 | 'ž' => 'z', 293 | 294 | // Polish 295 | 'Ą' => 'A', 296 | 'Ć' => 'C', 297 | 'Ę' => 'e', 298 | 'Ł' => 'L', 299 | 'Ń' => 'N', 300 | 'Ó' => 'o', 301 | 'Ś' => 'S', 302 | 'Ź' => 'Z', 303 | 'Ż' => 'Z', 304 | 'ą' => 'a', 305 | 'ć' => 'c', 306 | 'ę' => 'e', 307 | 'ł' => 'l', 308 | 'ń' => 'n', 309 | 'ó' => 'o', 310 | 'ś' => 's', 311 | 'ź' => 'z', 312 | 'ż' => 'z', 313 | 314 | // Latvian 315 | 'Ā' => 'A', 316 | 'Č' => 'C', 317 | 'Ē' => 'E', 318 | 'Ģ' => 'G', 319 | 'Ī' => 'i', 320 | 'Ķ' => 'k', 321 | 'Ļ' => 'L', 322 | 'Ņ' => 'N', 323 | 'Š' => 'S', 324 | 'Ū' => 'u', 325 | 'Ž' => 'Z', 326 | 'ā' => 'a', 327 | 'č' => 'c', 328 | 'ē' => 'e', 329 | 'ģ' => 'g', 330 | 'ī' => 'i', 331 | 'ķ' => 'k', 332 | 'ļ' => 'l', 333 | 'ņ' => 'n', 334 | 'š' => 's', 335 | 'ū' => 'u', 336 | 'ž' => 'z', 337 | ]; 338 | 339 | // Make custom replacements 340 | $str = preg_replace(array_keys($options['replacements']), $options['replacements'], $str); 341 | 342 | // Transliterate characters to ASCII 343 | if ($options['transliterate']) { 344 | $str = str_replace(array_keys($char_map), $char_map, $str); 345 | } 346 | 347 | // Replace non-alphanumeric characters with our delimiter 348 | $str = preg_replace('/[^\p{L}\p{Nd}]+/u', $options['delimiter'], $str); 349 | 350 | // Remove duplicate delimiters 351 | $str = preg_replace('/(' . preg_quote($options['delimiter'], '/') . '){2,}/', '$1', $str); 352 | 353 | // Truncate slug to max. characters 354 | $str = mb_substr($str, 0, ($options['limit'] ? $options['limit'] : mb_strlen($str, 'UTF-8')), 'UTF-8'); 355 | 356 | // Remove delimiter from ends 357 | $str = trim($str, $options['delimiter']); 358 | 359 | return $options['lowercase'] ? mb_strtolower($str, 'UTF-8') : $str; 360 | } 361 | 362 | /** 363 | * Find the urls inside a string a put them inside anchor tags. 364 | * 365 | * @usage __::urlify("I love https://google.com"); 366 | * >> 'I love google.com' 367 | * 368 | * @param string $string 369 | * 370 | * @return string|mixed 371 | */ 372 | public static function urlify(string $string) 373 | { 374 | /* Proposed by: 375 | * Søren Løvborg 376 | * http://stackoverflow.com/users/136796/soren-lovborg 377 | * http://stackoverflow.com/questions/17900004/turn-plain-text-urls-into-active-links-using-php/17900021#17900021 378 | */ 379 | 380 | $rexProtocol = '(https?://)?'; 381 | $rexDomain = '((?:[-a-zA-Z0-9]{1,63}\.)+[-a-zA-Z0-9]{2,63}|(?:[0-9]{1,3}\.){3}[0-9]{1,3})'; 382 | $rexPort = '(:[0-9]{1,5})?'; 383 | $rexPath = '(/[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]*?)?'; 384 | $rexQuery = '(\?[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]+?)?'; 385 | $rexFragment = '(#[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]+?)?'; 386 | 387 | return preg_replace_callback( 388 | "&\\b$rexProtocol$rexDomain$rexPort$rexPath$rexQuery$rexFragment(?=[?.!,;:\"]?(\s|$))&", 389 | function ($match) { 390 | $completeUrl = $match[1] ? $match[0] : "http://{$match[0]}"; 391 | 392 | return '' . $match[2] . $match[3] . $match[4] . ''; 393 | }, 394 | htmlspecialchars($string) 395 | ); 396 | } 397 | 398 | /** 399 | * Truncate string based on count of words 400 | * 401 | * @usage $string = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque et mi orci.'; 402 | * __::truncate($string); 403 | * >> 'Lorem ipsum dolor sit amet, consectetur...' 404 | * 405 | * @param string $text text to truncate 406 | * @param integer $limit limit of words 407 | * 408 | * @return string 409 | */ 410 | 411 | public static function truncate(string $text, int $limit = 40): string 412 | { 413 | if (str_word_count($text, 0) > $limit) { 414 | $words = (array)str_word_count($text, 2); 415 | $pos = array_keys($words); 416 | $text = mb_substr($text, 0, $pos[$limit], 'UTF-8') . '...'; 417 | } 418 | 419 | return $text; 420 | } 421 | } 422 | -------------------------------------------------------------------------------- /src/Traits/Objects.php: -------------------------------------------------------------------------------- 1 | > true 14 | * 15 | * @param mixed $value 16 | * 17 | * @return bool 18 | */ 19 | public static function isArray($value = null): bool 20 | { 21 | return is_array($value); 22 | } 23 | 24 | /** 25 | * Check if give value is function or not. 26 | * 27 | * @usage __::isFunction(function ($a) { return $a + 2; }); 28 | * >> true 29 | * 30 | * @param mixed $value 31 | * 32 | * @return bool 33 | */ 34 | public static function isFunction($value = null): bool 35 | { 36 | return is_callable($value); 37 | } 38 | 39 | /** 40 | * Check if give value is null or not. 41 | * 42 | * @usage __::isNull(null); 43 | * >> true 44 | * 45 | * @param mixed $value 46 | * 47 | * @return bool 48 | */ 49 | public static function isNull($value = null): bool 50 | { 51 | return is_null($value); 52 | } 53 | 54 | 55 | /** 56 | * Check if give value is number or not. 57 | * 58 | * @usage __::isNumber(123); 59 | * >> true 60 | * 61 | * @param mixed $value 62 | * 63 | * @return bool 64 | */ 65 | public static function isNumber($value = null): bool 66 | { 67 | return is_numeric($value); 68 | } 69 | 70 | /** 71 | * Check if give value is object or not. 72 | * 73 | * @usage __::isObject('fred'); 74 | * >> false 75 | * 76 | * @param mixed $value 77 | * 78 | * @return bool 79 | */ 80 | public static function isObject($value = null): bool 81 | { 82 | return is_object($value); 83 | } 84 | 85 | /** 86 | * Check if give value is string or not. 87 | * 88 | * @usage __::isString('fred'); 89 | * >> true 90 | * 91 | * @param mixed $value 92 | * 93 | * @return bool 94 | */ 95 | public static function isString($value = null): bool 96 | { 97 | return is_string($value); 98 | } 99 | 100 | /** 101 | * Check if the object is a collection. A collection is either an array or an object. 102 | * 103 | * @param mixed $value 104 | * 105 | * @return bool 106 | */ 107 | public static function isCollection($value): bool 108 | { 109 | return __::isArray($value) || __::isObject($value); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Traits/Sequence/Chain.php: -------------------------------------------------------------------------------- 1 | compact() 12 | * ->prepend(4) 13 | * ->value(); 14 | * >> [4, 1, 2, 3] 15 | * 16 | * @param mixed $initialValue 17 | * 18 | * @return mixed 19 | */ 20 | public static function chain($initialValue) 21 | { 22 | return new ChainWrapper($initialValue); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Traits/Sequence/ChainWrapper.php: -------------------------------------------------------------------------------- 1 | value = $value; 23 | } 24 | 25 | /** 26 | * Dynamically calls php-lodash functions, prepend the list of parameters with the current collection list 27 | * 28 | * @param string $functionName must be a valid php-lodash function 29 | * @param array $params 30 | * 31 | * @return $this 32 | * @throws \Exception 33 | */ 34 | public function __call(string $functionName, array $params): self 35 | { 36 | if (is_callable('\__::' . $functionName, true)) { 37 | $params = $params == null ? [] : $params; 38 | $params = __::prepend($params, $this->value); 39 | /** @var callable $fnCallable */ 40 | $fnCallable = ['\__', $functionName]; 41 | $this->value = call_user_func_array($fnCallable, $params); 42 | 43 | return $this; 44 | } else { 45 | throw new Exception("Invalid function {$functionName}"); 46 | } 47 | } 48 | 49 | /** 50 | * @return mixed 51 | */ 52 | public function value() 53 | { 54 | return $this->value; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Traits/Strings.php: -------------------------------------------------------------------------------- 1 | > ['a', 'b-c'] 15 | * 16 | * @param string $input The string to split. 17 | * @param string $delimiter The boundary string. 18 | * @param int $limit (optional) If limit is set and positive, the returned array 19 | * will contain a maximum of limit elements with the last element containing the 20 | * rest of string. 21 | * If the limit parameter is negative, all components except the last -limit are returned. 22 | * If the limit parameter is zero, then this is treated as 1. 23 | * 24 | * @return array 25 | */ 26 | public static function split(string $input, string $delimiter, int $limit = PHP_INT_MAX) 27 | { 28 | return explode($delimiter, $input, $limit); 29 | } 30 | 31 | /** 32 | * Converts string to [camel case](https://en.wikipedia.org/wiki/CamelCase). 33 | * 34 | * @usage __::camelCase('Foo Bar'); 35 | * >> 'fooBar' 36 | * 37 | * @param string $input 38 | * 39 | * @return string|array 40 | */ 41 | public static function camelCase(string $input) 42 | { 43 | $words = __::words(preg_replace("/['\x{2019}]/u", '', $input)); 44 | 45 | return array_reduce( 46 | $words, 47 | function ($result, $word) use ($words) { 48 | $isFirst = __::first($words) === $word; 49 | $word = __::toLower($word); 50 | 51 | return $result . (!$isFirst ? __::capitalize($word) : $word); 52 | }, 53 | '' 54 | ); 55 | } 56 | 57 | /** 58 | * Converts the first character of string to upper case and the remaining to lower case. 59 | * 60 | * @usage __::capitalize('FRED'); 61 | * >> 'Fred' 62 | * 63 | * @param string $input 64 | * 65 | * @return string 66 | */ 67 | public static function capitalize(string $input): string 68 | { 69 | return __::upperFirst(__::toLower($input)); 70 | } 71 | 72 | /** 73 | * Converts string to kebab case. 74 | * 75 | * @link https://en.wikipedia.org/wiki/Letter_case#Special_case_styles kebab case 76 | * 77 | * @usage __::kebabCase('Foo Bar'); 78 | * >> 'foo-bar' 79 | * 80 | * @param string $input 81 | * 82 | * @return string 83 | */ 84 | public static function kebabCase(string $input): string 85 | { 86 | $words = __::words(preg_replace("/['\x{2019}]/u", '', $input)); 87 | 88 | return array_reduce( 89 | $words, 90 | function ($result, $word) use ($words) { 91 | $isFirst = __::first($words) === $word; 92 | 93 | return $result . (!$isFirst ? '-' : '') . __::toLower($word); 94 | }, 95 | '' 96 | ); 97 | } 98 | 99 | /** 100 | * Converts the first character of string to lower case, like lcfirst. 101 | * 102 | * @usage __::lowerFirst('Fred'); 103 | * >> 'fred' 104 | * 105 | * @param string $input 106 | * 107 | * @return string 108 | */ 109 | public static function lowerFirst(string $input): string 110 | { 111 | return lcfirst($input); 112 | } 113 | 114 | /** 115 | * Converts string to snake case. 116 | * 117 | * @link https://en.wikipedia.org/wiki/Snake_case snake case 118 | * 119 | * @usage __::snakeCase('Foo Bar'); 120 | * >> 'foo_bar' 121 | * 122 | * @param string $input 123 | * 124 | * @return string 125 | */ 126 | public static function snakeCase(string $input): string 127 | { 128 | $words = __::words(preg_replace("/['\x{2019}]/u", '', $input)); 129 | 130 | return array_reduce( 131 | $words, 132 | function ($result, $word) use ($words) { 133 | $isFirst = __::first($words) === $word; 134 | 135 | return $result . (!$isFirst ? '_' : '') . __::toLower($word); 136 | }, 137 | '' 138 | ); 139 | } 140 | 141 | /** 142 | * Converts string to start case. 143 | * 144 | * @link https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage start case 145 | * 146 | * @usage __::startCase('--foo-bar--'); 147 | * >> 'Foo Bar' 148 | * 149 | * @param string $input 150 | * 151 | * @return string 152 | */ 153 | public static function startCase(string $input): string 154 | { 155 | $words = __::words(preg_replace("/['\x{2019}]/u", '', $input)); 156 | 157 | return array_reduce( 158 | $words, 159 | function ($result, $word) use ($words) { 160 | $isFirst = __::first($words) === $word; 161 | 162 | return $result . (!$isFirst ? ' ' : '') . __::upperFirst($word); 163 | }, 164 | '' 165 | ); 166 | } 167 | 168 | /** 169 | * Converts string, as a whole, to lower case just like strtolower. 170 | * 171 | * @usage __::toLower('fooBar'); 172 | * >> 'foobar' 173 | * 174 | * @param string $input 175 | * 176 | * @return string 177 | */ 178 | public static function toLower(string $input): string 179 | { 180 | return strtolower($input); 181 | } 182 | 183 | /** 184 | * Converts string, as a whole, to lower case just like strtoupper. 185 | * 186 | * @usage __::toUpper('fooBar'); 187 | * >> 'FOOBAR' 188 | * 189 | * @param string $input 190 | * 191 | * @return string 192 | */ 193 | public static function toUpper(string $input): string 194 | { 195 | return strtoupper($input); 196 | } 197 | 198 | /** 199 | * Converts string, as space separated words, to upper case. 200 | * 201 | * @usage __::upperCase('--foo-bar'); 202 | * >> 'FOO BAR' 203 | * 204 | * @param string $input 205 | * 206 | * @return string 207 | */ 208 | public static function upperCase(string $input): string 209 | { 210 | $words = __::words(preg_replace("/['\x{2019}]/u", '', $input)); 211 | 212 | return array_reduce( 213 | $words, 214 | function ($result, $word) use ($words) { 215 | $isFirst = __::first($words) === $word; 216 | 217 | return $result . (!$isFirst ? ' ' : '') . __::toUpper($word); 218 | }, 219 | '' 220 | ); 221 | } 222 | 223 | /** 224 | * Converts the first character of string to upper case, like ucfirst. 225 | * 226 | * @usage __::upperFirst('fred'); 227 | * >> 'Fred' 228 | * 229 | * @param string $input 230 | * 231 | * @return string 232 | */ 233 | public static function upperFirst(string $input): string 234 | { 235 | return ucfirst($input); 236 | } 237 | 238 | /** 239 | * Splits string into an array of its words. 240 | * 241 | * @usage __::words('fred, barney, & pebbles'); 242 | * >> ['fred', 'barney', 'pebbles'] 243 | * 244 | * __::words('fred, barney, & pebbles', '/[^, ]+/'); 245 | * >> ['fred', 'barney', '&', 'pebbles'] 246 | * 247 | * @param string|null $input 248 | * @param string $pattern : The pattern to match words. 249 | * 250 | * @return array 251 | */ 252 | public static function words(?string $input, $pattern = null) 253 | { 254 | /** Used to compose unicode character classes. */ 255 | $rsAstralRange = '\x{e800}-\x{efff}'; 256 | $rsComboMarksRange = '\x{0300}-\x{036f}'; 257 | $reComboHalfMarksRange = '\x{fe20}-\x{fe2f}'; 258 | $rsComboSymbolsRange = '\x{20d0}-\x{20ff}'; 259 | $rsComboRange = $rsComboMarksRange . $reComboHalfMarksRange . $rsComboSymbolsRange; 260 | $rsDingbatRange = '\x{2700}-\x{27bf}'; 261 | $rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff'; 262 | $rsMathOpRange = '\\xac\\xb1\\xd7\\xf7'; 263 | $rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf'; 264 | $rsPunctuationRange = '\x{2000}-\x{206f}'; 265 | $rsSpaceRange = ' \\t\\x0b\\f\\xa0\x{feff}\\n\\r\x{2028}\x{2029}\x{1680}\x{180e}\x{2000}\x{2001}\x{2002}\x{2003}\x{2004}\x{2005}\x{2006}\x{2007}\x{2008}\x{2009}\x{200a}\x{202f}\x{205f}\x{3000}'; 266 | $rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde'; 267 | $rsVarRange = '\x{fe0e}\x{fe0f}'; 268 | $rsBreakRange = $rsMathOpRange . $rsNonCharRange . $rsPunctuationRange . $rsSpaceRange; 269 | /** Used to compose unicode capture groups. */ 270 | $rsApos = "['\x{2019}]"; 271 | $rsBreak = '[' . $rsBreakRange . ']'; 272 | $rsCombo = '[' . $rsComboRange . ']'; 273 | $rsDigits = '\\d+'; 274 | $rsDingbat = '[' . $rsDingbatRange . ']'; 275 | $rsLower = '[' . $rsLowerRange . ']'; 276 | $rsMisc = '[^' . $rsAstralRange . $rsBreakRange . $rsDigits . $rsDingbatRange . $rsLowerRange . $rsUpperRange . ']'; 277 | $rsFitz = '\\x{e83c}[\x{effb}-\x{efff}]'; 278 | $rsModifier = '(?:' . $rsCombo . '|' . $rsFitz . ')'; 279 | $rsNonAstral = '[^' . $rsAstralRange . ']'; 280 | $rsRegional = '(?:\x{e83c}[\x{ede6}-\x{edff}]){2}'; 281 | $rsSurrPair = '[\x{e800}-\x{ebff}][\x{ec00}-\x{efff}]'; 282 | $rsUpper = '[' . $rsUpperRange . ']'; 283 | $rsZWJ = '\x{200d}'; 284 | /** Used to compose unicode regexes. */ 285 | $rsMiscLower = '(?:' . $rsLower . '|' . $rsMisc . ')'; 286 | $rsMiscUpper = '(?:' . $rsUpper . '|' . $rsMisc . ')'; 287 | $rsOptContrLower = '(?:' . $rsApos . '(?:d|ll|m|re|s|t|ve))?'; 288 | $rsOptContrUpper = '(?:' . $rsApos . '(?:D|LL|M|RE|S|T|VE))?'; 289 | $reOptMod = $rsModifier . '?'; 290 | $rsOptVar = '[' . $rsVarRange . ']?'; 291 | $rsOrdLower = '\\d*(?:(?:1st|2nd|3rd|(?![123])\\dth)\\b)'; 292 | $rsOrdUpper = '\\d*(?:(?:1ST|2ND|3RD|(?![123])\\dTH)\\b)'; 293 | $asciiWords = '/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/'; 294 | $hasUnicodeWordRegex = '/[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/'; 295 | $rsOptJoin = '(?:' . $rsZWJ . '(?:' . join( 296 | '|', 297 | [$rsNonAstral, $rsRegional, $rsSurrPair] 298 | ) . ')' . $rsOptVar . $reOptMod . ')*'; 299 | $rsSeq = $rsOptVar . $reOptMod . $rsOptJoin; 300 | $rsEmoji = '(?:' . join('|', [$rsDingbat, $rsRegional, $rsSurrPair]) . ')' . $rsSeq; 301 | 302 | /** @var string $unicodeWords unicode words patterns to be used in preg_match */ 303 | $unicodeWords = '/' . join('|', [ 304 | $rsUpper . '?' . $rsLower . '+' . $rsOptContrLower . '(?=' . join( 305 | '|', 306 | [$rsBreak, $rsUpper, '$'] 307 | ) . ')', 308 | $rsMiscUpper . '+' . $rsOptContrUpper . '(?=' . join( 309 | '|', 310 | [$rsBreak, $rsUpper . $rsMiscLower, '$'] 311 | ) . ')', 312 | $rsUpper . '?' . $rsMiscLower . '+' . $rsOptContrLower, 313 | $rsUpper . '+' . $rsOptContrUpper, 314 | $rsOrdUpper, 315 | $rsOrdLower, 316 | $rsDigits, 317 | $rsEmoji, 318 | ]) . '/u'; 319 | if ($pattern === null) { 320 | $hasUnicodeWord = preg_match($hasUnicodeWordRegex, $input); 321 | $pattern = $hasUnicodeWord ? $unicodeWords : $asciiWords; 322 | } 323 | $r = preg_match_all($pattern, $input, $matches, PREG_PATTERN_ORDER); 324 | if ($r === false) { 325 | throw new \RuntimeException('Regex exception'); 326 | } 327 | 328 | return count($matches[0]) > 0 ? $matches[0] : []; 329 | } 330 | 331 | /** 332 | * Converts string, as space separated words, to lower case. 333 | * 334 | * @usage __::lowerCase('--Foo-Bar--'); 335 | * >> 'foo bar' 336 | * 337 | * @param string $input 338 | * 339 | * @return string 340 | */ 341 | public static function lowerCase(string $input): string 342 | { 343 | $words = __::words(preg_replace("/['\x{2019}]/u", '', $input)); 344 | 345 | return array_reduce( 346 | $words, 347 | function ($result, $word) use ($words) { 348 | $isFirst = __::first($words) === $word; 349 | 350 | return $result . (!$isFirst ? ' ' : '') . __::toLower($word); 351 | }, 352 | '' 353 | ); 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /src/Traits/Utilities.php: -------------------------------------------------------------------------------- 1 | > true 12 | * 13 | * @param string $value 14 | * 15 | * @return bool 16 | */ 17 | public static function isEmail(string $value = null): bool 18 | { 19 | return filter_var($value, FILTER_VALIDATE_EMAIL) != false; 20 | } 21 | 22 | /** 23 | * Alis to original time() function which return current time. 24 | * 25 | * @usage __::now(); 26 | * >> 1417546029 27 | * 28 | * @return mixed 29 | */ 30 | public static function now() 31 | { 32 | $now = time(); 33 | 34 | return $now; 35 | } 36 | 37 | /** 38 | * Readable wrapper for strpos() 39 | * 40 | * @usage __::stringContains('waffle', 'wafflecone'); 41 | * >> true 42 | * 43 | * @param string $needle Substring to search for 44 | * @param string $haystack String to search within 45 | * @param int $offset Index of the $haystack we wish to start at 46 | * 47 | * @return bool 48 | */ 49 | public static function stringContains(string $needle, string $haystack, int $offset = 0): bool 50 | { 51 | return strpos($haystack, $needle, $offset) !== false ? true : false; 52 | } 53 | 54 | /** 55 | * Returns the first argument it receives 56 | * 57 | * @usage __::identity('arg1', 'arg2'); 58 | * >> 'arg1' 59 | * 60 | * @return mixed 61 | */ 62 | public static function identity() 63 | { 64 | $args = func_get_args(); 65 | 66 | return isset($args[0]) ? $args[0] : null; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/__.php: -------------------------------------------------------------------------------- 1 |