├── .gitignore ├── LICENSE.md ├── README.md ├── composer.json ├── composer.lock ├── demo ├── images │ ├── Magic-Book-Green.jpg │ ├── avatar-batman.jpg │ ├── avatar-flash.jpg │ ├── avatar-superman.jpg │ ├── avatar-wonder-woman.jpg │ ├── free.jpg │ └── green_magic_misssle_by_scorpio_empire.jpg └── index.php ├── doc └── images │ └── view.png ├── phpunit.xml ├── shema └── matrix.sql ├── src ├── Coord.php ├── Exception │ ├── FilledMatrixException.php │ ├── IncorrectCoordinatesMatrixException.php │ ├── MatrixException.php │ └── UnavailablePositionException.php ├── Matrix.php ├── MatrixManager.php ├── MatrixPositionManager.php └── MatrixRender.php └── tests ├── CoordTest.php ├── MatrixManagerTest.php ├── MatrixPositionManagerTest.php ├── MatrixRenderTest.php └── MatrixTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /vendor -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2010-2018 Google, Inc. http://angularjs.org 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MLM Matrix 2 | ========== 3 | 4 | [![Latest Version](https://img.shields.io/github/tag/nepster-web/php-mlm-matrix.svg?style=flat-square&label=release)](https://github.com/nepster-web/php-mlm-matrix) 5 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/nepster-web/php-mlm-matrix.svg?style=flat-square)](https://packagist.org/packages/nepster-web/php-mlm-matrix) 7 | 8 | Library for working with MLM matrices. 9 | 10 | 11 | Did you find an error? 12 | ----------------------- 13 | If you found an error in the code or grammatical mistake or any inaccuracy, 14 | please create [new issues](https://github.com/nepster-web/php-mlm-matrix/issues/new). 15 | 16 | 17 | What is the MLM matrix? 18 | ----------------------- 19 | 20 | Among the many MLM compensation plans available today, the Matrix plan is among the most popularly 21 | recommended owing to its uncomplicated structure. As it is quite simple in understanding it is 22 | considered very useful and resourceful and can be easily integrated into the MLM business. 23 | 24 | To understand the Matrix plan, it makes sense to first understand its structure. The matrix 25 | has fixed numbers of rows and columns, organizing the numbers in a particular width and depth. 26 | Typically, most MLM Matrix plans follow two types of structures; 2x2 or the 3x3, but there are 27 | exceptions based on company requirements. All the members in a Matrix Plan are positioned 28 | serially from top to bottom or left to right. 29 | 30 | ![demo](./doc/images/view.png "") 31 | 32 | After the matrix is filled, user at level 1 receives a reward and the matrix itself is divided into 33 | several matrices (depends on matrix pow, for example the cubic matrix will be divided into 3 new matrices). 34 | After that, new matrices wait for filling and cycle is repeated. 35 | 36 | 37 | Install 38 | ------- 39 | 40 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 41 | 42 | Either run 43 | 44 | ``` 45 | $ php composer.phar require --prefer-dist nepster-web/php-mlm-matrix "*" 46 | ``` 47 | 48 | or add 49 | 50 | ``` 51 | "nepster-web/php-mlm-matrix": "*" 52 | ``` 53 | 54 | to the `require` section of your `composer.json` file. 55 | 56 | 57 | 58 | Structure 59 | --------- 60 | 61 | * `demo` - Library demo 62 | * `doc` - Documentation files for GitHub 63 | * `shema` - Sample database table schema (MySQL) 64 | * `src` - Main library code 65 | * `tests` - Unit tests 66 | 67 | 68 | 69 | Usage 70 | ----- 71 | 72 | Creating a new matrix object: 73 | ```php 74 | use Nepster\Matrix\Matrix; 75 | 76 | $matrix = new Matrix(3, 2); 77 | ``` 78 | 79 | 80 | Getting information about the matrix: 81 | ```php 82 | $matrix->getDepth(); 83 | $matrix->getPow(); 84 | ``` 85 | 86 | 87 | Get matrix array: 88 | ```php 89 | $matrix->toArray(); 90 | ``` 91 | 92 | 93 | Managing users in the matrix: 94 | ```php 95 | use Nepster\Matrix\Coord; 96 | use Nepster\Matrix\Matrix; 97 | 98 | $matrix = new Matrix(3, 2); 99 | 100 | $matrix->addTenant(null, function() { 101 | // return your user data 102 | }) 103 | 104 | $matrix->addTenant(new Coord(1, 1), function() { 105 | // return your user data 106 | }) 107 | 108 | $matrix->hasTenant(new Coord(0, 0)); 109 | $matrix->hasTenant(new Coord(1, 1)); 110 | 111 | $matrix->removeTenant(new Coord(1, 1)); 112 | ``` 113 | 114 | 115 | Check the correctness of coordinates: 116 | ```php 117 | $matrix->isValidCoord(new Coord(0, 0)); 118 | ``` 119 | 120 | 121 | Check if there are free positions in the matrix: 122 | ```php 123 | $matrix->isFilled(); 124 | ``` 125 | 126 | [For more examples, see the demo file.](./demo/index.php) 127 | 128 | 129 | How can I use database for matrices? 130 | ------------------------------------ 131 | 132 | Based on the different specifics of mlm projects and web development tools, 133 | this library implements only the algorithm of operation of mlm matrices without storage support. 134 | 135 | However, if you works with the database you can easily implement keeping and restore of matrix objects. 136 | You can study the example in the file [MySQL schema](shema/matrix.sql). 137 | 138 | For example, create a new service that allows you to write and/or restore the matrix object from the database: 139 | 140 | ```php 141 | class MatrixService { 142 | 143 | public function findById(int $id): Matrix 144 | { 145 | // You need make a query to the `matrix` table that find the required record 146 | // Use join or another query to retrieve user data from the `matrix_users` table 147 | // Initialize new Matrix object 148 | // Using `addTenant` method that add users to Matrix object (based on data from `matrix_users` table) 149 | // Return the proper Matrix object 150 | } 151 | 152 | public function save(Matrix $matrix): void 153 | { 154 | // Get the matrix array using the `$matrix->toArray()` method 155 | // Create a valid request to save data to the database 156 | // - Most likely in a relational database you will have 2 tables (matrices and matrix_users) 157 | // - Don`t forget to check a new matrix is being created or edited an already existing matrix 158 | 159 | // Note1: Write down users with depth and number for further recovery 160 | // Note2: Don`t write coordinates with empty positions to the database. 161 | } 162 | 163 | } 164 | ``` 165 | 166 | 167 | Testing 168 | ------- 169 | 170 | ```$ phpunit``` 171 | 172 | or 173 | 174 | ```$ vendor/bin/phpunit``` 175 | 176 | 177 | License 178 | ------- 179 | This library is licensed under the MIT License - see the LICENSE file for details. -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nepster-web/php-mlm-matrix", 3 | "description": "Library for working with mlm matrices", 4 | "type": "library", 5 | "keywords": ["mlm matrix", "network marketing", "mlm marketing"], 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Nepster", 10 | "email": "nepsterxxx@mail.ru" 11 | } 12 | ], 13 | "support": { 14 | "issues": "https://github.com/nepster-web/php-mlm-matrix/issues", 15 | "source": "https://github.com/nepster-web/php-mlm-matrix" 16 | }, 17 | "require": { 18 | "php": ">=7.2", 19 | "ext-json": "*" 20 | }, 21 | "require-dev": { 22 | "phpunit/phpunit": "7.3.5" 23 | }, 24 | "autoload": { 25 | "psr-4": { 26 | "Nepster\\Matrix\\": "src" 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "d43ef613080086dafef37c065a5e5f00", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "doctrine/instantiator", 12 | "version": "1.1.0", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/doctrine/instantiator.git", 16 | "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", 21 | "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "php": "^7.1" 26 | }, 27 | "require-dev": { 28 | "athletic/athletic": "~0.1.8", 29 | "ext-pdo": "*", 30 | "ext-phar": "*", 31 | "phpunit/phpunit": "^6.2.3", 32 | "squizlabs/php_codesniffer": "^3.0.2" 33 | }, 34 | "type": "library", 35 | "extra": { 36 | "branch-alias": { 37 | "dev-master": "1.2.x-dev" 38 | } 39 | }, 40 | "autoload": { 41 | "psr-4": { 42 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 43 | } 44 | }, 45 | "notification-url": "https://packagist.org/downloads/", 46 | "license": [ 47 | "MIT" 48 | ], 49 | "authors": [ 50 | { 51 | "name": "Marco Pivetta", 52 | "email": "ocramius@gmail.com", 53 | "homepage": "http://ocramius.github.com/" 54 | } 55 | ], 56 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 57 | "homepage": "https://github.com/doctrine/instantiator", 58 | "keywords": [ 59 | "constructor", 60 | "instantiate" 61 | ], 62 | "time": "2017-07-22T11:58:36+00:00" 63 | }, 64 | { 65 | "name": "myclabs/deep-copy", 66 | "version": "1.8.1", 67 | "source": { 68 | "type": "git", 69 | "url": "https://github.com/myclabs/DeepCopy.git", 70 | "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" 71 | }, 72 | "dist": { 73 | "type": "zip", 74 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", 75 | "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", 76 | "shasum": "" 77 | }, 78 | "require": { 79 | "php": "^7.1" 80 | }, 81 | "replace": { 82 | "myclabs/deep-copy": "self.version" 83 | }, 84 | "require-dev": { 85 | "doctrine/collections": "^1.0", 86 | "doctrine/common": "^2.6", 87 | "phpunit/phpunit": "^7.1" 88 | }, 89 | "type": "library", 90 | "autoload": { 91 | "psr-4": { 92 | "DeepCopy\\": "src/DeepCopy/" 93 | }, 94 | "files": [ 95 | "src/DeepCopy/deep_copy.php" 96 | ] 97 | }, 98 | "notification-url": "https://packagist.org/downloads/", 99 | "license": [ 100 | "MIT" 101 | ], 102 | "description": "Create deep copies (clones) of your objects", 103 | "keywords": [ 104 | "clone", 105 | "copy", 106 | "duplicate", 107 | "object", 108 | "object graph" 109 | ], 110 | "time": "2018-06-11T23:09:50+00:00" 111 | }, 112 | { 113 | "name": "phar-io/manifest", 114 | "version": "1.0.3", 115 | "source": { 116 | "type": "git", 117 | "url": "https://github.com/phar-io/manifest.git", 118 | "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" 119 | }, 120 | "dist": { 121 | "type": "zip", 122 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", 123 | "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", 124 | "shasum": "" 125 | }, 126 | "require": { 127 | "ext-dom": "*", 128 | "ext-phar": "*", 129 | "phar-io/version": "^2.0", 130 | "php": "^5.6 || ^7.0" 131 | }, 132 | "type": "library", 133 | "extra": { 134 | "branch-alias": { 135 | "dev-master": "1.0.x-dev" 136 | } 137 | }, 138 | "autoload": { 139 | "classmap": [ 140 | "src/" 141 | ] 142 | }, 143 | "notification-url": "https://packagist.org/downloads/", 144 | "license": [ 145 | "BSD-3-Clause" 146 | ], 147 | "authors": [ 148 | { 149 | "name": "Arne Blankerts", 150 | "email": "arne@blankerts.de", 151 | "role": "Developer" 152 | }, 153 | { 154 | "name": "Sebastian Heuer", 155 | "email": "sebastian@phpeople.de", 156 | "role": "Developer" 157 | }, 158 | { 159 | "name": "Sebastian Bergmann", 160 | "email": "sebastian@phpunit.de", 161 | "role": "Developer" 162 | } 163 | ], 164 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", 165 | "time": "2018-07-08T19:23:20+00:00" 166 | }, 167 | { 168 | "name": "phar-io/version", 169 | "version": "2.0.1", 170 | "source": { 171 | "type": "git", 172 | "url": "https://github.com/phar-io/version.git", 173 | "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" 174 | }, 175 | "dist": { 176 | "type": "zip", 177 | "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", 178 | "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", 179 | "shasum": "" 180 | }, 181 | "require": { 182 | "php": "^5.6 || ^7.0" 183 | }, 184 | "type": "library", 185 | "autoload": { 186 | "classmap": [ 187 | "src/" 188 | ] 189 | }, 190 | "notification-url": "https://packagist.org/downloads/", 191 | "license": [ 192 | "BSD-3-Clause" 193 | ], 194 | "authors": [ 195 | { 196 | "name": "Arne Blankerts", 197 | "email": "arne@blankerts.de", 198 | "role": "Developer" 199 | }, 200 | { 201 | "name": "Sebastian Heuer", 202 | "email": "sebastian@phpeople.de", 203 | "role": "Developer" 204 | }, 205 | { 206 | "name": "Sebastian Bergmann", 207 | "email": "sebastian@phpunit.de", 208 | "role": "Developer" 209 | } 210 | ], 211 | "description": "Library for handling version information and constraints", 212 | "time": "2018-07-08T19:19:57+00:00" 213 | }, 214 | { 215 | "name": "phpdocumentor/reflection-common", 216 | "version": "1.0.1", 217 | "source": { 218 | "type": "git", 219 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 220 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" 221 | }, 222 | "dist": { 223 | "type": "zip", 224 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 225 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", 226 | "shasum": "" 227 | }, 228 | "require": { 229 | "php": ">=5.5" 230 | }, 231 | "require-dev": { 232 | "phpunit/phpunit": "^4.6" 233 | }, 234 | "type": "library", 235 | "extra": { 236 | "branch-alias": { 237 | "dev-master": "1.0.x-dev" 238 | } 239 | }, 240 | "autoload": { 241 | "psr-4": { 242 | "phpDocumentor\\Reflection\\": [ 243 | "src" 244 | ] 245 | } 246 | }, 247 | "notification-url": "https://packagist.org/downloads/", 248 | "license": [ 249 | "MIT" 250 | ], 251 | "authors": [ 252 | { 253 | "name": "Jaap van Otterdijk", 254 | "email": "opensource@ijaap.nl" 255 | } 256 | ], 257 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 258 | "homepage": "http://www.phpdoc.org", 259 | "keywords": [ 260 | "FQSEN", 261 | "phpDocumentor", 262 | "phpdoc", 263 | "reflection", 264 | "static analysis" 265 | ], 266 | "time": "2017-09-11T18:02:19+00:00" 267 | }, 268 | { 269 | "name": "phpdocumentor/reflection-docblock", 270 | "version": "4.3.0", 271 | "source": { 272 | "type": "git", 273 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 274 | "reference": "94fd0001232e47129dd3504189fa1c7225010d08" 275 | }, 276 | "dist": { 277 | "type": "zip", 278 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", 279 | "reference": "94fd0001232e47129dd3504189fa1c7225010d08", 280 | "shasum": "" 281 | }, 282 | "require": { 283 | "php": "^7.0", 284 | "phpdocumentor/reflection-common": "^1.0.0", 285 | "phpdocumentor/type-resolver": "^0.4.0", 286 | "webmozart/assert": "^1.0" 287 | }, 288 | "require-dev": { 289 | "doctrine/instantiator": "~1.0.5", 290 | "mockery/mockery": "^1.0", 291 | "phpunit/phpunit": "^6.4" 292 | }, 293 | "type": "library", 294 | "extra": { 295 | "branch-alias": { 296 | "dev-master": "4.x-dev" 297 | } 298 | }, 299 | "autoload": { 300 | "psr-4": { 301 | "phpDocumentor\\Reflection\\": [ 302 | "src/" 303 | ] 304 | } 305 | }, 306 | "notification-url": "https://packagist.org/downloads/", 307 | "license": [ 308 | "MIT" 309 | ], 310 | "authors": [ 311 | { 312 | "name": "Mike van Riel", 313 | "email": "me@mikevanriel.com" 314 | } 315 | ], 316 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 317 | "time": "2017-11-30T07:14:17+00:00" 318 | }, 319 | { 320 | "name": "phpdocumentor/type-resolver", 321 | "version": "0.4.0", 322 | "source": { 323 | "type": "git", 324 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 325 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" 326 | }, 327 | "dist": { 328 | "type": "zip", 329 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", 330 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", 331 | "shasum": "" 332 | }, 333 | "require": { 334 | "php": "^5.5 || ^7.0", 335 | "phpdocumentor/reflection-common": "^1.0" 336 | }, 337 | "require-dev": { 338 | "mockery/mockery": "^0.9.4", 339 | "phpunit/phpunit": "^5.2||^4.8.24" 340 | }, 341 | "type": "library", 342 | "extra": { 343 | "branch-alias": { 344 | "dev-master": "1.0.x-dev" 345 | } 346 | }, 347 | "autoload": { 348 | "psr-4": { 349 | "phpDocumentor\\Reflection\\": [ 350 | "src/" 351 | ] 352 | } 353 | }, 354 | "notification-url": "https://packagist.org/downloads/", 355 | "license": [ 356 | "MIT" 357 | ], 358 | "authors": [ 359 | { 360 | "name": "Mike van Riel", 361 | "email": "me@mikevanriel.com" 362 | } 363 | ], 364 | "time": "2017-07-14T14:27:02+00:00" 365 | }, 366 | { 367 | "name": "phpspec/prophecy", 368 | "version": "1.8.0", 369 | "source": { 370 | "type": "git", 371 | "url": "https://github.com/phpspec/prophecy.git", 372 | "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" 373 | }, 374 | "dist": { 375 | "type": "zip", 376 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", 377 | "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", 378 | "shasum": "" 379 | }, 380 | "require": { 381 | "doctrine/instantiator": "^1.0.2", 382 | "php": "^5.3|^7.0", 383 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", 384 | "sebastian/comparator": "^1.1|^2.0|^3.0", 385 | "sebastian/recursion-context": "^1.0|^2.0|^3.0" 386 | }, 387 | "require-dev": { 388 | "phpspec/phpspec": "^2.5|^3.2", 389 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" 390 | }, 391 | "type": "library", 392 | "extra": { 393 | "branch-alias": { 394 | "dev-master": "1.8.x-dev" 395 | } 396 | }, 397 | "autoload": { 398 | "psr-0": { 399 | "Prophecy\\": "src/" 400 | } 401 | }, 402 | "notification-url": "https://packagist.org/downloads/", 403 | "license": [ 404 | "MIT" 405 | ], 406 | "authors": [ 407 | { 408 | "name": "Konstantin Kudryashov", 409 | "email": "ever.zet@gmail.com", 410 | "homepage": "http://everzet.com" 411 | }, 412 | { 413 | "name": "Marcello Duarte", 414 | "email": "marcello.duarte@gmail.com" 415 | } 416 | ], 417 | "description": "Highly opinionated mocking framework for PHP 5.3+", 418 | "homepage": "https://github.com/phpspec/prophecy", 419 | "keywords": [ 420 | "Double", 421 | "Dummy", 422 | "fake", 423 | "mock", 424 | "spy", 425 | "stub" 426 | ], 427 | "time": "2018-08-05T17:53:17+00:00" 428 | }, 429 | { 430 | "name": "phpunit/php-code-coverage", 431 | "version": "6.1.0", 432 | "source": { 433 | "type": "git", 434 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 435 | "reference": "0685fb6a43aed1b2e09804d1aaf17144c82861f8" 436 | }, 437 | "dist": { 438 | "type": "zip", 439 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0685fb6a43aed1b2e09804d1aaf17144c82861f8", 440 | "reference": "0685fb6a43aed1b2e09804d1aaf17144c82861f8", 441 | "shasum": "" 442 | }, 443 | "require": { 444 | "ext-dom": "*", 445 | "ext-xmlwriter": "*", 446 | "php": "^7.1", 447 | "phpunit/php-file-iterator": "^2.0", 448 | "phpunit/php-text-template": "^1.2.1", 449 | "phpunit/php-token-stream": "^3.0", 450 | "sebastian/code-unit-reverse-lookup": "^1.0.1", 451 | "sebastian/environment": "^3.1", 452 | "sebastian/version": "^2.0.1", 453 | "theseer/tokenizer": "^1.1" 454 | }, 455 | "require-dev": { 456 | "phpunit/phpunit": "^7.0" 457 | }, 458 | "suggest": { 459 | "ext-xdebug": "^2.6.0" 460 | }, 461 | "type": "library", 462 | "extra": { 463 | "branch-alias": { 464 | "dev-master": "6.1-dev" 465 | } 466 | }, 467 | "autoload": { 468 | "classmap": [ 469 | "src/" 470 | ] 471 | }, 472 | "notification-url": "https://packagist.org/downloads/", 473 | "license": [ 474 | "BSD-3-Clause" 475 | ], 476 | "authors": [ 477 | { 478 | "name": "Sebastian Bergmann", 479 | "email": "sebastian@phpunit.de", 480 | "role": "lead" 481 | } 482 | ], 483 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 484 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 485 | "keywords": [ 486 | "coverage", 487 | "testing", 488 | "xunit" 489 | ], 490 | "time": "2018-10-16T05:37:37+00:00" 491 | }, 492 | { 493 | "name": "phpunit/php-file-iterator", 494 | "version": "2.0.2", 495 | "source": { 496 | "type": "git", 497 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 498 | "reference": "050bedf145a257b1ff02746c31894800e5122946" 499 | }, 500 | "dist": { 501 | "type": "zip", 502 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", 503 | "reference": "050bedf145a257b1ff02746c31894800e5122946", 504 | "shasum": "" 505 | }, 506 | "require": { 507 | "php": "^7.1" 508 | }, 509 | "require-dev": { 510 | "phpunit/phpunit": "^7.1" 511 | }, 512 | "type": "library", 513 | "extra": { 514 | "branch-alias": { 515 | "dev-master": "2.0.x-dev" 516 | } 517 | }, 518 | "autoload": { 519 | "classmap": [ 520 | "src/" 521 | ] 522 | }, 523 | "notification-url": "https://packagist.org/downloads/", 524 | "license": [ 525 | "BSD-3-Clause" 526 | ], 527 | "authors": [ 528 | { 529 | "name": "Sebastian Bergmann", 530 | "email": "sebastian@phpunit.de", 531 | "role": "lead" 532 | } 533 | ], 534 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 535 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 536 | "keywords": [ 537 | "filesystem", 538 | "iterator" 539 | ], 540 | "time": "2018-09-13T20:33:42+00:00" 541 | }, 542 | { 543 | "name": "phpunit/php-text-template", 544 | "version": "1.2.1", 545 | "source": { 546 | "type": "git", 547 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 548 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 549 | }, 550 | "dist": { 551 | "type": "zip", 552 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 553 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 554 | "shasum": "" 555 | }, 556 | "require": { 557 | "php": ">=5.3.3" 558 | }, 559 | "type": "library", 560 | "autoload": { 561 | "classmap": [ 562 | "src/" 563 | ] 564 | }, 565 | "notification-url": "https://packagist.org/downloads/", 566 | "license": [ 567 | "BSD-3-Clause" 568 | ], 569 | "authors": [ 570 | { 571 | "name": "Sebastian Bergmann", 572 | "email": "sebastian@phpunit.de", 573 | "role": "lead" 574 | } 575 | ], 576 | "description": "Simple template engine.", 577 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 578 | "keywords": [ 579 | "template" 580 | ], 581 | "time": "2015-06-21T13:50:34+00:00" 582 | }, 583 | { 584 | "name": "phpunit/php-timer", 585 | "version": "2.0.0", 586 | "source": { 587 | "type": "git", 588 | "url": "https://github.com/sebastianbergmann/php-timer.git", 589 | "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f" 590 | }, 591 | "dist": { 592 | "type": "zip", 593 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f", 594 | "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f", 595 | "shasum": "" 596 | }, 597 | "require": { 598 | "php": "^7.1" 599 | }, 600 | "require-dev": { 601 | "phpunit/phpunit": "^7.0" 602 | }, 603 | "type": "library", 604 | "extra": { 605 | "branch-alias": { 606 | "dev-master": "2.0-dev" 607 | } 608 | }, 609 | "autoload": { 610 | "classmap": [ 611 | "src/" 612 | ] 613 | }, 614 | "notification-url": "https://packagist.org/downloads/", 615 | "license": [ 616 | "BSD-3-Clause" 617 | ], 618 | "authors": [ 619 | { 620 | "name": "Sebastian Bergmann", 621 | "email": "sebastian@phpunit.de", 622 | "role": "lead" 623 | } 624 | ], 625 | "description": "Utility class for timing", 626 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 627 | "keywords": [ 628 | "timer" 629 | ], 630 | "time": "2018-02-01T13:07:23+00:00" 631 | }, 632 | { 633 | "name": "phpunit/php-token-stream", 634 | "version": "3.0.0", 635 | "source": { 636 | "type": "git", 637 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 638 | "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace" 639 | }, 640 | "dist": { 641 | "type": "zip", 642 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace", 643 | "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace", 644 | "shasum": "" 645 | }, 646 | "require": { 647 | "ext-tokenizer": "*", 648 | "php": "^7.1" 649 | }, 650 | "require-dev": { 651 | "phpunit/phpunit": "^7.0" 652 | }, 653 | "type": "library", 654 | "extra": { 655 | "branch-alias": { 656 | "dev-master": "3.0-dev" 657 | } 658 | }, 659 | "autoload": { 660 | "classmap": [ 661 | "src/" 662 | ] 663 | }, 664 | "notification-url": "https://packagist.org/downloads/", 665 | "license": [ 666 | "BSD-3-Clause" 667 | ], 668 | "authors": [ 669 | { 670 | "name": "Sebastian Bergmann", 671 | "email": "sebastian@phpunit.de" 672 | } 673 | ], 674 | "description": "Wrapper around PHP's tokenizer extension.", 675 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 676 | "keywords": [ 677 | "tokenizer" 678 | ], 679 | "time": "2018-02-01T13:16:43+00:00" 680 | }, 681 | { 682 | "name": "phpunit/phpunit", 683 | "version": "7.3.5", 684 | "source": { 685 | "type": "git", 686 | "url": "https://github.com/sebastianbergmann/phpunit.git", 687 | "reference": "7b331efabbb628c518c408fdfcaf571156775de2" 688 | }, 689 | "dist": { 690 | "type": "zip", 691 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7b331efabbb628c518c408fdfcaf571156775de2", 692 | "reference": "7b331efabbb628c518c408fdfcaf571156775de2", 693 | "shasum": "" 694 | }, 695 | "require": { 696 | "doctrine/instantiator": "^1.1", 697 | "ext-dom": "*", 698 | "ext-json": "*", 699 | "ext-libxml": "*", 700 | "ext-mbstring": "*", 701 | "ext-xml": "*", 702 | "myclabs/deep-copy": "^1.7", 703 | "phar-io/manifest": "^1.0.2", 704 | "phar-io/version": "^2.0", 705 | "php": "^7.1", 706 | "phpspec/prophecy": "^1.7", 707 | "phpunit/php-code-coverage": "^6.0.7", 708 | "phpunit/php-file-iterator": "^2.0.1", 709 | "phpunit/php-text-template": "^1.2.1", 710 | "phpunit/php-timer": "^2.0", 711 | "sebastian/comparator": "^3.0", 712 | "sebastian/diff": "^3.0", 713 | "sebastian/environment": "^3.1", 714 | "sebastian/exporter": "^3.1", 715 | "sebastian/global-state": "^2.0", 716 | "sebastian/object-enumerator": "^3.0.3", 717 | "sebastian/resource-operations": "^1.0", 718 | "sebastian/version": "^2.0.1" 719 | }, 720 | "conflict": { 721 | "phpunit/phpunit-mock-objects": "*" 722 | }, 723 | "require-dev": { 724 | "ext-pdo": "*" 725 | }, 726 | "suggest": { 727 | "ext-soap": "*", 728 | "ext-xdebug": "*", 729 | "phpunit/php-invoker": "^2.0" 730 | }, 731 | "bin": [ 732 | "phpunit" 733 | ], 734 | "type": "library", 735 | "extra": { 736 | "branch-alias": { 737 | "dev-master": "7.3-dev" 738 | } 739 | }, 740 | "autoload": { 741 | "classmap": [ 742 | "src/" 743 | ] 744 | }, 745 | "notification-url": "https://packagist.org/downloads/", 746 | "license": [ 747 | "BSD-3-Clause" 748 | ], 749 | "authors": [ 750 | { 751 | "name": "Sebastian Bergmann", 752 | "email": "sebastian@phpunit.de", 753 | "role": "lead" 754 | } 755 | ], 756 | "description": "The PHP Unit Testing framework.", 757 | "homepage": "https://phpunit.de/", 758 | "keywords": [ 759 | "phpunit", 760 | "testing", 761 | "xunit" 762 | ], 763 | "time": "2018-09-08T15:14:29+00:00" 764 | }, 765 | { 766 | "name": "sebastian/code-unit-reverse-lookup", 767 | "version": "1.0.1", 768 | "source": { 769 | "type": "git", 770 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 771 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" 772 | }, 773 | "dist": { 774 | "type": "zip", 775 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 776 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", 777 | "shasum": "" 778 | }, 779 | "require": { 780 | "php": "^5.6 || ^7.0" 781 | }, 782 | "require-dev": { 783 | "phpunit/phpunit": "^5.7 || ^6.0" 784 | }, 785 | "type": "library", 786 | "extra": { 787 | "branch-alias": { 788 | "dev-master": "1.0.x-dev" 789 | } 790 | }, 791 | "autoload": { 792 | "classmap": [ 793 | "src/" 794 | ] 795 | }, 796 | "notification-url": "https://packagist.org/downloads/", 797 | "license": [ 798 | "BSD-3-Clause" 799 | ], 800 | "authors": [ 801 | { 802 | "name": "Sebastian Bergmann", 803 | "email": "sebastian@phpunit.de" 804 | } 805 | ], 806 | "description": "Looks up which function or method a line of code belongs to", 807 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 808 | "time": "2017-03-04T06:30:41+00:00" 809 | }, 810 | { 811 | "name": "sebastian/comparator", 812 | "version": "3.0.2", 813 | "source": { 814 | "type": "git", 815 | "url": "https://github.com/sebastianbergmann/comparator.git", 816 | "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" 817 | }, 818 | "dist": { 819 | "type": "zip", 820 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", 821 | "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", 822 | "shasum": "" 823 | }, 824 | "require": { 825 | "php": "^7.1", 826 | "sebastian/diff": "^3.0", 827 | "sebastian/exporter": "^3.1" 828 | }, 829 | "require-dev": { 830 | "phpunit/phpunit": "^7.1" 831 | }, 832 | "type": "library", 833 | "extra": { 834 | "branch-alias": { 835 | "dev-master": "3.0-dev" 836 | } 837 | }, 838 | "autoload": { 839 | "classmap": [ 840 | "src/" 841 | ] 842 | }, 843 | "notification-url": "https://packagist.org/downloads/", 844 | "license": [ 845 | "BSD-3-Clause" 846 | ], 847 | "authors": [ 848 | { 849 | "name": "Jeff Welch", 850 | "email": "whatthejeff@gmail.com" 851 | }, 852 | { 853 | "name": "Volker Dusch", 854 | "email": "github@wallbash.com" 855 | }, 856 | { 857 | "name": "Bernhard Schussek", 858 | "email": "bschussek@2bepublished.at" 859 | }, 860 | { 861 | "name": "Sebastian Bergmann", 862 | "email": "sebastian@phpunit.de" 863 | } 864 | ], 865 | "description": "Provides the functionality to compare PHP values for equality", 866 | "homepage": "https://github.com/sebastianbergmann/comparator", 867 | "keywords": [ 868 | "comparator", 869 | "compare", 870 | "equality" 871 | ], 872 | "time": "2018-07-12T15:12:46+00:00" 873 | }, 874 | { 875 | "name": "sebastian/diff", 876 | "version": "3.0.1", 877 | "source": { 878 | "type": "git", 879 | "url": "https://github.com/sebastianbergmann/diff.git", 880 | "reference": "366541b989927187c4ca70490a35615d3fef2dce" 881 | }, 882 | "dist": { 883 | "type": "zip", 884 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/366541b989927187c4ca70490a35615d3fef2dce", 885 | "reference": "366541b989927187c4ca70490a35615d3fef2dce", 886 | "shasum": "" 887 | }, 888 | "require": { 889 | "php": "^7.1" 890 | }, 891 | "require-dev": { 892 | "phpunit/phpunit": "^7.0", 893 | "symfony/process": "^2 || ^3.3 || ^4" 894 | }, 895 | "type": "library", 896 | "extra": { 897 | "branch-alias": { 898 | "dev-master": "3.0-dev" 899 | } 900 | }, 901 | "autoload": { 902 | "classmap": [ 903 | "src/" 904 | ] 905 | }, 906 | "notification-url": "https://packagist.org/downloads/", 907 | "license": [ 908 | "BSD-3-Clause" 909 | ], 910 | "authors": [ 911 | { 912 | "name": "Kore Nordmann", 913 | "email": "mail@kore-nordmann.de" 914 | }, 915 | { 916 | "name": "Sebastian Bergmann", 917 | "email": "sebastian@phpunit.de" 918 | } 919 | ], 920 | "description": "Diff implementation", 921 | "homepage": "https://github.com/sebastianbergmann/diff", 922 | "keywords": [ 923 | "diff", 924 | "udiff", 925 | "unidiff", 926 | "unified diff" 927 | ], 928 | "time": "2018-06-10T07:54:39+00:00" 929 | }, 930 | { 931 | "name": "sebastian/environment", 932 | "version": "3.1.0", 933 | "source": { 934 | "type": "git", 935 | "url": "https://github.com/sebastianbergmann/environment.git", 936 | "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" 937 | }, 938 | "dist": { 939 | "type": "zip", 940 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", 941 | "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", 942 | "shasum": "" 943 | }, 944 | "require": { 945 | "php": "^7.0" 946 | }, 947 | "require-dev": { 948 | "phpunit/phpunit": "^6.1" 949 | }, 950 | "type": "library", 951 | "extra": { 952 | "branch-alias": { 953 | "dev-master": "3.1.x-dev" 954 | } 955 | }, 956 | "autoload": { 957 | "classmap": [ 958 | "src/" 959 | ] 960 | }, 961 | "notification-url": "https://packagist.org/downloads/", 962 | "license": [ 963 | "BSD-3-Clause" 964 | ], 965 | "authors": [ 966 | { 967 | "name": "Sebastian Bergmann", 968 | "email": "sebastian@phpunit.de" 969 | } 970 | ], 971 | "description": "Provides functionality to handle HHVM/PHP environments", 972 | "homepage": "http://www.github.com/sebastianbergmann/environment", 973 | "keywords": [ 974 | "Xdebug", 975 | "environment", 976 | "hhvm" 977 | ], 978 | "time": "2017-07-01T08:51:00+00:00" 979 | }, 980 | { 981 | "name": "sebastian/exporter", 982 | "version": "3.1.0", 983 | "source": { 984 | "type": "git", 985 | "url": "https://github.com/sebastianbergmann/exporter.git", 986 | "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" 987 | }, 988 | "dist": { 989 | "type": "zip", 990 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", 991 | "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", 992 | "shasum": "" 993 | }, 994 | "require": { 995 | "php": "^7.0", 996 | "sebastian/recursion-context": "^3.0" 997 | }, 998 | "require-dev": { 999 | "ext-mbstring": "*", 1000 | "phpunit/phpunit": "^6.0" 1001 | }, 1002 | "type": "library", 1003 | "extra": { 1004 | "branch-alias": { 1005 | "dev-master": "3.1.x-dev" 1006 | } 1007 | }, 1008 | "autoload": { 1009 | "classmap": [ 1010 | "src/" 1011 | ] 1012 | }, 1013 | "notification-url": "https://packagist.org/downloads/", 1014 | "license": [ 1015 | "BSD-3-Clause" 1016 | ], 1017 | "authors": [ 1018 | { 1019 | "name": "Jeff Welch", 1020 | "email": "whatthejeff@gmail.com" 1021 | }, 1022 | { 1023 | "name": "Volker Dusch", 1024 | "email": "github@wallbash.com" 1025 | }, 1026 | { 1027 | "name": "Bernhard Schussek", 1028 | "email": "bschussek@2bepublished.at" 1029 | }, 1030 | { 1031 | "name": "Sebastian Bergmann", 1032 | "email": "sebastian@phpunit.de" 1033 | }, 1034 | { 1035 | "name": "Adam Harvey", 1036 | "email": "aharvey@php.net" 1037 | } 1038 | ], 1039 | "description": "Provides the functionality to export PHP variables for visualization", 1040 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 1041 | "keywords": [ 1042 | "export", 1043 | "exporter" 1044 | ], 1045 | "time": "2017-04-03T13:19:02+00:00" 1046 | }, 1047 | { 1048 | "name": "sebastian/global-state", 1049 | "version": "2.0.0", 1050 | "source": { 1051 | "type": "git", 1052 | "url": "https://github.com/sebastianbergmann/global-state.git", 1053 | "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" 1054 | }, 1055 | "dist": { 1056 | "type": "zip", 1057 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", 1058 | "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", 1059 | "shasum": "" 1060 | }, 1061 | "require": { 1062 | "php": "^7.0" 1063 | }, 1064 | "require-dev": { 1065 | "phpunit/phpunit": "^6.0" 1066 | }, 1067 | "suggest": { 1068 | "ext-uopz": "*" 1069 | }, 1070 | "type": "library", 1071 | "extra": { 1072 | "branch-alias": { 1073 | "dev-master": "2.0-dev" 1074 | } 1075 | }, 1076 | "autoload": { 1077 | "classmap": [ 1078 | "src/" 1079 | ] 1080 | }, 1081 | "notification-url": "https://packagist.org/downloads/", 1082 | "license": [ 1083 | "BSD-3-Clause" 1084 | ], 1085 | "authors": [ 1086 | { 1087 | "name": "Sebastian Bergmann", 1088 | "email": "sebastian@phpunit.de" 1089 | } 1090 | ], 1091 | "description": "Snapshotting of global state", 1092 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1093 | "keywords": [ 1094 | "global state" 1095 | ], 1096 | "time": "2017-04-27T15:39:26+00:00" 1097 | }, 1098 | { 1099 | "name": "sebastian/object-enumerator", 1100 | "version": "3.0.3", 1101 | "source": { 1102 | "type": "git", 1103 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1104 | "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" 1105 | }, 1106 | "dist": { 1107 | "type": "zip", 1108 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", 1109 | "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", 1110 | "shasum": "" 1111 | }, 1112 | "require": { 1113 | "php": "^7.0", 1114 | "sebastian/object-reflector": "^1.1.1", 1115 | "sebastian/recursion-context": "^3.0" 1116 | }, 1117 | "require-dev": { 1118 | "phpunit/phpunit": "^6.0" 1119 | }, 1120 | "type": "library", 1121 | "extra": { 1122 | "branch-alias": { 1123 | "dev-master": "3.0.x-dev" 1124 | } 1125 | }, 1126 | "autoload": { 1127 | "classmap": [ 1128 | "src/" 1129 | ] 1130 | }, 1131 | "notification-url": "https://packagist.org/downloads/", 1132 | "license": [ 1133 | "BSD-3-Clause" 1134 | ], 1135 | "authors": [ 1136 | { 1137 | "name": "Sebastian Bergmann", 1138 | "email": "sebastian@phpunit.de" 1139 | } 1140 | ], 1141 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1142 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1143 | "time": "2017-08-03T12:35:26+00:00" 1144 | }, 1145 | { 1146 | "name": "sebastian/object-reflector", 1147 | "version": "1.1.1", 1148 | "source": { 1149 | "type": "git", 1150 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 1151 | "reference": "773f97c67f28de00d397be301821b06708fca0be" 1152 | }, 1153 | "dist": { 1154 | "type": "zip", 1155 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", 1156 | "reference": "773f97c67f28de00d397be301821b06708fca0be", 1157 | "shasum": "" 1158 | }, 1159 | "require": { 1160 | "php": "^7.0" 1161 | }, 1162 | "require-dev": { 1163 | "phpunit/phpunit": "^6.0" 1164 | }, 1165 | "type": "library", 1166 | "extra": { 1167 | "branch-alias": { 1168 | "dev-master": "1.1-dev" 1169 | } 1170 | }, 1171 | "autoload": { 1172 | "classmap": [ 1173 | "src/" 1174 | ] 1175 | }, 1176 | "notification-url": "https://packagist.org/downloads/", 1177 | "license": [ 1178 | "BSD-3-Clause" 1179 | ], 1180 | "authors": [ 1181 | { 1182 | "name": "Sebastian Bergmann", 1183 | "email": "sebastian@phpunit.de" 1184 | } 1185 | ], 1186 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 1187 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 1188 | "time": "2017-03-29T09:07:27+00:00" 1189 | }, 1190 | { 1191 | "name": "sebastian/recursion-context", 1192 | "version": "3.0.0", 1193 | "source": { 1194 | "type": "git", 1195 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1196 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" 1197 | }, 1198 | "dist": { 1199 | "type": "zip", 1200 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", 1201 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", 1202 | "shasum": "" 1203 | }, 1204 | "require": { 1205 | "php": "^7.0" 1206 | }, 1207 | "require-dev": { 1208 | "phpunit/phpunit": "^6.0" 1209 | }, 1210 | "type": "library", 1211 | "extra": { 1212 | "branch-alias": { 1213 | "dev-master": "3.0.x-dev" 1214 | } 1215 | }, 1216 | "autoload": { 1217 | "classmap": [ 1218 | "src/" 1219 | ] 1220 | }, 1221 | "notification-url": "https://packagist.org/downloads/", 1222 | "license": [ 1223 | "BSD-3-Clause" 1224 | ], 1225 | "authors": [ 1226 | { 1227 | "name": "Jeff Welch", 1228 | "email": "whatthejeff@gmail.com" 1229 | }, 1230 | { 1231 | "name": "Sebastian Bergmann", 1232 | "email": "sebastian@phpunit.de" 1233 | }, 1234 | { 1235 | "name": "Adam Harvey", 1236 | "email": "aharvey@php.net" 1237 | } 1238 | ], 1239 | "description": "Provides functionality to recursively process PHP variables", 1240 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 1241 | "time": "2017-03-03T06:23:57+00:00" 1242 | }, 1243 | { 1244 | "name": "sebastian/resource-operations", 1245 | "version": "1.0.0", 1246 | "source": { 1247 | "type": "git", 1248 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 1249 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" 1250 | }, 1251 | "dist": { 1252 | "type": "zip", 1253 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1254 | "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", 1255 | "shasum": "" 1256 | }, 1257 | "require": { 1258 | "php": ">=5.6.0" 1259 | }, 1260 | "type": "library", 1261 | "extra": { 1262 | "branch-alias": { 1263 | "dev-master": "1.0.x-dev" 1264 | } 1265 | }, 1266 | "autoload": { 1267 | "classmap": [ 1268 | "src/" 1269 | ] 1270 | }, 1271 | "notification-url": "https://packagist.org/downloads/", 1272 | "license": [ 1273 | "BSD-3-Clause" 1274 | ], 1275 | "authors": [ 1276 | { 1277 | "name": "Sebastian Bergmann", 1278 | "email": "sebastian@phpunit.de" 1279 | } 1280 | ], 1281 | "description": "Provides a list of PHP built-in functions that operate on resources", 1282 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 1283 | "time": "2015-07-28T20:34:47+00:00" 1284 | }, 1285 | { 1286 | "name": "sebastian/version", 1287 | "version": "2.0.1", 1288 | "source": { 1289 | "type": "git", 1290 | "url": "https://github.com/sebastianbergmann/version.git", 1291 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" 1292 | }, 1293 | "dist": { 1294 | "type": "zip", 1295 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", 1296 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", 1297 | "shasum": "" 1298 | }, 1299 | "require": { 1300 | "php": ">=5.6" 1301 | }, 1302 | "type": "library", 1303 | "extra": { 1304 | "branch-alias": { 1305 | "dev-master": "2.0.x-dev" 1306 | } 1307 | }, 1308 | "autoload": { 1309 | "classmap": [ 1310 | "src/" 1311 | ] 1312 | }, 1313 | "notification-url": "https://packagist.org/downloads/", 1314 | "license": [ 1315 | "BSD-3-Clause" 1316 | ], 1317 | "authors": [ 1318 | { 1319 | "name": "Sebastian Bergmann", 1320 | "email": "sebastian@phpunit.de", 1321 | "role": "lead" 1322 | } 1323 | ], 1324 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1325 | "homepage": "https://github.com/sebastianbergmann/version", 1326 | "time": "2016-10-03T07:35:21+00:00" 1327 | }, 1328 | { 1329 | "name": "theseer/tokenizer", 1330 | "version": "1.1.0", 1331 | "source": { 1332 | "type": "git", 1333 | "url": "https://github.com/theseer/tokenizer.git", 1334 | "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" 1335 | }, 1336 | "dist": { 1337 | "type": "zip", 1338 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", 1339 | "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", 1340 | "shasum": "" 1341 | }, 1342 | "require": { 1343 | "ext-dom": "*", 1344 | "ext-tokenizer": "*", 1345 | "ext-xmlwriter": "*", 1346 | "php": "^7.0" 1347 | }, 1348 | "type": "library", 1349 | "autoload": { 1350 | "classmap": [ 1351 | "src/" 1352 | ] 1353 | }, 1354 | "notification-url": "https://packagist.org/downloads/", 1355 | "license": [ 1356 | "BSD-3-Clause" 1357 | ], 1358 | "authors": [ 1359 | { 1360 | "name": "Arne Blankerts", 1361 | "email": "arne@blankerts.de", 1362 | "role": "Developer" 1363 | } 1364 | ], 1365 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", 1366 | "time": "2017-04-07T12:08:54+00:00" 1367 | }, 1368 | { 1369 | "name": "webmozart/assert", 1370 | "version": "1.3.0", 1371 | "source": { 1372 | "type": "git", 1373 | "url": "https://github.com/webmozart/assert.git", 1374 | "reference": "0df1908962e7a3071564e857d86874dad1ef204a" 1375 | }, 1376 | "dist": { 1377 | "type": "zip", 1378 | "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", 1379 | "reference": "0df1908962e7a3071564e857d86874dad1ef204a", 1380 | "shasum": "" 1381 | }, 1382 | "require": { 1383 | "php": "^5.3.3 || ^7.0" 1384 | }, 1385 | "require-dev": { 1386 | "phpunit/phpunit": "^4.6", 1387 | "sebastian/version": "^1.0.1" 1388 | }, 1389 | "type": "library", 1390 | "extra": { 1391 | "branch-alias": { 1392 | "dev-master": "1.3-dev" 1393 | } 1394 | }, 1395 | "autoload": { 1396 | "psr-4": { 1397 | "Webmozart\\Assert\\": "src/" 1398 | } 1399 | }, 1400 | "notification-url": "https://packagist.org/downloads/", 1401 | "license": [ 1402 | "MIT" 1403 | ], 1404 | "authors": [ 1405 | { 1406 | "name": "Bernhard Schussek", 1407 | "email": "bschussek@gmail.com" 1408 | } 1409 | ], 1410 | "description": "Assertions to validate method input/output with nice error messages.", 1411 | "keywords": [ 1412 | "assert", 1413 | "check", 1414 | "validate" 1415 | ], 1416 | "time": "2018-01-29T19:49:41+00:00" 1417 | } 1418 | ], 1419 | "aliases": [], 1420 | "minimum-stability": "stable", 1421 | "stability-flags": [], 1422 | "prefer-stable": false, 1423 | "prefer-lowest": false, 1424 | "platform": { 1425 | "php": ">=7.2", 1426 | "ext-json": "*" 1427 | }, 1428 | "platform-dev": [] 1429 | } 1430 | -------------------------------------------------------------------------------- /demo/images/Magic-Book-Green.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepster-web/php-mlm-matrix/b4c96e6eb8eec3671b40db1cf609be7ced861698/demo/images/Magic-Book-Green.jpg -------------------------------------------------------------------------------- /demo/images/avatar-batman.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepster-web/php-mlm-matrix/b4c96e6eb8eec3671b40db1cf609be7ced861698/demo/images/avatar-batman.jpg -------------------------------------------------------------------------------- /demo/images/avatar-flash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepster-web/php-mlm-matrix/b4c96e6eb8eec3671b40db1cf609be7ced861698/demo/images/avatar-flash.jpg -------------------------------------------------------------------------------- /demo/images/avatar-superman.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepster-web/php-mlm-matrix/b4c96e6eb8eec3671b40db1cf609be7ced861698/demo/images/avatar-superman.jpg -------------------------------------------------------------------------------- /demo/images/avatar-wonder-woman.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepster-web/php-mlm-matrix/b4c96e6eb8eec3671b40db1cf609be7ced861698/demo/images/avatar-wonder-woman.jpg -------------------------------------------------------------------------------- /demo/images/free.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepster-web/php-mlm-matrix/b4c96e6eb8eec3671b40db1cf609be7ced861698/demo/images/free.jpg -------------------------------------------------------------------------------- /demo/images/green_magic_misssle_by_scorpio_empire.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepster-web/php-mlm-matrix/b4c96e6eb8eec3671b40db1cf609be7ced861698/demo/images/green_magic_misssle_by_scorpio_empire.jpg -------------------------------------------------------------------------------- /demo/index.php: -------------------------------------------------------------------------------- 1 | addTenant(null, function (Coord $coord): array { 16 | return [ 17 | 'name' => 'Superman', 18 | 'avatar' => 'images/avatar-superman.jpg', 19 | ]; 20 | }); 21 | 22 | $matrix->addTenant(null, function (Coord $coord): array { 23 | return [ 24 | 'name' => 'Diana', 25 | 'avatar' => 'images/avatar-wonder-woman.jpg', 26 | ]; 27 | }); 28 | 29 | $matrix->addTenant(null, function (Coord $coord): array { 30 | return [ 31 | 'name' => 'The Flash', 32 | 'avatar' => 'images/avatar-flash.jpg', 33 | ]; 34 | }); 35 | 36 | $matrix->addTenant($matrixPositionManager->positionToCoord(6), function (Coord $coord): array { 37 | return [ 38 | 'name' => 'Batman', 39 | 'avatar' => 'images/avatar-batman.jpg', 40 | ]; 41 | }); 42 | 43 | 44 | // Matrix Render 45 | $render = new MatrixRender($matrix); 46 | $render->setOptions(['class' => 'matrix']); 47 | $render->setDepthOptions(['class' => 'depth']); 48 | $render->setGroupSeparatorOptions(['class' => 'matrix-group-separator']); 49 | $render->setClearOptions(['style' => 'clear:both']); 50 | $render->setGroupJoinOptions(['class' => 'matrix-join-group']); 51 | $render->registerDepthCallback(function (Matrix $matrix, int $d, array $tenants): string { 52 | return '
Depth ' . (++$d) . '
'; 53 | }); 54 | $render->registerCellCallback(function (Matrix $matrix, Coord $coord, $tenant) use ($matrixPositionManager): string { 55 | if ($tenant === null) { 56 | return '
57 | ' . $matrixPositionManager->coordToPosition($coord) . ' 58 |
59 |
60 |
61 |
free
62 |
'; 63 | } 64 | 65 | return '
66 | ' . $matrixPositionManager->coordToPosition($coord) . ' 67 |
68 |
69 | 72 |
73 |
' . $tenant['name'] . '
74 |
'; 75 | }); 76 | 77 | ?> 78 | 79 | 80 | 81 | 82 | 83 | MLM Matrix 84 | 169 | 170 | 171 | 172 | 173 | show() ?> 174 | 175 | 176 | -------------------------------------------------------------------------------- /doc/images/view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepster-web/php-mlm-matrix/b4c96e6eb8eec3671b40db1cf609be7ced861698/doc/images/view.png -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | ./tests/ 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /shema/matrix.sql: -------------------------------------------------------------------------------- 1 | -- ---------------------------- 2 | -- Table structure for matrix 3 | -- ---------------------------- 4 | DROP TABLE IF EXISTS `matrix`; 5 | CREATE TABLE `matrix` ( 6 | `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 7 | `depth` tinyint(4) unsigned NOT NULL DEFAULT '3' COMMENT 'Уровни матрицы', 8 | `pow` tinyint(4) unsigned NOT NULL DEFAULT '2' COMMENT 'Вид матрицы (например двоичная)', 9 | `date_create` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Дата создания', 10 | `date_close` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Дата закрытия', 11 | `filled` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Матрица поделена', 12 | `parent_id` int(11) unsigned DEFAULT NULL COMMENT 'Идентификатор родительской матрицы', 13 | PRIMARY KEY (`id`), 14 | KEY `matrix_alias_id` (`alias_id`), 15 | CONSTRAINT `FK_matrix_parent_id` FOREIGN KEY (`parent_id`) REFERENCES `matrix` (`id`) 16 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Матрицы'; 17 | 18 | -- ---------------------------- 19 | -- Table structure for matrix_users 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `matrix_users`; 22 | CREATE TABLE `matrix_users` ( 23 | `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 24 | `matrix_id` int(11) unsigned NOT NULL COMMENT 'Матрица', 25 | `user_id` int(11) unsigned NOT NULL COMMENT 'Пользователь', 26 | `depth` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Уровень пользователя в матрице', 27 | `number` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Номер пользователя в уровне в матрице', 28 | `date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Дата входа', 29 | PRIMARY KEY (`id`), 30 | KEY `matrix_users_matrix_id` (`matrix_id`), 31 | KEY `matrix_users_user_id` (`user_id`), 32 | CONSTRAINT `FK_matrix_users_matrix_id` FOREIGN KEY (`matrix_id`) REFERENCES `matrix` (`matrix_id`) ON DELETE CASCADE ON UPDATE CASCADE 33 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Пользователи в матрицах'; -------------------------------------------------------------------------------- /src/Coord.php: -------------------------------------------------------------------------------- 1 | depth = $depth; 30 | $this->number = $number; 31 | } 32 | 33 | /** 34 | * @return int 35 | */ 36 | public function getDepth(): int 37 | { 38 | return $this->depth; 39 | } 40 | 41 | /** 42 | * @return int 43 | */ 44 | public function getNumber(): int 45 | { 46 | return $this->number; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Exception/FilledMatrixException.php: -------------------------------------------------------------------------------- 1 | pow = $pow; 44 | $this->depth = $depth; 45 | 46 | $matrix = []; 47 | $pointer = 1; 48 | for ($d = 0; $d < $this->depth; ++$d) { 49 | for ($n = 0; $n < $pointer; ++$n) { 50 | $matrix[$d][$n] = null; 51 | } 52 | $pointer *= $this->pow; 53 | } 54 | 55 | $this->generatedMatrix = $matrix; 56 | } 57 | 58 | /** 59 | * @return int 60 | */ 61 | public function getDepth(): int 62 | { 63 | return $this->depth; 64 | } 65 | 66 | /** 67 | * @return int 68 | */ 69 | public function getPow(): int 70 | { 71 | return $this->pow; 72 | } 73 | 74 | /** 75 | * @return array 76 | */ 77 | public function toArray(): array 78 | { 79 | return $this->generatedMatrix; 80 | } 81 | 82 | /** 83 | * Checks if matrix position is free 84 | * 85 | * @param Coord $coord 86 | * @return bool 87 | * @throws IncorrectCoordinatesMatrixException 88 | */ 89 | public function hasTenant(Coord $coord): bool 90 | { 91 | if ($this->isValidCoord($coord) === false) { 92 | throw new IncorrectCoordinatesMatrixException(); 93 | } 94 | 95 | foreach ($this->generatedMatrix as $d => $depth) { 96 | if ($d === $coord->getDepth()) { 97 | foreach ($depth as $n => $number) { 98 | if ($coord->getNumber() === $n) { 99 | if ($this->generatedMatrix[$d][$n] === null) { 100 | return false; 101 | } 102 | } 103 | } 104 | } 105 | } 106 | 107 | return true; 108 | } 109 | 110 | /** 111 | * Take this matrix position 112 | * 113 | * @param Coord|null $coord 114 | * @param callable $tenant 115 | * @throws FilledMatrixException 116 | * @throws IncorrectCoordinatesMatrixException 117 | * @throws MatrixException 118 | * @throws UnavailablePositionException 119 | */ 120 | public function addTenant(?Coord $coord, callable $tenant): void 121 | { 122 | if ($this->isFilled() === true) { 123 | throw new FilledMatrixException(); 124 | } 125 | 126 | if ($coord !== null && $this->isValidCoord($coord) === false) { 127 | throw new IncorrectCoordinatesMatrixException(); 128 | } 129 | 130 | if ($coord !== null && $this->hasTenant($coord) === true) { 131 | throw new UnavailablePositionException(); 132 | } 133 | 134 | if ($coord === null) { 135 | foreach ($this->generatedMatrix as $d => $depth) { 136 | foreach ($depth as $n => $number) { 137 | if ($number === null) { 138 | $result = call_user_func_array($tenant, [new Coord($d, $n)]); 139 | if ($result === null || (empty($result) && $result !== false)) { 140 | throw new MatrixException('The callable argument $tenant should not return null or be empty'); 141 | } 142 | $this->generatedMatrix[$d][$n] = $result; 143 | return; 144 | } 145 | } 146 | } 147 | } else { 148 | foreach ($this->generatedMatrix as $d => $depth) { 149 | if ($d === $coord->getDepth()) { 150 | foreach ($depth as $n => $number) { 151 | if ($coord->getNumber() === $n) { 152 | $result = call_user_func_array($tenant, [$coord]); 153 | if ($result === null || (empty($result) && $result !== false)) { 154 | throw new MatrixException('The callable argument $tenant should not return null or be empty'); 155 | } 156 | $this->generatedMatrix[$d][$n] = $result; 157 | return; 158 | } 159 | } 160 | } 161 | } 162 | } 163 | } 164 | 165 | /** 166 | * Free this matrix position 167 | * 168 | * @param Coord $coord 169 | * @throws IncorrectCoordinatesMatrixException 170 | */ 171 | public function removeTenant(Coord $coord): void 172 | { 173 | if ($this->isValidCoord($coord) === false) { 174 | throw new IncorrectCoordinatesMatrixException(); 175 | } 176 | 177 | foreach ($this->generatedMatrix as $d => $depth) { 178 | if ($d === $coord->getDepth()) { 179 | foreach ($depth as $n => $number) { 180 | if ($coord->getNumber() === $n) { 181 | $this->generatedMatrix[$d][$n] = null; 182 | break; 183 | } 184 | } 185 | } 186 | } 187 | } 188 | 189 | /** 190 | * Is the matrix of the filled 191 | * 192 | * @return bool 193 | */ 194 | public function isFilled(): bool 195 | { 196 | foreach ($this->generatedMatrix as $d => $depth) { 197 | if (is_array($depth)) { 198 | foreach ($depth as $n => $number) { 199 | if ($number === null) { 200 | return false; 201 | } 202 | } 203 | } 204 | } 205 | 206 | return true; 207 | } 208 | 209 | /** 210 | * Checks the coordinates for validity 211 | * 212 | * @param Coord $coord 213 | * @return bool 214 | */ 215 | public function isValidCoord(Coord $coord): bool 216 | { 217 | if ($coord->getDepth() < 0 || $coord->getDepth() > $this->depth) { 218 | return false; 219 | } 220 | 221 | if ($coord->getNumber() < 0) { 222 | return false; 223 | } 224 | 225 | if (isset($this->generatedMatrix[$coord->getDepth()]) === false) { 226 | return false; 227 | } 228 | 229 | if ($coord->getNumber() > (count($this->generatedMatrix[$coord->getDepth()]) - 1)) { 230 | return false; 231 | } 232 | 233 | return true; 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/MatrixManager.php: -------------------------------------------------------------------------------- 1 | matrix = $matrix; 24 | } 25 | 26 | /** 27 | * @return array 28 | */ 29 | public function division(): array 30 | { 31 | $matrices = []; 32 | $pointer = 1; 33 | 34 | for ($m = 1; $m < $this->matrix->getDepth(); ++$m) { 35 | $matrices[] = array_chunk($this->matrix->toArray()[$m], $pointer); 36 | $pointer *= $this->matrix->getPow(); 37 | } 38 | 39 | $countMatrices = count($matrices); 40 | 41 | $newMatrixArrayList = []; 42 | 43 | $x = 0; 44 | 45 | for ($m = 0; $m < $countMatrices; ++$m) { 46 | $countMatrixDepth = count($matrices[$m]); 47 | for ($n = 0; $n < $countMatrixDepth; ++$n, ++$x) { 48 | $newMatrixArrayList[$x][] = $matrices[$m][$n]; 49 | } 50 | $x = 0; 51 | } 52 | 53 | $newMatrixList = []; 54 | 55 | foreach ($newMatrixArrayList as $m => $newMatrixArray) { 56 | $newMatrixList[$m] = new Matrix($this->matrix->getDepth(), $this->matrix->getPow()); 57 | foreach ($newMatrixArray as $d => $depth) { 58 | foreach ($depth as $n => $number) { 59 | $newMatrixList[$m]->addTenant(new Coord($d, $n), function () use ($d, $n, $newMatrixArray) { 60 | if (isset($newMatrixArray[$d][$n]) && empty($newMatrixArray[$d][$n]) === false) { 61 | return $newMatrixArray[$d][$n]; 62 | } 63 | return false; 64 | }); 65 | } 66 | 67 | } 68 | 69 | } 70 | 71 | return $newMatrixList; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/MatrixPositionManager.php: -------------------------------------------------------------------------------- 1 | matrix = $matrix; 24 | } 25 | 26 | /** 27 | * Converts position to coordinates 28 | * 29 | * For example: 30 | * position: 1 - [depth: 0, number 0] 31 | * position: 2 - [depth: 1, number 0] 32 | * position: 3 - [depth: 1, number 1] 33 | * 34 | * returns null if the position does not match the coordinates 35 | * 36 | * @param int $position 37 | * @return Coord|null 38 | */ 39 | public function positionToCoord(int $position): ?Coord 40 | { 41 | $result = 0; 42 | $pointer = 1; 43 | for ($d = 0; $d < $this->matrix->getDepth(); ++$d) { 44 | for ($n = 0; $n < $pointer; ++$n) { 45 | ++$result; 46 | if ($result === $position) { 47 | return new Coord($d, $n); 48 | } 49 | } 50 | $pointer *= $this->matrix->getPow(); 51 | } 52 | 53 | return null; 54 | } 55 | 56 | /** 57 | * Converts coordinates to position 58 | * 59 | * For example: 60 | * [depth: 0, number 0] - position: 1 61 | * [depth: 1, number 0] - position: 2 62 | * [depth: 1, number 1] - position: 3 63 | * 64 | * returns null if the coordinates are outside the matrix 65 | * 66 | * @param Coord $coord 67 | * @return int|null 68 | */ 69 | public function coordToPosition(Coord $coord): ?int 70 | { 71 | if ($coord->getDepth() === 0 && $coord->getNumber() === 0) { 72 | return 1; 73 | } 74 | 75 | if ($coord->getDepth() > $this->matrix->getDepth()) { 76 | return null; 77 | } 78 | 79 | $position = 0; 80 | $pointer = 1; 81 | for ($d = 0; $d < $this->matrix->getDepth(); ++$d) { 82 | for ($n = 0; $n < $pointer; ++$n) { 83 | ++$position; 84 | if ($d === $coord->getDepth() && $n === $coord->getNumber()) { 85 | return $position; 86 | } 87 | } 88 | $pointer *= $this->matrix->getPow(); 89 | } 90 | 91 | return null; 92 | } 93 | 94 | /** 95 | * Find first free matrix coordinates 96 | * @return Coord|null 97 | */ 98 | public function findFirstFreeCoord(): ?Coord 99 | { 100 | foreach ($this->matrix->toArray() as $d => $depth) { 101 | if (is_array($depth)) { 102 | foreach ($depth as $n => $number) { 103 | if (empty($number)) { 104 | return new Coord($d, $n); 105 | } 106 | } 107 | } 108 | } 109 | 110 | return null; 111 | } 112 | 113 | /** 114 | * Find all free coordinates in the matrix 115 | * @return array 116 | */ 117 | public function findFreeCoords(): array 118 | { 119 | $result = []; 120 | foreach ($this->matrix->toArray() as $l => &$level) { 121 | if (is_array($level)) { 122 | foreach ($level as $n => &$number) { 123 | if (empty($number)) { 124 | $result[] = new Coord($l, $n); 125 | } 126 | } 127 | } 128 | } 129 | 130 | return $result; 131 | } 132 | 133 | /** 134 | * Find all free positions in the matrix 135 | * @return array 136 | */ 137 | public function findFreePositions(): array 138 | { 139 | $result = []; 140 | $freeCoords = $this->findFreeCoords(); 141 | 142 | /** @var Coord $coord */ 143 | foreach ($freeCoords as $coord) { 144 | $result[] = $this->coordToPosition(new Coord($coord->getDepth(), $coord->getNumber())); 145 | } 146 | 147 | return $result; 148 | } 149 | 150 | /** 151 | * Returns the coordinates of all sector positions for the current position 152 | * 153 | * Пример использования: 154 | * $matrix->getCoordBySector($level, $number, $deep, $all) 155 | * 156 | * @param Coord $coord 157 | * @return array 158 | */ 159 | public function findSectorCoordsForNextDepth(Coord $coord): array 160 | { 161 | if ($this->matrix->isValidCoord($coord) === false) { 162 | return []; 163 | } 164 | 165 | $number = [$coord->getNumber()]; 166 | 167 | $newChildrenLevel = []; 168 | foreach ($number as $pos) { 169 | $newChildrenLevel = array_merge( 170 | $newChildrenLevel, 171 | range( 172 | $pos * $this->matrix->getPow(), 173 | ($pos + 1) * $this->matrix->getPow() - 1 174 | ) 175 | ); 176 | } 177 | 178 | $newResultDepth = []; 179 | 180 | foreach ($newChildrenLevel as $child) { 181 | $newCoord = new Coord($coord->getDepth() + 1, $child); 182 | if ($this->matrix->isValidCoord($newCoord)) { 183 | $newResultDepth[] = $newCoord; 184 | } 185 | } 186 | 187 | return $newResultDepth; 188 | } 189 | 190 | } 191 | -------------------------------------------------------------------------------- /src/MatrixRender.php: -------------------------------------------------------------------------------- 1 | 'matrix']; 31 | 32 | /** 33 | * @var array 34 | */ 35 | private $depthOptions = ['class' => 'depth']; 36 | 37 | /** 38 | * @var array 39 | */ 40 | private $groupSeparatorOptions = ['class' => 'matrix-group-separator']; 41 | 42 | /** 43 | * @var array 44 | */ 45 | private $groupJoinOptions = ['class' => 'matrix-join-group']; 46 | 47 | /** 48 | * @var array 49 | */ 50 | private $clearOptions = ['style' => 'clear:both']; 51 | 52 | /** 53 | * MatrixRender constructor. 54 | * @param Matrix $matrix 55 | */ 56 | public function __construct(Matrix $matrix) 57 | { 58 | $this->matrix = $matrix; 59 | } 60 | 61 | /** 62 | * @param array $options 63 | */ 64 | public function setOptions(array $options): void 65 | { 66 | $this->options = $options; 67 | } 68 | 69 | /** 70 | * @param array $options 71 | */ 72 | public function setDepthOptions(array $options): void 73 | { 74 | $this->depthOptions = $options; 75 | } 76 | 77 | /** 78 | * @param array $options 79 | */ 80 | public function setGroupSeparatorOptions(array $options): void 81 | { 82 | $this->groupSeparatorOptions = $options; 83 | } 84 | 85 | /** 86 | * @param array $options 87 | */ 88 | public function setGroupJoinOptions(array $options): void 89 | { 90 | $this->groupJoinOptions = $options; 91 | } 92 | 93 | /** 94 | * @param array $options 95 | */ 96 | public function setClearOptions(array $options): void 97 | { 98 | $this->clearOptions = $options; 99 | } 100 | 101 | /** 102 | * @param callable $callback 103 | */ 104 | public function registerCellCallback(callable $callback): void 105 | { 106 | $this->cellCallback = $callback; 107 | } 108 | 109 | /** 110 | * @param callable $callback 111 | */ 112 | public function registerDepthCallback(callable $callback): void 113 | { 114 | $this->depthCallback = $callback; 115 | } 116 | 117 | /** 118 | * Возвращает html код матрицы 119 | * @return string 120 | */ 121 | public function show(): string 122 | { 123 | return 'renderTagAttributes($this->options) . '>' . $this->generateMatrixHtml() . ''; 124 | } 125 | 126 | /** 127 | * Generate matrix html 128 | * @return string 129 | */ 130 | protected function generateMatrixHtml(): string 131 | { 132 | $matrixArray = $this->matrix->toArray(); 133 | 134 | $result = ''; 135 | $pV = $this->matrix->getPow() <= 2 ? 2 : pow($this->matrix->getPow(), 2); 136 | 137 | for ($d = 0, $classD = 1; $d < $this->matrix->getDepth(); ++$d, ++$classD) { 138 | 139 | $depthClassCounter = ' depth-' . $classD; 140 | $depthOptions = $this->depthOptions; 141 | if (isset($depthOptions['class'])) { 142 | $depthOptions['class'] .= $depthClassCounter; 143 | } else { 144 | $depthOptions['class'] = $depthClassCounter; 145 | } 146 | 147 | $result .= 'renderTagAttributes($depthOptions) . '>'; 148 | 149 | $result .= call_user_func_array($this->depthCallback, [ 150 | $this->matrix, 151 | $d, 152 | $matrixArray[$d], 153 | ]); 154 | 155 | $countL = count($matrixArray[$d]); 156 | 157 | for ($n = 0, $e = 1; $n < $countL; ++$n, ++$e) { 158 | 159 | if ($d < 3) { 160 | /* event before 4 depth */ 161 | } else { 162 | if ($e === 1) { 163 | $result .= 'renderTagAttributes($this->groupJoinOptions) . '> '; 164 | } 165 | } 166 | 167 | $result .= call_user_func_array($this->cellCallback, [ 168 | $this->matrix, 169 | new Coord($d, $n), 170 | $matrixArray[$d][$n], 171 | ]); 172 | 173 | if ($d < 3) { 174 | if (($n + 1) != count($matrixArray[$d]) && (($n + 1) % $this->matrix->getPow()) === 0) { 175 | $result .= 'renderTagAttributes($this->groupSeparatorOptions) . '>'; 176 | } 177 | } else { 178 | if ($d > 1 && (($n + 1) % $this->matrix->getPow()) === 0) { 179 | $result .= 'renderTagAttributes($this->clearOptions) . '>'; 180 | } 181 | 182 | if ($e === $pV) { 183 | 184 | $result .= ''; 185 | $e = 0; 186 | 187 | if (($n + 1) !== count($matrixArray[$d])) { 188 | $result .= 'renderTagAttributes($this->groupSeparatorOptions) . '>'; 189 | } 190 | } 191 | } 192 | $result .= PHP_EOL; 193 | } 194 | 195 | $result .= 'renderTagAttributes($this->clearOptions) . '>'; 196 | $result .= '' . PHP_EOL; 197 | } 198 | 199 | return $result; 200 | } 201 | 202 | /** 203 | * @param array $attributes 204 | * @return string 205 | */ 206 | protected function renderTagAttributes(array $attributes): string 207 | { 208 | $html = ''; 209 | foreach ($attributes as $name => $value) { 210 | if (is_bool($value)) { 211 | if ($value) { 212 | $html .= " $name"; 213 | } 214 | } else { 215 | if (is_array($value) && $name === 'data') { 216 | foreach ($value as $n => $v) { 217 | if (is_array($v)) { 218 | $html .= " $name-$n='" . json_encode($v, JSON_HEX_APOS) . "'"; 219 | } else { 220 | $html .= " $name-$n=\"" . htmlspecialchars($v) . '"'; 221 | } 222 | } 223 | } else { 224 | if ($value !== null) { 225 | $html .= " $name=\"" . htmlspecialchars($value) . '"'; 226 | } 227 | } 228 | } 229 | } 230 | 231 | return $html; 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /tests/CoordTest.php: -------------------------------------------------------------------------------- 1 | getDepth() ,1); 16 | } 17 | 18 | /** @test */ 19 | public function testItReturnsCurrentNumber(): void 20 | { 21 | $coord = new Coord(1, 2); 22 | 23 | self::assertEquals($coord->getNumber() ,2); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/MatrixManagerTest.php: -------------------------------------------------------------------------------- 1 | addTenant(null, function (): array { 16 | return ['name' => 'John1']; 17 | }); 18 | $matrix->addTenant(null, function (): array { 19 | return ['name' => 'John2']; 20 | }); 21 | $matrix->addTenant(null, function (): array { 22 | return ['name' => 'John3']; 23 | }); 24 | $matrix->addTenant(null, function (): array { 25 | return ['name' => 'John4']; 26 | }); 27 | $matrix->addTenant(null, function (): array { 28 | return ['name' => 'John5']; 29 | }); 30 | $matrix->addTenant(null, function (): array { 31 | return ['name' => 'John6']; 32 | }); 33 | $matrix->addTenant(null, function (): array { 34 | return ['name' => 'John7']; 35 | }); 36 | 37 | $matrixManager = new MatrixManager($matrix); 38 | 39 | $matrices = $matrixManager->division(); 40 | 41 | /** @var Matrix $matrix1 */ 42 | $matrix1 = $matrices[0]; 43 | 44 | /** @var Matrix $matrix2 */ 45 | $matrix2 = $matrices[1]; 46 | 47 | self::assertEquals($matrix1->toArray(), [ 48 | [['name' => 'John2']], 49 | [['name' => 'John4'], ['name' => 'John5']], 50 | [null, null, null, null] 51 | ]); 52 | self::assertEquals($matrix2->toArray(), [ 53 | [['name' => 'John3']], 54 | [['name' => 'John6'], ['name' => 'John7']], 55 | [null, null, null, null] 56 | ]); 57 | } 58 | 59 | /** @test */ 60 | public function testEmptyMatrixDivision(): void 61 | { 62 | $matrix = new Matrix(3, 2); 63 | $matrix->addTenant(null, function (): array { 64 | return ['name' => 'John2']; 65 | }); 66 | 67 | $matrixManager = new MatrixManager($matrix); 68 | 69 | $matrices = $matrixManager->division(); 70 | 71 | /** @var Matrix $matrix1 */ 72 | $matrix1 = $matrices[0]; 73 | 74 | /** @var Matrix $matrix2 */ 75 | $matrix2 = $matrices[1]; 76 | 77 | self::assertEquals($matrix1->toArray(), [ 78 | [false], 79 | [false, false], 80 | [null, null, null, null] 81 | ]); 82 | self::assertEquals($matrix2->toArray(), [ 83 | [false], 84 | [false, false], 85 | [null, null, null, null] 86 | ]); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/MatrixPositionManagerTest.php: -------------------------------------------------------------------------------- 1 | positionToCoord(1), new Coord(0, 0)); 19 | self::assertEquals($MatrixPositionManager->positionToCoord(2), new Coord(1, 0)); 20 | self::assertEquals($MatrixPositionManager->positionToCoord(3), new Coord(1, 1)); 21 | self::assertEquals($MatrixPositionManager->positionToCoord(4), new Coord(2, 0)); 22 | self::assertEquals($MatrixPositionManager->positionToCoord(5), new Coord(2, 1)); 23 | 24 | self::assertEquals($MatrixPositionManager->positionToCoord(-100), null); 25 | self::assertEquals($MatrixPositionManager->positionToCoord(100), null); 26 | } 27 | 28 | /** @test */ 29 | public function testConvertCoordToPosition(): void 30 | { 31 | $matrix = new Matrix(3, 2); 32 | $MatrixPositionManager = new MatrixPositionManager($matrix); 33 | 34 | self::assertEquals($MatrixPositionManager->coordToPosition(new Coord(0, 0)), 1); 35 | self::assertEquals($MatrixPositionManager->coordToPosition(new Coord(1, 0)), 2); 36 | self::assertEquals($MatrixPositionManager->coordToPosition(new Coord(1, 1)), 3); 37 | self::assertEquals($MatrixPositionManager->coordToPosition(new Coord(2, 0)), 4); 38 | self::assertEquals($MatrixPositionManager->coordToPosition(new Coord(2, 1)), 5); 39 | 40 | self::assertEquals($MatrixPositionManager->coordToPosition(new Coord(-1, -1)), null); 41 | self::assertEquals($MatrixPositionManager->coordToPosition(new Coord(100, 100)), null); 42 | } 43 | 44 | /** @test */ 45 | public function testFindFirstFreeCoord(): void 46 | { 47 | $matrix = new Matrix(3, 2); 48 | $MatrixPositionManager = new MatrixPositionManager($matrix); 49 | 50 | self::assertEquals($MatrixPositionManager->findFirstFreeCoord(), new Coord(0, 0)); 51 | } 52 | 53 | /** @test */ 54 | public function testFindFirstFreeCoordInNotEmptyMatrix(): void 55 | { 56 | $matrix = new Matrix(3, 2); 57 | $matrix->addTenant(null, function (): array { 58 | return ['name' => 'John']; 59 | }); 60 | 61 | $MatrixPositionManager = new MatrixPositionManager($matrix); 62 | 63 | self::assertEquals($MatrixPositionManager->findFirstFreeCoord(), new Coord(1, 0)); 64 | } 65 | 66 | /** @test */ 67 | public function testFindFirstFreeCoordInFilledMatrix(): void 68 | { 69 | $matrix = new Matrix(3, 2); 70 | $matrix->addTenant(null, function (): array { 71 | return ['name' => 'John1']; 72 | }); 73 | $matrix->addTenant(null, function (): array { 74 | return ['name' => 'John2']; 75 | }); 76 | $matrix->addTenant(null, function (): array { 77 | return ['name' => 'John3']; 78 | }); 79 | $matrix->addTenant(null, function (): array { 80 | return ['name' => 'John4']; 81 | }); 82 | $matrix->addTenant(null, function (): array { 83 | return ['name' => 'John5']; 84 | }); 85 | $matrix->addTenant(null, function (): array { 86 | return ['name' => 'John6']; 87 | }); 88 | $matrix->addTenant(null, function (): array { 89 | return ['name' => 'John7']; 90 | }); 91 | 92 | $MatrixPositionManager = new MatrixPositionManager($matrix); 93 | 94 | self::assertEquals($MatrixPositionManager->findFirstFreeCoord(), null); 95 | } 96 | 97 | /** @test */ 98 | public function testFindFreeCoords(): void 99 | { 100 | $matrix = new Matrix(3, 2); 101 | $matrix->addTenant(new Coord(0, 0), function (): array { 102 | return ['name' => 'John1']; 103 | }); 104 | $matrix->addTenant(new Coord(1, 0), function (): array { 105 | return ['name' => 'John2']; 106 | }); 107 | $matrix->addTenant(new Coord(2, 2), function (): array { 108 | return ['name' => 'John3']; 109 | }); 110 | $matrix->addTenant(new Coord(2, 3), function (): array { 111 | return ['name' => 'John4']; 112 | }); 113 | 114 | $MatrixPositionManager = new MatrixPositionManager($matrix); 115 | 116 | self::assertEquals($MatrixPositionManager->findFreeCoords(), [ 117 | new Coord(1, 1), 118 | new Coord(2, 0), 119 | new Coord(2, 1), 120 | ]); 121 | } 122 | 123 | /** @test */ 124 | public function testFindFreePositions(): void 125 | { 126 | $matrix = new Matrix(3, 2); 127 | $matrix->addTenant(new Coord(0, 0), function (): array { 128 | return ['name' => 'John1']; 129 | }); 130 | $matrix->addTenant(new Coord(1, 0), function (): array { 131 | return ['name' => 'John2']; 132 | }); 133 | $matrix->addTenant(new Coord(2, 2), function (): array { 134 | return ['name' => 'John3']; 135 | }); 136 | 137 | $MatrixPositionManager = new MatrixPositionManager($matrix); 138 | 139 | self::assertEquals($MatrixPositionManager->findFreePositions(), [3, 4, 5, 7]); 140 | } 141 | 142 | /** @test */ 143 | public function testFindSectorCoordsForNextDepth(): void 144 | { 145 | $matrix = new Matrix(3, 2); 146 | 147 | $MatrixPositionManager = new MatrixPositionManager($matrix); 148 | 149 | self::assertEquals($MatrixPositionManager->findSectorCoordsForNextDepth(new Coord(1, 1)), [ 150 | new Coord(2, 2), 151 | new Coord(2, 3) 152 | ]); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /tests/MatrixRenderTest.php: -------------------------------------------------------------------------------- 1 | addTenant(null, function (): array { 18 | return ['name' => 'Superman']; 19 | }); 20 | 21 | $render = new MatrixRender($matrix); 22 | $render->setOptions(['class' => 'matrix']); 23 | $render->setDepthOptions(['class' => 'depth']); 24 | $render->setGroupSeparatorOptions(['class' => 'matrix-group-separator']); 25 | $render->setClearOptions(['style' => 'clear:both']); 26 | $render->setGroupJoinOptions(['class' => 'matrix-join-group']); 27 | $render->registerDepthCallback(function (Matrix $matrix, int $d, array $tenants): string { 28 | return '
Depth ' . (++$d) . '
'; 29 | }); 30 | $render->registerCellCallback(function (Matrix $matrix, Coord $coord, $tenant): string { 31 | if ($tenant === null) { 32 | return '
free
'; 33 | } 34 | 35 | return '
' . $tenant['name'] . '
'; 36 | }); 37 | 38 | $expected = trim(preg_replace('/\s+/', ' ', $render->show())); 39 | $actual = trim(preg_replace('/\s+/', ' ', '
Depth 1
Superman
40 |
41 |
Depth 2
free
42 |
free
43 |
')); 44 | 45 | self::assertEquals($expected, $actual); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/MatrixTest.php: -------------------------------------------------------------------------------- 1 | getDepth() ,3); 18 | } 19 | 20 | /** @test */ 21 | public function testItReturnsCurrentPow(): void 22 | { 23 | $matrix = new Matrix(3, 2); 24 | 25 | self::assertEquals($matrix->getPow() ,2); 26 | } 27 | 28 | /** @test */ 29 | public function testItReturnsCurrentMatrixArrayWithDepth3AndPow2(): void 30 | { 31 | $matrix = new Matrix(3, 2); 32 | 33 | self::assertEquals($matrix->toArray() ,[ 34 | [null], 35 | [null, null], 36 | [null, null, null, null] 37 | ]); 38 | } 39 | 40 | /** @test */ 41 | public function testItReturnsCurrentMatrixArrayWithDepth4AndPow2(): void 42 | { 43 | $matrix = new Matrix(4, 2); 44 | 45 | self::assertEquals($matrix->toArray() ,[ 46 | [null], 47 | [null, null], 48 | [null, null, null, null], 49 | [null, null, null, null, null, null, null, null] 50 | ]); 51 | } 52 | 53 | /** @test */ 54 | public function testItReturnsCurrentMatrixArrayWithDepth3AndPow3(): void 55 | { 56 | $matrix = new Matrix(3, 3); 57 | 58 | self::assertEquals($matrix->toArray() ,[ 59 | [null], 60 | [null, null, null], 61 | [null, null, null, null, null, null, null, null, null] 62 | ]); 63 | } 64 | 65 | /** @test */ 66 | public function testItReturnsCurrentMatrixArrayWithDepth4AndPow3(): void 67 | { 68 | $matrix = new Matrix(4, 3); 69 | 70 | self::assertEquals($matrix->toArray() ,[ 71 | [null], 72 | [null, null, null], 73 | [null, null, null, null, null, null, null, null, null], 74 | [ 75 | null, null, null, null, null, null, null, null, null, 76 | null, null, null, null, null, null, null, null, null, 77 | null, null, null, null, null, null, null, null, null, 78 | ] 79 | ]); 80 | } 81 | 82 | /** @test */ 83 | public function testCheckValidCoord(): void 84 | { 85 | $matrix = new Matrix(3, 2); 86 | 87 | self::assertTrue($matrix->isValidCoord(new Coord(0, 0))); 88 | } 89 | 90 | /** @test */ 91 | public function testCheckValidCoordWithRandDepth(): void 92 | { 93 | $matrix = new Matrix(3, 2); 94 | 95 | self::assertTrue($matrix->isValidCoord(new Coord(2, 0))); 96 | } 97 | 98 | /** @test */ 99 | public function testCheckValidCoordWithRandPow(): void 100 | { 101 | $matrix = new Matrix(3, 2); 102 | 103 | self::assertTrue($matrix->isValidCoord(new Coord(2, 3))); 104 | } 105 | 106 | /** @test */ 107 | public function testCheckInValidCoord(): void 108 | { 109 | $matrix = new Matrix(3, 2); 110 | 111 | self::assertFalse($matrix->isValidCoord(new Coord(0, 1))); 112 | } 113 | 114 | /** @test */ 115 | public function testCheckInValidCoordWithLongDepth(): void 116 | { 117 | $matrix = new Matrix(3, 2); 118 | 119 | self::assertFalse($matrix->isValidCoord(new Coord(10, 1))); 120 | } 121 | 122 | /** @test */ 123 | public function testCheckInValidCoordWithRandDepth(): void 124 | { 125 | $matrix = new Matrix(3, 2); 126 | 127 | self::assertFalse($matrix->isValidCoord(new Coord(5, 1))); 128 | } 129 | 130 | /** @test */ 131 | public function testCheckInValidCoordWithRandPow(): void 132 | { 133 | $matrix = new Matrix(3, 2); 134 | 135 | self::assertFalse($matrix->isValidCoord(new Coord(2, 7))); 136 | } 137 | 138 | /** @test */ 139 | public function testCheckThatMatrixIsNotFilled(): void 140 | { 141 | $matrix = new Matrix(2, 2); 142 | 143 | self::assertFalse($matrix->isFilled()); 144 | } 145 | 146 | /** @test */ 147 | public function testCheckThatMatrixIsFilled(): void 148 | { 149 | $this->expectException(FilledMatrixException::class); 150 | 151 | $matrix = new Matrix(2, 2); 152 | 153 | $matrix->addTenant(null, function (): string { return uniqid();}); 154 | $matrix->addTenant(null, function (): string { return uniqid();}); 155 | $matrix->addTenant(null, function (): string { return uniqid();}); 156 | $matrix->addTenant(null, function (): string { return uniqid();}); 157 | } 158 | 159 | /** @test */ 160 | public function testItsAddTenantToFirstFreePosition1(): void 161 | { 162 | $matrix = new Matrix(2, 2); 163 | 164 | $matrix->addTenant(null, function (): string { return uniqid();}); 165 | 166 | self::assertTrue($matrix->hasTenant(new Coord(0, 0))); 167 | } 168 | 169 | /** @test */ 170 | public function testItsAddTenantToFirstFreePosition2(): void 171 | { 172 | $matrix = new Matrix(2, 2); 173 | 174 | $matrix->addTenant(null, function (): string { return uniqid();}); 175 | $matrix->addTenant(null, function (): string { return uniqid();}); 176 | 177 | self::assertTrue($matrix->hasTenant(new Coord(0, 0))); 178 | self::assertTrue($matrix->hasTenant(new Coord(1, 0))); 179 | } 180 | 181 | /** @test */ 182 | public function testItsAddTenantToSelectPosition(): void 183 | { 184 | $matrix = new Matrix(3, 2); 185 | 186 | $matrix->addTenant(new Coord(2, 1), function (): string { return uniqid();}); 187 | 188 | self::assertTrue($matrix->hasTenant(new Coord(2, 1))); 189 | } 190 | 191 | /** @test */ 192 | public function testItsHasTenant(): void 193 | { 194 | $matrix = new Matrix(3, 2); 195 | 196 | $matrix->addTenant(new Coord(2, 1), function (): string { return uniqid();}); 197 | 198 | self::assertTrue($matrix->hasTenant(new Coord(2, 1))); 199 | self::assertFalse($matrix->hasTenant(new Coord(0, 0))); 200 | self::assertFalse($matrix->hasTenant(new Coord(1, 0))); 201 | self::assertFalse($matrix->hasTenant(new Coord(1, 1))); 202 | } 203 | 204 | /** @test */ 205 | public function testItsRemoveTenant(): void 206 | { 207 | $matrix = new Matrix(3, 2); 208 | 209 | $matrix->addTenant(new Coord(2, 1), function (): string { return uniqid();}); 210 | 211 | self::assertTrue($matrix->hasTenant(new Coord(2, 1))); 212 | 213 | $matrix->removeTenant(new Coord(2, 1)); 214 | 215 | self::assertFalse($matrix->hasTenant(new Coord(2, 1))); 216 | } 217 | 218 | } 219 | --------------------------------------------------------------------------------