├── .gitignore
├── .styleci.yml
├── .travis.yml
├── README.md
├── components
└── Context.php
├── composer.json
├── composer.lock
├── controllers
└── BuildController.php
├── helpers
└── DocBlockHelper.php
├── models
├── ControllerDoc.php
├── ControllerParser.php
├── Doc.php
├── FieldDoc.php
├── ModelDoc.php
├── ModelParser.php
├── ObjectParser.php
└── Parser.php
├── phpunit.xml.dist
├── tags
└── QueryTag.php
├── tests
├── bootstrap.php
├── config
│ └── main.php
├── controllers
│ ├── BrandController.php
│ ├── NewBrandController.php
│ └── ProductController.php
├── models
│ ├── Brand.php
│ ├── NewSpecialOffer.php
│ ├── Product.php
│ └── SpecialOffer.php
├── modules
│ └── api
│ │ ├── Module.php
│ │ ├── controllers
│ │ ├── CountryController.php
│ │ └── HelpController.php
│ │ └── models
│ │ └── Country.php
└── unit
│ ├── components
│ └── ContextTest.php
│ └── models
│ ├── ControllerParserTest.php
│ └── ModelParserTest.php
└── views
└── slate.php
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | vendor
3 |
--------------------------------------------------------------------------------
/.styleci.yml:
--------------------------------------------------------------------------------
1 | preset: psr2
2 | enabled:
3 | - concat_with_spaces
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 7.3
5 |
6 | matrix:
7 | fast_finish: true
8 |
9 | install:
10 | - travis_retry composer self-update
11 | - travis_retry composer install --prefer-dist --no-interaction
12 | - export PATH="$HOME/.composer/vendor/bin:$PATH"
13 | - travis_retry composer global require "phpunit/phpunit=4.8.6"
14 |
15 | script:
16 | - vendor/bin/phpunit
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Yii2 Rest Controller Documentator
2 |
3 | [](https://travis-ci.org/pahanini/yii2-rest-doc)
4 | [](https://styleci.io/repos/33711749)
5 | [](https://packagist.org/packages/pahanini/yii2-rest-doc)
6 | [](https://packagist.org/packages/pahanini/yii2-rest-doc)
7 | [](https://packagist.org/packages/pahanini/yii2-rest-doc)
8 | [](https://packagist.org/packages/pahanini/yii2-rest-doc)
9 |
10 |
11 | ## About
12 |
13 | Create precise documentation to your Yii2 API [REST](http://www.yiiframework.com/doc-2.0/guide-rest-quick-start.html)
14 | controllers. Library parses your code and generates objects with meta data that could be used with any template
15 | engine to generate great API docs.
16 |
17 | You do not need to edit documentation when you change you code. Just rebuild you docs with this tool.
18 |
19 | ## Install
20 |
21 | - Add `"pahanini/yii2-rest-doc": "*"` to required section of your composer.json
22 | - Add to your console application config
23 |
24 | ``` php
25 |
26 | 'controllerMap' => [
27 | 'build-rest-doc' => [
28 | 'sourceDirs' => [
29 | '@frontend\controllers\rest', // <-- path to your API controllers
30 | ],
31 | 'template' => '//restdoc/restdoc.twig',
32 | 'class' => '\pahanini\restdoc\controllers\BuildController',
33 | 'sortProperty' => 'shortDescription', // <-- default value (how controllers will be sorted)
34 | 'targetFile' => 'path/to/nice-documentation.html'
35 | ],
36 | ]
37 | ```
38 |
39 | ## Template example (twig)
40 |
41 | ``` html
42 | {% for controller in controllers %}
43 |
{{ controller.shortDescription }}
44 | {{ controller.longDescription }}
45 | {% if controller.hasLabel('authenticated') %}
46 | Require login and password!
47 | {% endif %}
48 | List of supported actions:
49 |
50 | {% for action in controller.actions %}
51 | - {{ action }}
52 | {% endfor %}
53 |
54 |
55 | Get params available for index action:
56 |
57 | {% for item in controller.query %}
58 | -
59 | {{ item.variableName }} - {{ item.description }}, default - {{ item.defaultValue }}
60 |
61 | {% endfor %}
62 |
63 |
64 | Model fields:
65 |
66 |
67 | Name |
68 | Type |
69 | Description |
70 | Can be updated? |
71 |
72 | {% for item in controller.model.fields %}
73 |
74 | {{ item.name }} |
75 | {{ item.type }} |
76 | {{ item.description }} |
77 | {{ item.isInScenario('api-update') ? 'yes' : 'no' }} |
78 |
79 | {% endfor %}
80 |
81 | {% endfor %}
82 | ```
83 |
84 | ## Data available in template
85 |
86 | List of data automatically extracted from code:
87 |
88 | - controller name
89 | - action's of each controller
90 | - model fields
91 | - extra fields
92 | - model rules (TBD)
93 |
94 | List of special tags:
95 |
96 | - short and long description of controller
97 | - query tags
98 |
99 | Inheritance is also supported. Use `@inherited` or `@inheritdoc` tags.
100 |
101 | ### Controller
102 |
103 | - `@restdoc-ignore` - skip controller.
104 | - `@restdoc-label name` - mark controller with label. Label name available via `controller.hasLabel('labelName')` in template
105 | - `@restdoc-query name=false Name of part of name to find users` - query params with description.
106 |
107 | ### Model
108 |
109 | To describe model's fields you can use two approaches.
110 |
111 | #### Link to property tag.
112 |
113 | If you already have phpDocumentator `@property` tag you can use it to describe API field.
114 | Model's doc block example:
115 |
116 | ```php
117 |
118 | /**
119 | * My model.
120 | *
121 | * @property string $title Model's title
122 | */
123 | ```
124 |
125 | * `@restdoc-link $title` - use `$title` property to describe `$title` api field
126 | * `@restdoc-link title $model_title` - use `$title` property to describe `$model_title` api field
127 |
128 | ### Separate field description
129 |
130 | If you do not have `@property` tag or API field is not directly connected with property use `@restdoc-field` tag.
131 |
132 | Example:
133 |
134 | ```php
135 |
136 | /**
137 | * @restdoc-field int $id ID
138 | * @restdoc-field string $title Model's title
139 | */
140 | ```
141 |
142 | ### Extra fields
143 |
144 | Use @restdoc-extraField and @restdoc-extraLink for extra fields.
145 |
146 | ### Sort fields
147 |
148 | Use @restdoc-sortField to sort field according to your code.
149 |
150 | ### Skip fields
151 |
152 | Use @restdoc-ignore to skip field.
153 |
154 | ```php
155 |
156 | /**
157 | * @restdoc-ignore $hidden
158 | */
159 | ```
160 |
161 | ## Integrate With Slate
162 |
163 | [Slate](https://github.com/tripit/slate) is probably one of the best tools to generate nice API. So you can
164 | use this tool to create index.md file for slate. You can use on afterAction event to automatically start slate.
165 |
166 | Example:
167 |
168 | ``` php
169 | 'controllerMap' => [
170 | 'build-rest-doc' => [
171 | 'sourceDirs' => [
172 | '@frontend\controllers\rest',
173 | ],
174 | 'template' => '//restdoc/restdoc.twig',
175 | 'class' => '\pahanini\restdoc\controllers\BuildController',
176 | 'targetFile' => 'path/to/slate/index.md',
177 | 'on afterAction' => function() { exec("bundle exec middleman build") }
178 | ],
179 | ]
180 | ```
181 |
182 | ## Rationale
183 |
184 | Creating of Yii2 controllers is an easy task, but supporting of documentation in actual state is often boring
185 | and tough challenge. Using automatic tool like [phpDocumentator](https://github.com/phpDocumentor/phpDocumentor2)
186 | or [swagger](http://swagger.io/) makes life easier but its still require to describe all models fields
187 | and rules using tags or comments.
188 |
189 | In other hand Yii2 controllers and models keep a lot of information about internal structure like actions,
190 | field names, scenarios for update and insert operations. This package extracts such an information from
191 | REST controllers and models and using this data along with phpdocumentator tags automatically generates
192 | index.md for [slate](https://github.com/tripit/slate) or any other documentation file.
193 |
194 |
--------------------------------------------------------------------------------
/components/Context.php:
--------------------------------------------------------------------------------
1 | ControllerParser::className(),
35 | 'reflection' => new \ReflectionClass($className),
36 | 'objectConfig' => $objectConfig,
37 | ]
38 | );
39 | $doc = new ControllerDoc();
40 | if ($parser->parse($doc) === false) {
41 | Yii::error($parser->error, 'restdoc');
42 | } else {
43 | $doc->prepare();
44 | $this->_controllers[$doc->path] = $doc;
45 | }
46 | }
47 |
48 |
49 | /**
50 | * Adds module to context.
51 | *
52 | * @param string $module Module class, e.g. \frontend\modules\my\Module
53 | */
54 | public function addModule($module)
55 | {
56 | /* @var $module Module */
57 | $module = Yii::createObject($module, ['_id', null]);
58 | $module->setInstance($module);
59 | $this->addDirs($module->getControllerPath());
60 |
61 | foreach ($module->controllerMap as $value) {
62 | if (is_array($value)) {
63 | $class = $value['class'];
64 | unset($value['class']);
65 | $objectConfig = $value;
66 | } else {
67 | $class = $value;
68 | $objectConfig = null;
69 | }
70 | $this->addControllerDoc($class, $objectConfig);
71 | }
72 | }
73 |
74 | /**
75 | * Adds array of modules to context.
76 | *
77 | * @param string[] $modules Array with names of modules.
78 | */
79 | public function addModules($modules)
80 | {
81 | $modules = is_array($modules) ? $modules : [$modules];
82 | foreach ($modules as $module) {
83 | $this->addModule($module);
84 | }
85 | }
86 |
87 | /**
88 | * Adds one or more directories with controllers to context.
89 | *
90 | * @param string[] $dirs
91 | */
92 | public function addDirs($dirs)
93 | {
94 | $dirs = is_array($dirs) ? $dirs : [$dirs];
95 | foreach ($dirs as $dir) {
96 | $files = FileHelper::findFiles(Yii::getAlias($dir), [
97 | 'only' => ['*Controller.php']
98 | ]);
99 | foreach ($files as $file) {
100 | $this->addFile($file);
101 | }
102 | }
103 | }
104 |
105 | /**
106 | * Adds file to context.
107 | *
108 | * @param string $fileName
109 | */
110 | public function addFile($fileName)
111 | {
112 | $reflector = new FileReflector($fileName);
113 | $reflector->process();
114 |
115 | $classes = $reflector->getClasses();
116 |
117 | if (count($classes) !== 1) {
118 | throw new InvalidArgumentException("File $fileName includes more then one class");
119 | }
120 |
121 | $this->addControllerDoc($classes[0]->getName());
122 | }
123 |
124 | /**
125 | * @param $property
126 | */
127 | public function sortControllers($property)
128 | {
129 | uasort($this->_controllers, function ($a, $b) use ($property) {
130 | return strcmp($a->$property, $b->$property);
131 | });
132 | }
133 |
134 | /**
135 | * Returns list of controller documents.
136 | * @return \pahanini\restdoc\models\ControllerDoc[]
137 | */
138 | public function getControllers()
139 | {
140 | return $this->_controllers;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pahanini/yii2-rest-doc",
3 | "description": "A Yii2 tool to create slate index.md for you REST controllers.",
4 | "keywords": ["yii2", "rest", "api", "doc", "slate"],
5 | "homepage": "https://github.com/pahanini/yii2-rest-to-slate",
6 | "type": "yii2-extension",
7 | "license": "BSD-3-Clause",
8 | "authors": [
9 | {
10 | "name": "Pavel Tetyaev",
11 | "email": "pahanini@gmail.com"
12 | }
13 | ],
14 | "require": {
15 | "php": ">=7.1.0",
16 | "ext-curl": "*",
17 | "yiisoft/yii2": "*",
18 | "phpdocumentor/reflection": ">=3.0.0",
19 | "phpdocumentor/reflection-docblock": "~2.0"
20 | },
21 | "require-dev": {
22 | "phpunit/phpunit" : ">=6.0"
23 | },
24 | "autoload": {
25 | "psr-4": {
26 | "pahanini\\restdoc\\": ""
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/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": "58c263763c94f387dc8e26cc840640f8",
8 | "packages": [
9 | {
10 | "name": "bower-asset/inputmask",
11 | "version": "3.3.11",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/RobinHerbots/Inputmask.git",
15 | "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/RobinHerbots/Inputmask/zipball/5e670ad62f50c738388d4dcec78d2888505ad77b",
20 | "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "bower-asset/jquery": ">=1.7"
25 | },
26 | "type": "bower-asset-library",
27 | "extra": {
28 | "bower-asset-main": [
29 | "./dist/inputmask/inputmask.js",
30 | "./dist/inputmask/inputmask.extensions.js",
31 | "./dist/inputmask/inputmask.date.extensions.js",
32 | "./dist/inputmask/inputmask.numeric.extensions.js",
33 | "./dist/inputmask/inputmask.phone.extensions.js",
34 | "./dist/inputmask/jquery.inputmask.js",
35 | "./dist/inputmask/global/document.js",
36 | "./dist/inputmask/global/window.js",
37 | "./dist/inputmask/phone-codes/phone.js",
38 | "./dist/inputmask/phone-codes/phone-be.js",
39 | "./dist/inputmask/phone-codes/phone-nl.js",
40 | "./dist/inputmask/phone-codes/phone-ru.js",
41 | "./dist/inputmask/phone-codes/phone-uk.js",
42 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.jqlite.js",
43 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.jquery.js",
44 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.js",
45 | "./dist/inputmask/bindings/inputmask.binding.js"
46 | ],
47 | "bower-asset-ignore": [
48 | "**/*",
49 | "!dist/*",
50 | "!dist/inputmask/*",
51 | "!dist/min/*",
52 | "!dist/min/inputmask/*"
53 | ]
54 | },
55 | "license": [
56 | "http://opensource.org/licenses/mit-license.php"
57 | ],
58 | "description": "Inputmask is a javascript library which creates an input mask. Inputmask can run against vanilla javascript, jQuery and jqlite.",
59 | "keywords": [
60 | "form",
61 | "input",
62 | "inputmask",
63 | "jquery",
64 | "mask",
65 | "plugins"
66 | ],
67 | "time": "2017-11-21T11:46:23+00:00"
68 | },
69 | {
70 | "name": "bower-asset/jquery",
71 | "version": "3.4.1",
72 | "source": {
73 | "type": "git",
74 | "url": "https://github.com/jquery/jquery-dist.git",
75 | "reference": "15bc73803f76bc53b654b9fdbbbc096f56d7c03d"
76 | },
77 | "dist": {
78 | "type": "zip",
79 | "url": "https://api.github.com/repos/jquery/jquery-dist/zipball/15bc73803f76bc53b654b9fdbbbc096f56d7c03d",
80 | "reference": "15bc73803f76bc53b654b9fdbbbc096f56d7c03d",
81 | "shasum": ""
82 | },
83 | "type": "bower-asset-library",
84 | "extra": {
85 | "bower-asset-main": "dist/jquery.js",
86 | "bower-asset-ignore": [
87 | "package.json"
88 | ]
89 | },
90 | "license": [
91 | "MIT"
92 | ],
93 | "keywords": [
94 | "browser",
95 | "javascript",
96 | "jquery",
97 | "library"
98 | ],
99 | "time": "2019-05-01T21:19:28+00:00"
100 | },
101 | {
102 | "name": "bower-asset/punycode",
103 | "version": "v1.3.2",
104 | "source": {
105 | "type": "git",
106 | "url": "https://github.com/bestiejs/punycode.js.git",
107 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3"
108 | },
109 | "dist": {
110 | "type": "zip",
111 | "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3",
112 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3",
113 | "shasum": ""
114 | },
115 | "type": "bower-asset-library",
116 | "extra": {
117 | "bower-asset-main": "punycode.js",
118 | "bower-asset-ignore": [
119 | "coverage",
120 | "tests",
121 | ".*",
122 | "component.json",
123 | "Gruntfile.js",
124 | "node_modules",
125 | "package.json"
126 | ]
127 | },
128 | "time": "2014-10-22T12:02:42+00:00"
129 | },
130 | {
131 | "name": "bower-asset/yii2-pjax",
132 | "version": "2.0.7.1",
133 | "source": {
134 | "type": "git",
135 | "url": "https://github.com/yiisoft/jquery-pjax.git",
136 | "reference": "aef7b953107264f00234902a3880eb50dafc48be"
137 | },
138 | "dist": {
139 | "type": "zip",
140 | "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/aef7b953107264f00234902a3880eb50dafc48be",
141 | "reference": "aef7b953107264f00234902a3880eb50dafc48be",
142 | "shasum": ""
143 | },
144 | "require": {
145 | "bower-asset/jquery": ">=1.8"
146 | },
147 | "type": "bower-asset-library",
148 | "extra": {
149 | "bower-asset-main": "./jquery.pjax.js",
150 | "bower-asset-ignore": [
151 | ".travis.yml",
152 | "Gemfile",
153 | "Gemfile.lock",
154 | "CONTRIBUTING.md",
155 | "vendor/",
156 | "script/",
157 | "test/"
158 | ]
159 | },
160 | "license": [
161 | "MIT"
162 | ],
163 | "time": "2017-10-12T10:11:14+00:00"
164 | },
165 | {
166 | "name": "cebe/markdown",
167 | "version": "1.2.1",
168 | "source": {
169 | "type": "git",
170 | "url": "https://github.com/cebe/markdown.git",
171 | "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86"
172 | },
173 | "dist": {
174 | "type": "zip",
175 | "url": "https://api.github.com/repos/cebe/markdown/zipball/9bac5e971dd391e2802dca5400bbeacbaea9eb86",
176 | "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86",
177 | "shasum": ""
178 | },
179 | "require": {
180 | "lib-pcre": "*",
181 | "php": ">=5.4.0"
182 | },
183 | "require-dev": {
184 | "cebe/indent": "*",
185 | "facebook/xhprof": "*@dev",
186 | "phpunit/phpunit": "4.1.*"
187 | },
188 | "bin": [
189 | "bin/markdown"
190 | ],
191 | "type": "library",
192 | "extra": {
193 | "branch-alias": {
194 | "dev-master": "1.2.x-dev"
195 | }
196 | },
197 | "autoload": {
198 | "psr-4": {
199 | "cebe\\markdown\\": ""
200 | }
201 | },
202 | "notification-url": "https://packagist.org/downloads/",
203 | "license": [
204 | "MIT"
205 | ],
206 | "authors": [
207 | {
208 | "name": "Carsten Brandt",
209 | "email": "mail@cebe.cc",
210 | "homepage": "http://cebe.cc/",
211 | "role": "Creator"
212 | }
213 | ],
214 | "description": "A super fast, highly extensible markdown parser for PHP",
215 | "homepage": "https://github.com/cebe/markdown#readme",
216 | "keywords": [
217 | "extensible",
218 | "fast",
219 | "gfm",
220 | "markdown",
221 | "markdown-extra"
222 | ],
223 | "time": "2018-03-26T11:24:36+00:00"
224 | },
225 | {
226 | "name": "ezyang/htmlpurifier",
227 | "version": "v4.12.0",
228 | "source": {
229 | "type": "git",
230 | "url": "https://github.com/ezyang/htmlpurifier.git",
231 | "reference": "a617e55bc62a87eec73bd456d146d134ad716f03"
232 | },
233 | "dist": {
234 | "type": "zip",
235 | "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/a617e55bc62a87eec73bd456d146d134ad716f03",
236 | "reference": "a617e55bc62a87eec73bd456d146d134ad716f03",
237 | "shasum": ""
238 | },
239 | "require": {
240 | "php": ">=5.2"
241 | },
242 | "require-dev": {
243 | "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd"
244 | },
245 | "type": "library",
246 | "autoload": {
247 | "psr-0": {
248 | "HTMLPurifier": "library/"
249 | },
250 | "files": [
251 | "library/HTMLPurifier.composer.php"
252 | ]
253 | },
254 | "notification-url": "https://packagist.org/downloads/",
255 | "license": [
256 | "LGPL-2.1-or-later"
257 | ],
258 | "authors": [
259 | {
260 | "name": "Edward Z. Yang",
261 | "email": "admin@htmlpurifier.org",
262 | "homepage": "http://ezyang.com"
263 | }
264 | ],
265 | "description": "Standards compliant HTML filter written in PHP",
266 | "homepage": "http://htmlpurifier.org/",
267 | "keywords": [
268 | "html"
269 | ],
270 | "time": "2019-10-28T03:44:26+00:00"
271 | },
272 | {
273 | "name": "nikic/php-parser",
274 | "version": "v1.4.1",
275 | "source": {
276 | "type": "git",
277 | "url": "https://github.com/nikic/PHP-Parser.git",
278 | "reference": "f78af2c9c86107aa1a34cd1dbb5bbe9eeb0d9f51"
279 | },
280 | "dist": {
281 | "type": "zip",
282 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f78af2c9c86107aa1a34cd1dbb5bbe9eeb0d9f51",
283 | "reference": "f78af2c9c86107aa1a34cd1dbb5bbe9eeb0d9f51",
284 | "shasum": ""
285 | },
286 | "require": {
287 | "ext-tokenizer": "*",
288 | "php": ">=5.3"
289 | },
290 | "type": "library",
291 | "extra": {
292 | "branch-alias": {
293 | "dev-master": "1.4-dev"
294 | }
295 | },
296 | "autoload": {
297 | "files": [
298 | "lib/bootstrap.php"
299 | ]
300 | },
301 | "notification-url": "https://packagist.org/downloads/",
302 | "license": [
303 | "BSD-3-Clause"
304 | ],
305 | "authors": [
306 | {
307 | "name": "Nikita Popov"
308 | }
309 | ],
310 | "description": "A PHP parser written in PHP",
311 | "keywords": [
312 | "parser",
313 | "php"
314 | ],
315 | "time": "2015-09-19T14:15:08+00:00"
316 | },
317 | {
318 | "name": "phpdocumentor/reflection",
319 | "version": "3.0.1",
320 | "source": {
321 | "type": "git",
322 | "url": "https://github.com/phpDocumentor/Reflection.git",
323 | "reference": "793bfd92d9a0fc96ae9608fb3e947c3f59fb3a0d"
324 | },
325 | "dist": {
326 | "type": "zip",
327 | "url": "https://api.github.com/repos/phpDocumentor/Reflection/zipball/793bfd92d9a0fc96ae9608fb3e947c3f59fb3a0d",
328 | "reference": "793bfd92d9a0fc96ae9608fb3e947c3f59fb3a0d",
329 | "shasum": ""
330 | },
331 | "require": {
332 | "nikic/php-parser": "^1.0",
333 | "php": ">=5.3.3",
334 | "phpdocumentor/reflection-docblock": "~2.0",
335 | "psr/log": "~1.0"
336 | },
337 | "require-dev": {
338 | "behat/behat": "~2.4",
339 | "mockery/mockery": "~0.8",
340 | "phpunit/phpunit": "~4.0"
341 | },
342 | "type": "library",
343 | "extra": {
344 | "branch-alias": {
345 | "dev-master": "1.0.x-dev"
346 | }
347 | },
348 | "autoload": {
349 | "psr-0": {
350 | "phpDocumentor": [
351 | "src/",
352 | "tests/unit/",
353 | "tests/mocks/"
354 | ]
355 | }
356 | },
357 | "notification-url": "https://packagist.org/downloads/",
358 | "license": [
359 | "MIT"
360 | ],
361 | "description": "Reflection library to do Static Analysis for PHP Projects",
362 | "homepage": "http://www.phpdoc.org",
363 | "keywords": [
364 | "phpDocumentor",
365 | "phpdoc",
366 | "reflection",
367 | "static analysis"
368 | ],
369 | "time": "2016-05-21T08:42:32+00:00"
370 | },
371 | {
372 | "name": "phpdocumentor/reflection-docblock",
373 | "version": "2.0.5",
374 | "source": {
375 | "type": "git",
376 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
377 | "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b"
378 | },
379 | "dist": {
380 | "type": "zip",
381 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e6a969a640b00d8daa3c66518b0405fb41ae0c4b",
382 | "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b",
383 | "shasum": ""
384 | },
385 | "require": {
386 | "php": ">=5.3.3"
387 | },
388 | "require-dev": {
389 | "phpunit/phpunit": "~4.0"
390 | },
391 | "suggest": {
392 | "dflydev/markdown": "~1.0",
393 | "erusev/parsedown": "~1.0"
394 | },
395 | "type": "library",
396 | "extra": {
397 | "branch-alias": {
398 | "dev-master": "2.0.x-dev"
399 | }
400 | },
401 | "autoload": {
402 | "psr-0": {
403 | "phpDocumentor": [
404 | "src/"
405 | ]
406 | }
407 | },
408 | "notification-url": "https://packagist.org/downloads/",
409 | "license": [
410 | "MIT"
411 | ],
412 | "authors": [
413 | {
414 | "name": "Mike van Riel",
415 | "email": "mike.vanriel@naenius.com"
416 | }
417 | ],
418 | "time": "2016-01-25T08:17:30+00:00"
419 | },
420 | {
421 | "name": "psr/log",
422 | "version": "1.1.3",
423 | "source": {
424 | "type": "git",
425 | "url": "https://github.com/php-fig/log.git",
426 | "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
427 | },
428 | "dist": {
429 | "type": "zip",
430 | "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
431 | "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
432 | "shasum": ""
433 | },
434 | "require": {
435 | "php": ">=5.3.0"
436 | },
437 | "type": "library",
438 | "extra": {
439 | "branch-alias": {
440 | "dev-master": "1.1.x-dev"
441 | }
442 | },
443 | "autoload": {
444 | "psr-4": {
445 | "Psr\\Log\\": "Psr/Log/"
446 | }
447 | },
448 | "notification-url": "https://packagist.org/downloads/",
449 | "license": [
450 | "MIT"
451 | ],
452 | "authors": [
453 | {
454 | "name": "PHP-FIG",
455 | "homepage": "http://www.php-fig.org/"
456 | }
457 | ],
458 | "description": "Common interface for logging libraries",
459 | "homepage": "https://github.com/php-fig/log",
460 | "keywords": [
461 | "log",
462 | "psr",
463 | "psr-3"
464 | ],
465 | "time": "2020-03-23T09:12:05+00:00"
466 | },
467 | {
468 | "name": "yiisoft/yii2",
469 | "version": "2.0.35",
470 | "source": {
471 | "type": "git",
472 | "url": "https://github.com/yiisoft/yii2-framework.git",
473 | "reference": "d42809e4969cdc0adb97197ba32774b3e4cd9e8e"
474 | },
475 | "dist": {
476 | "type": "zip",
477 | "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/d42809e4969cdc0adb97197ba32774b3e4cd9e8e",
478 | "reference": "d42809e4969cdc0adb97197ba32774b3e4cd9e8e",
479 | "shasum": ""
480 | },
481 | "require": {
482 | "bower-asset/inputmask": "~3.2.2 | ~3.3.5",
483 | "bower-asset/jquery": "3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
484 | "bower-asset/punycode": "1.3.*",
485 | "bower-asset/yii2-pjax": "~2.0.1",
486 | "cebe/markdown": "~1.0.0 | ~1.1.0 | ~1.2.0",
487 | "ext-ctype": "*",
488 | "ext-mbstring": "*",
489 | "ezyang/htmlpurifier": "~4.6",
490 | "lib-pcre": "*",
491 | "php": ">=5.4.0",
492 | "yiisoft/yii2-composer": "~2.0.4"
493 | },
494 | "bin": [
495 | "yii"
496 | ],
497 | "type": "library",
498 | "extra": {
499 | "branch-alias": {
500 | "dev-master": "2.0.x-dev"
501 | }
502 | },
503 | "autoload": {
504 | "psr-4": {
505 | "yii\\": ""
506 | }
507 | },
508 | "notification-url": "https://packagist.org/downloads/",
509 | "license": [
510 | "BSD-3-Clause"
511 | ],
512 | "authors": [
513 | {
514 | "name": "Qiang Xue",
515 | "email": "qiang.xue@gmail.com",
516 | "homepage": "http://www.yiiframework.com/",
517 | "role": "Founder and project lead"
518 | },
519 | {
520 | "name": "Alexander Makarov",
521 | "email": "sam@rmcreative.ru",
522 | "homepage": "http://rmcreative.ru/",
523 | "role": "Core framework development"
524 | },
525 | {
526 | "name": "Maurizio Domba",
527 | "homepage": "http://mdomba.info/",
528 | "role": "Core framework development"
529 | },
530 | {
531 | "name": "Carsten Brandt",
532 | "email": "mail@cebe.cc",
533 | "homepage": "http://cebe.cc/",
534 | "role": "Core framework development"
535 | },
536 | {
537 | "name": "Timur Ruziev",
538 | "email": "resurtm@gmail.com",
539 | "homepage": "http://resurtm.com/",
540 | "role": "Core framework development"
541 | },
542 | {
543 | "name": "Paul Klimov",
544 | "email": "klimov.paul@gmail.com",
545 | "role": "Core framework development"
546 | },
547 | {
548 | "name": "Dmitry Naumenko",
549 | "email": "d.naumenko.a@gmail.com",
550 | "role": "Core framework development"
551 | },
552 | {
553 | "name": "Boudewijn Vahrmeijer",
554 | "email": "info@dynasource.eu",
555 | "homepage": "http://dynasource.eu",
556 | "role": "Core framework development"
557 | }
558 | ],
559 | "description": "Yii PHP Framework Version 2",
560 | "homepage": "http://www.yiiframework.com/",
561 | "keywords": [
562 | "framework",
563 | "yii2"
564 | ],
565 | "funding": [
566 | {
567 | "url": "https://github.com/yiisoft",
568 | "type": "github"
569 | },
570 | {
571 | "url": "https://opencollective.com/yiisoft",
572 | "type": "open_collective"
573 | },
574 | {
575 | "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2",
576 | "type": "tidelift"
577 | }
578 | ],
579 | "time": "2020-05-02T11:11:31+00:00"
580 | },
581 | {
582 | "name": "yiisoft/yii2-composer",
583 | "version": "2.0.9",
584 | "source": {
585 | "type": "git",
586 | "url": "https://github.com/yiisoft/yii2-composer.git",
587 | "reference": "d191176c4f8372e397a9e3df27360dca6a70efaa"
588 | },
589 | "dist": {
590 | "type": "zip",
591 | "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/d191176c4f8372e397a9e3df27360dca6a70efaa",
592 | "reference": "d191176c4f8372e397a9e3df27360dca6a70efaa",
593 | "shasum": ""
594 | },
595 | "require": {
596 | "composer-plugin-api": "^1.0 | ^2.0"
597 | },
598 | "require-dev": {
599 | "composer/composer": "^1.0 | ^2.0@dev",
600 | "phpunit/phpunit": "<7"
601 | },
602 | "type": "composer-plugin",
603 | "extra": {
604 | "class": "yii\\composer\\Plugin",
605 | "branch-alias": {
606 | "dev-master": "2.0.x-dev"
607 | }
608 | },
609 | "autoload": {
610 | "psr-4": {
611 | "yii\\composer\\": ""
612 | }
613 | },
614 | "notification-url": "https://packagist.org/downloads/",
615 | "license": [
616 | "BSD-3-Clause"
617 | ],
618 | "authors": [
619 | {
620 | "name": "Qiang Xue",
621 | "email": "qiang.xue@gmail.com"
622 | },
623 | {
624 | "name": "Carsten Brandt",
625 | "email": "mail@cebe.cc"
626 | }
627 | ],
628 | "description": "The composer plugin for Yii extension installer",
629 | "keywords": [
630 | "composer",
631 | "extension installer",
632 | "yii2"
633 | ],
634 | "funding": [
635 | {
636 | "url": "https://github.com/yiisoft",
637 | "type": "github"
638 | },
639 | {
640 | "url": "https://opencollective.com/yiisoft",
641 | "type": "open_collective"
642 | },
643 | {
644 | "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2-composer",
645 | "type": "tidelift"
646 | }
647 | ],
648 | "time": "2020-04-20T18:47:46+00:00"
649 | }
650 | ],
651 | "packages-dev": [
652 | {
653 | "name": "doctrine/instantiator",
654 | "version": "1.3.0",
655 | "source": {
656 | "type": "git",
657 | "url": "https://github.com/doctrine/instantiator.git",
658 | "reference": "ae466f726242e637cebdd526a7d991b9433bacf1"
659 | },
660 | "dist": {
661 | "type": "zip",
662 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1",
663 | "reference": "ae466f726242e637cebdd526a7d991b9433bacf1",
664 | "shasum": ""
665 | },
666 | "require": {
667 | "php": "^7.1"
668 | },
669 | "require-dev": {
670 | "doctrine/coding-standard": "^6.0",
671 | "ext-pdo": "*",
672 | "ext-phar": "*",
673 | "phpbench/phpbench": "^0.13",
674 | "phpstan/phpstan-phpunit": "^0.11",
675 | "phpstan/phpstan-shim": "^0.11",
676 | "phpunit/phpunit": "^7.0"
677 | },
678 | "type": "library",
679 | "extra": {
680 | "branch-alias": {
681 | "dev-master": "1.2.x-dev"
682 | }
683 | },
684 | "autoload": {
685 | "psr-4": {
686 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
687 | }
688 | },
689 | "notification-url": "https://packagist.org/downloads/",
690 | "license": [
691 | "MIT"
692 | ],
693 | "authors": [
694 | {
695 | "name": "Marco Pivetta",
696 | "email": "ocramius@gmail.com",
697 | "homepage": "http://ocramius.github.com/"
698 | }
699 | ],
700 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
701 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
702 | "keywords": [
703 | "constructor",
704 | "instantiate"
705 | ],
706 | "time": "2019-10-21T16:45:58+00:00"
707 | },
708 | {
709 | "name": "myclabs/deep-copy",
710 | "version": "1.9.5",
711 | "source": {
712 | "type": "git",
713 | "url": "https://github.com/myclabs/DeepCopy.git",
714 | "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef"
715 | },
716 | "dist": {
717 | "type": "zip",
718 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef",
719 | "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef",
720 | "shasum": ""
721 | },
722 | "require": {
723 | "php": "^7.1"
724 | },
725 | "replace": {
726 | "myclabs/deep-copy": "self.version"
727 | },
728 | "require-dev": {
729 | "doctrine/collections": "^1.0",
730 | "doctrine/common": "^2.6",
731 | "phpunit/phpunit": "^7.1"
732 | },
733 | "type": "library",
734 | "autoload": {
735 | "psr-4": {
736 | "DeepCopy\\": "src/DeepCopy/"
737 | },
738 | "files": [
739 | "src/DeepCopy/deep_copy.php"
740 | ]
741 | },
742 | "notification-url": "https://packagist.org/downloads/",
743 | "license": [
744 | "MIT"
745 | ],
746 | "description": "Create deep copies (clones) of your objects",
747 | "keywords": [
748 | "clone",
749 | "copy",
750 | "duplicate",
751 | "object",
752 | "object graph"
753 | ],
754 | "time": "2020-01-17T21:11:47+00:00"
755 | },
756 | {
757 | "name": "phar-io/manifest",
758 | "version": "1.0.3",
759 | "source": {
760 | "type": "git",
761 | "url": "https://github.com/phar-io/manifest.git",
762 | "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4"
763 | },
764 | "dist": {
765 | "type": "zip",
766 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
767 | "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
768 | "shasum": ""
769 | },
770 | "require": {
771 | "ext-dom": "*",
772 | "ext-phar": "*",
773 | "phar-io/version": "^2.0",
774 | "php": "^5.6 || ^7.0"
775 | },
776 | "type": "library",
777 | "extra": {
778 | "branch-alias": {
779 | "dev-master": "1.0.x-dev"
780 | }
781 | },
782 | "autoload": {
783 | "classmap": [
784 | "src/"
785 | ]
786 | },
787 | "notification-url": "https://packagist.org/downloads/",
788 | "license": [
789 | "BSD-3-Clause"
790 | ],
791 | "authors": [
792 | {
793 | "name": "Arne Blankerts",
794 | "email": "arne@blankerts.de",
795 | "role": "Developer"
796 | },
797 | {
798 | "name": "Sebastian Heuer",
799 | "email": "sebastian@phpeople.de",
800 | "role": "Developer"
801 | },
802 | {
803 | "name": "Sebastian Bergmann",
804 | "email": "sebastian@phpunit.de",
805 | "role": "Developer"
806 | }
807 | ],
808 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
809 | "time": "2018-07-08T19:23:20+00:00"
810 | },
811 | {
812 | "name": "phar-io/version",
813 | "version": "2.0.1",
814 | "source": {
815 | "type": "git",
816 | "url": "https://github.com/phar-io/version.git",
817 | "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6"
818 | },
819 | "dist": {
820 | "type": "zip",
821 | "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6",
822 | "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6",
823 | "shasum": ""
824 | },
825 | "require": {
826 | "php": "^5.6 || ^7.0"
827 | },
828 | "type": "library",
829 | "autoload": {
830 | "classmap": [
831 | "src/"
832 | ]
833 | },
834 | "notification-url": "https://packagist.org/downloads/",
835 | "license": [
836 | "BSD-3-Clause"
837 | ],
838 | "authors": [
839 | {
840 | "name": "Arne Blankerts",
841 | "email": "arne@blankerts.de",
842 | "role": "Developer"
843 | },
844 | {
845 | "name": "Sebastian Heuer",
846 | "email": "sebastian@phpeople.de",
847 | "role": "Developer"
848 | },
849 | {
850 | "name": "Sebastian Bergmann",
851 | "email": "sebastian@phpunit.de",
852 | "role": "Developer"
853 | }
854 | ],
855 | "description": "Library for handling version information and constraints",
856 | "time": "2018-07-08T19:19:57+00:00"
857 | },
858 | {
859 | "name": "phpspec/prophecy",
860 | "version": "v1.10.3",
861 | "source": {
862 | "type": "git",
863 | "url": "https://github.com/phpspec/prophecy.git",
864 | "reference": "451c3cd1418cf640de218914901e51b064abb093"
865 | },
866 | "dist": {
867 | "type": "zip",
868 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093",
869 | "reference": "451c3cd1418cf640de218914901e51b064abb093",
870 | "shasum": ""
871 | },
872 | "require": {
873 | "doctrine/instantiator": "^1.0.2",
874 | "php": "^5.3|^7.0",
875 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
876 | "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0",
877 | "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0"
878 | },
879 | "require-dev": {
880 | "phpspec/phpspec": "^2.5 || ^3.2",
881 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
882 | },
883 | "type": "library",
884 | "extra": {
885 | "branch-alias": {
886 | "dev-master": "1.10.x-dev"
887 | }
888 | },
889 | "autoload": {
890 | "psr-4": {
891 | "Prophecy\\": "src/Prophecy"
892 | }
893 | },
894 | "notification-url": "https://packagist.org/downloads/",
895 | "license": [
896 | "MIT"
897 | ],
898 | "authors": [
899 | {
900 | "name": "Konstantin Kudryashov",
901 | "email": "ever.zet@gmail.com",
902 | "homepage": "http://everzet.com"
903 | },
904 | {
905 | "name": "Marcello Duarte",
906 | "email": "marcello.duarte@gmail.com"
907 | }
908 | ],
909 | "description": "Highly opinionated mocking framework for PHP 5.3+",
910 | "homepage": "https://github.com/phpspec/prophecy",
911 | "keywords": [
912 | "Double",
913 | "Dummy",
914 | "fake",
915 | "mock",
916 | "spy",
917 | "stub"
918 | ],
919 | "time": "2020-03-05T15:02:03+00:00"
920 | },
921 | {
922 | "name": "phpunit/php-code-coverage",
923 | "version": "8.0.2",
924 | "source": {
925 | "type": "git",
926 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
927 | "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc"
928 | },
929 | "dist": {
930 | "type": "zip",
931 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca6647ffddd2add025ab3f21644a441d7c146cdc",
932 | "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc",
933 | "shasum": ""
934 | },
935 | "require": {
936 | "ext-dom": "*",
937 | "ext-xmlwriter": "*",
938 | "php": "^7.3",
939 | "phpunit/php-file-iterator": "^3.0",
940 | "phpunit/php-text-template": "^2.0",
941 | "phpunit/php-token-stream": "^4.0",
942 | "sebastian/code-unit-reverse-lookup": "^2.0",
943 | "sebastian/environment": "^5.0",
944 | "sebastian/version": "^3.0",
945 | "theseer/tokenizer": "^1.1.3"
946 | },
947 | "require-dev": {
948 | "phpunit/phpunit": "^9.0"
949 | },
950 | "suggest": {
951 | "ext-pcov": "*",
952 | "ext-xdebug": "*"
953 | },
954 | "type": "library",
955 | "extra": {
956 | "branch-alias": {
957 | "dev-master": "8.0-dev"
958 | }
959 | },
960 | "autoload": {
961 | "classmap": [
962 | "src/"
963 | ]
964 | },
965 | "notification-url": "https://packagist.org/downloads/",
966 | "license": [
967 | "BSD-3-Clause"
968 | ],
969 | "authors": [
970 | {
971 | "name": "Sebastian Bergmann",
972 | "email": "sebastian@phpunit.de",
973 | "role": "lead"
974 | }
975 | ],
976 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
977 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
978 | "keywords": [
979 | "coverage",
980 | "testing",
981 | "xunit"
982 | ],
983 | "funding": [
984 | {
985 | "url": "https://github.com/sebastianbergmann",
986 | "type": "github"
987 | }
988 | ],
989 | "time": "2020-05-23T08:02:54+00:00"
990 | },
991 | {
992 | "name": "phpunit/php-file-iterator",
993 | "version": "3.0.1",
994 | "source": {
995 | "type": "git",
996 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
997 | "reference": "4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4"
998 | },
999 | "dist": {
1000 | "type": "zip",
1001 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4",
1002 | "reference": "4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4",
1003 | "shasum": ""
1004 | },
1005 | "require": {
1006 | "php": "^7.3"
1007 | },
1008 | "require-dev": {
1009 | "phpunit/phpunit": "^9.0"
1010 | },
1011 | "type": "library",
1012 | "extra": {
1013 | "branch-alias": {
1014 | "dev-master": "3.0-dev"
1015 | }
1016 | },
1017 | "autoload": {
1018 | "classmap": [
1019 | "src/"
1020 | ]
1021 | },
1022 | "notification-url": "https://packagist.org/downloads/",
1023 | "license": [
1024 | "BSD-3-Clause"
1025 | ],
1026 | "authors": [
1027 | {
1028 | "name": "Sebastian Bergmann",
1029 | "email": "sebastian@phpunit.de",
1030 | "role": "lead"
1031 | }
1032 | ],
1033 | "description": "FilterIterator implementation that filters files based on a list of suffixes.",
1034 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
1035 | "keywords": [
1036 | "filesystem",
1037 | "iterator"
1038 | ],
1039 | "funding": [
1040 | {
1041 | "url": "https://github.com/sebastianbergmann",
1042 | "type": "github"
1043 | }
1044 | ],
1045 | "time": "2020-04-18T05:02:12+00:00"
1046 | },
1047 | {
1048 | "name": "phpunit/php-invoker",
1049 | "version": "3.0.0",
1050 | "source": {
1051 | "type": "git",
1052 | "url": "https://github.com/sebastianbergmann/php-invoker.git",
1053 | "reference": "7579d5a1ba7f3ac11c80004d205877911315ae7a"
1054 | },
1055 | "dist": {
1056 | "type": "zip",
1057 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/7579d5a1ba7f3ac11c80004d205877911315ae7a",
1058 | "reference": "7579d5a1ba7f3ac11c80004d205877911315ae7a",
1059 | "shasum": ""
1060 | },
1061 | "require": {
1062 | "php": "^7.3"
1063 | },
1064 | "require-dev": {
1065 | "ext-pcntl": "*",
1066 | "phpunit/phpunit": "^9.0"
1067 | },
1068 | "suggest": {
1069 | "ext-pcntl": "*"
1070 | },
1071 | "type": "library",
1072 | "extra": {
1073 | "branch-alias": {
1074 | "dev-master": "3.0-dev"
1075 | }
1076 | },
1077 | "autoload": {
1078 | "classmap": [
1079 | "src/"
1080 | ]
1081 | },
1082 | "notification-url": "https://packagist.org/downloads/",
1083 | "license": [
1084 | "BSD-3-Clause"
1085 | ],
1086 | "authors": [
1087 | {
1088 | "name": "Sebastian Bergmann",
1089 | "email": "sebastian@phpunit.de",
1090 | "role": "lead"
1091 | }
1092 | ],
1093 | "description": "Invoke callables with a timeout",
1094 | "homepage": "https://github.com/sebastianbergmann/php-invoker/",
1095 | "keywords": [
1096 | "process"
1097 | ],
1098 | "time": "2020-02-07T06:06:11+00:00"
1099 | },
1100 | {
1101 | "name": "phpunit/php-text-template",
1102 | "version": "2.0.0",
1103 | "source": {
1104 | "type": "git",
1105 | "url": "https://github.com/sebastianbergmann/php-text-template.git",
1106 | "reference": "526dc996cc0ebdfa428cd2dfccd79b7b53fee346"
1107 | },
1108 | "dist": {
1109 | "type": "zip",
1110 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/526dc996cc0ebdfa428cd2dfccd79b7b53fee346",
1111 | "reference": "526dc996cc0ebdfa428cd2dfccd79b7b53fee346",
1112 | "shasum": ""
1113 | },
1114 | "require": {
1115 | "php": "^7.3"
1116 | },
1117 | "type": "library",
1118 | "extra": {
1119 | "branch-alias": {
1120 | "dev-master": "2.0-dev"
1121 | }
1122 | },
1123 | "autoload": {
1124 | "classmap": [
1125 | "src/"
1126 | ]
1127 | },
1128 | "notification-url": "https://packagist.org/downloads/",
1129 | "license": [
1130 | "BSD-3-Clause"
1131 | ],
1132 | "authors": [
1133 | {
1134 | "name": "Sebastian Bergmann",
1135 | "email": "sebastian@phpunit.de",
1136 | "role": "lead"
1137 | }
1138 | ],
1139 | "description": "Simple template engine.",
1140 | "homepage": "https://github.com/sebastianbergmann/php-text-template/",
1141 | "keywords": [
1142 | "template"
1143 | ],
1144 | "time": "2020-02-01T07:43:44+00:00"
1145 | },
1146 | {
1147 | "name": "phpunit/php-timer",
1148 | "version": "3.1.4",
1149 | "source": {
1150 | "type": "git",
1151 | "url": "https://github.com/sebastianbergmann/php-timer.git",
1152 | "reference": "dc9368fae6ef2ffa57eba80a7410bcef81df6258"
1153 | },
1154 | "dist": {
1155 | "type": "zip",
1156 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/dc9368fae6ef2ffa57eba80a7410bcef81df6258",
1157 | "reference": "dc9368fae6ef2ffa57eba80a7410bcef81df6258",
1158 | "shasum": ""
1159 | },
1160 | "require": {
1161 | "php": "^7.3"
1162 | },
1163 | "require-dev": {
1164 | "phpunit/phpunit": "^9.0"
1165 | },
1166 | "type": "library",
1167 | "extra": {
1168 | "branch-alias": {
1169 | "dev-master": "3.1-dev"
1170 | }
1171 | },
1172 | "autoload": {
1173 | "classmap": [
1174 | "src/"
1175 | ]
1176 | },
1177 | "notification-url": "https://packagist.org/downloads/",
1178 | "license": [
1179 | "BSD-3-Clause"
1180 | ],
1181 | "authors": [
1182 | {
1183 | "name": "Sebastian Bergmann",
1184 | "email": "sebastian@phpunit.de",
1185 | "role": "lead"
1186 | }
1187 | ],
1188 | "description": "Utility class for timing",
1189 | "homepage": "https://github.com/sebastianbergmann/php-timer/",
1190 | "keywords": [
1191 | "timer"
1192 | ],
1193 | "funding": [
1194 | {
1195 | "url": "https://github.com/sebastianbergmann",
1196 | "type": "github"
1197 | }
1198 | ],
1199 | "time": "2020-04-20T06:00:37+00:00"
1200 | },
1201 | {
1202 | "name": "phpunit/php-token-stream",
1203 | "version": "4.0.1",
1204 | "source": {
1205 | "type": "git",
1206 | "url": "https://github.com/sebastianbergmann/php-token-stream.git",
1207 | "reference": "cdc0db5aed8fbfaf475fbd95bfd7bab83c7a779c"
1208 | },
1209 | "dist": {
1210 | "type": "zip",
1211 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/cdc0db5aed8fbfaf475fbd95bfd7bab83c7a779c",
1212 | "reference": "cdc0db5aed8fbfaf475fbd95bfd7bab83c7a779c",
1213 | "shasum": ""
1214 | },
1215 | "require": {
1216 | "ext-tokenizer": "*",
1217 | "php": "^7.3"
1218 | },
1219 | "require-dev": {
1220 | "phpunit/phpunit": "^9.0"
1221 | },
1222 | "type": "library",
1223 | "extra": {
1224 | "branch-alias": {
1225 | "dev-master": "4.0-dev"
1226 | }
1227 | },
1228 | "autoload": {
1229 | "classmap": [
1230 | "src/"
1231 | ]
1232 | },
1233 | "notification-url": "https://packagist.org/downloads/",
1234 | "license": [
1235 | "BSD-3-Clause"
1236 | ],
1237 | "authors": [
1238 | {
1239 | "name": "Sebastian Bergmann",
1240 | "email": "sebastian@phpunit.de"
1241 | }
1242 | ],
1243 | "description": "Wrapper around PHP's tokenizer extension.",
1244 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
1245 | "keywords": [
1246 | "tokenizer"
1247 | ],
1248 | "funding": [
1249 | {
1250 | "url": "https://github.com/sebastianbergmann",
1251 | "type": "github"
1252 | }
1253 | ],
1254 | "time": "2020-05-06T09:56:31+00:00"
1255 | },
1256 | {
1257 | "name": "phpunit/phpunit",
1258 | "version": "9.1.5",
1259 | "source": {
1260 | "type": "git",
1261 | "url": "https://github.com/sebastianbergmann/phpunit.git",
1262 | "reference": "1b570cd7edbe136055bf5f651857dc8af6b829d2"
1263 | },
1264 | "dist": {
1265 | "type": "zip",
1266 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1b570cd7edbe136055bf5f651857dc8af6b829d2",
1267 | "reference": "1b570cd7edbe136055bf5f651857dc8af6b829d2",
1268 | "shasum": ""
1269 | },
1270 | "require": {
1271 | "doctrine/instantiator": "^1.2.0",
1272 | "ext-dom": "*",
1273 | "ext-json": "*",
1274 | "ext-libxml": "*",
1275 | "ext-mbstring": "*",
1276 | "ext-xml": "*",
1277 | "ext-xmlwriter": "*",
1278 | "myclabs/deep-copy": "^1.9.1",
1279 | "phar-io/manifest": "^1.0.3",
1280 | "phar-io/version": "^2.0.1",
1281 | "php": "^7.3",
1282 | "phpspec/prophecy": "^1.8.1",
1283 | "phpunit/php-code-coverage": "^8.0.1",
1284 | "phpunit/php-file-iterator": "^3.0",
1285 | "phpunit/php-invoker": "^3.0",
1286 | "phpunit/php-text-template": "^2.0",
1287 | "phpunit/php-timer": "^3.1.4",
1288 | "sebastian/code-unit": "^1.0.2",
1289 | "sebastian/comparator": "^4.0",
1290 | "sebastian/diff": "^4.0",
1291 | "sebastian/environment": "^5.0.1",
1292 | "sebastian/exporter": "^4.0",
1293 | "sebastian/global-state": "^4.0",
1294 | "sebastian/object-enumerator": "^4.0",
1295 | "sebastian/resource-operations": "^3.0",
1296 | "sebastian/type": "^2.0",
1297 | "sebastian/version": "^3.0"
1298 | },
1299 | "require-dev": {
1300 | "ext-pdo": "*",
1301 | "phpspec/prophecy-phpunit": "^2.0"
1302 | },
1303 | "suggest": {
1304 | "ext-soap": "*",
1305 | "ext-xdebug": "*"
1306 | },
1307 | "bin": [
1308 | "phpunit"
1309 | ],
1310 | "type": "library",
1311 | "extra": {
1312 | "branch-alias": {
1313 | "dev-master": "9.1-dev"
1314 | }
1315 | },
1316 | "autoload": {
1317 | "classmap": [
1318 | "src/"
1319 | ],
1320 | "files": [
1321 | "src/Framework/Assert/Functions.php"
1322 | ]
1323 | },
1324 | "notification-url": "https://packagist.org/downloads/",
1325 | "license": [
1326 | "BSD-3-Clause"
1327 | ],
1328 | "authors": [
1329 | {
1330 | "name": "Sebastian Bergmann",
1331 | "email": "sebastian@phpunit.de",
1332 | "role": "lead"
1333 | }
1334 | ],
1335 | "description": "The PHP Unit Testing framework.",
1336 | "homepage": "https://phpunit.de/",
1337 | "keywords": [
1338 | "phpunit",
1339 | "testing",
1340 | "xunit"
1341 | ],
1342 | "funding": [
1343 | {
1344 | "url": "https://phpunit.de/donate.html",
1345 | "type": "custom"
1346 | },
1347 | {
1348 | "url": "https://github.com/sebastianbergmann",
1349 | "type": "github"
1350 | }
1351 | ],
1352 | "time": "2020-05-22T13:54:05+00:00"
1353 | },
1354 | {
1355 | "name": "sebastian/code-unit",
1356 | "version": "1.0.2",
1357 | "source": {
1358 | "type": "git",
1359 | "url": "https://github.com/sebastianbergmann/code-unit.git",
1360 | "reference": "ac958085bc19fcd1d36425c781ef4cbb5b06e2a5"
1361 | },
1362 | "dist": {
1363 | "type": "zip",
1364 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/ac958085bc19fcd1d36425c781ef4cbb5b06e2a5",
1365 | "reference": "ac958085bc19fcd1d36425c781ef4cbb5b06e2a5",
1366 | "shasum": ""
1367 | },
1368 | "require": {
1369 | "php": "^7.3"
1370 | },
1371 | "require-dev": {
1372 | "phpunit/phpunit": "^9.0"
1373 | },
1374 | "type": "library",
1375 | "extra": {
1376 | "branch-alias": {
1377 | "dev-master": "1.0-dev"
1378 | }
1379 | },
1380 | "autoload": {
1381 | "classmap": [
1382 | "src/"
1383 | ]
1384 | },
1385 | "notification-url": "https://packagist.org/downloads/",
1386 | "license": [
1387 | "BSD-3-Clause"
1388 | ],
1389 | "authors": [
1390 | {
1391 | "name": "Sebastian Bergmann",
1392 | "email": "sebastian@phpunit.de",
1393 | "role": "lead"
1394 | }
1395 | ],
1396 | "description": "Collection of value objects that represent the PHP code units",
1397 | "homepage": "https://github.com/sebastianbergmann/code-unit",
1398 | "funding": [
1399 | {
1400 | "url": "https://github.com/sebastianbergmann",
1401 | "type": "github"
1402 | }
1403 | ],
1404 | "time": "2020-04-30T05:58:10+00:00"
1405 | },
1406 | {
1407 | "name": "sebastian/code-unit-reverse-lookup",
1408 | "version": "2.0.0",
1409 | "source": {
1410 | "type": "git",
1411 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
1412 | "reference": "5b5dbe0044085ac41df47e79d34911a15b96d82e"
1413 | },
1414 | "dist": {
1415 | "type": "zip",
1416 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5b5dbe0044085ac41df47e79d34911a15b96d82e",
1417 | "reference": "5b5dbe0044085ac41df47e79d34911a15b96d82e",
1418 | "shasum": ""
1419 | },
1420 | "require": {
1421 | "php": "^7.3"
1422 | },
1423 | "require-dev": {
1424 | "phpunit/phpunit": "^9.0"
1425 | },
1426 | "type": "library",
1427 | "extra": {
1428 | "branch-alias": {
1429 | "dev-master": "2.0-dev"
1430 | }
1431 | },
1432 | "autoload": {
1433 | "classmap": [
1434 | "src/"
1435 | ]
1436 | },
1437 | "notification-url": "https://packagist.org/downloads/",
1438 | "license": [
1439 | "BSD-3-Clause"
1440 | ],
1441 | "authors": [
1442 | {
1443 | "name": "Sebastian Bergmann",
1444 | "email": "sebastian@phpunit.de"
1445 | }
1446 | ],
1447 | "description": "Looks up which function or method a line of code belongs to",
1448 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
1449 | "time": "2020-02-07T06:20:13+00:00"
1450 | },
1451 | {
1452 | "name": "sebastian/comparator",
1453 | "version": "4.0.0",
1454 | "source": {
1455 | "type": "git",
1456 | "url": "https://github.com/sebastianbergmann/comparator.git",
1457 | "reference": "85b3435da967696ed618ff745f32be3ff4a2b8e8"
1458 | },
1459 | "dist": {
1460 | "type": "zip",
1461 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85b3435da967696ed618ff745f32be3ff4a2b8e8",
1462 | "reference": "85b3435da967696ed618ff745f32be3ff4a2b8e8",
1463 | "shasum": ""
1464 | },
1465 | "require": {
1466 | "php": "^7.3",
1467 | "sebastian/diff": "^4.0",
1468 | "sebastian/exporter": "^4.0"
1469 | },
1470 | "require-dev": {
1471 | "phpunit/phpunit": "^9.0"
1472 | },
1473 | "type": "library",
1474 | "extra": {
1475 | "branch-alias": {
1476 | "dev-master": "4.0-dev"
1477 | }
1478 | },
1479 | "autoload": {
1480 | "classmap": [
1481 | "src/"
1482 | ]
1483 | },
1484 | "notification-url": "https://packagist.org/downloads/",
1485 | "license": [
1486 | "BSD-3-Clause"
1487 | ],
1488 | "authors": [
1489 | {
1490 | "name": "Sebastian Bergmann",
1491 | "email": "sebastian@phpunit.de"
1492 | },
1493 | {
1494 | "name": "Jeff Welch",
1495 | "email": "whatthejeff@gmail.com"
1496 | },
1497 | {
1498 | "name": "Volker Dusch",
1499 | "email": "github@wallbash.com"
1500 | },
1501 | {
1502 | "name": "Bernhard Schussek",
1503 | "email": "bschussek@2bepublished.at"
1504 | }
1505 | ],
1506 | "description": "Provides the functionality to compare PHP values for equality",
1507 | "homepage": "https://github.com/sebastianbergmann/comparator",
1508 | "keywords": [
1509 | "comparator",
1510 | "compare",
1511 | "equality"
1512 | ],
1513 | "time": "2020-02-07T06:08:51+00:00"
1514 | },
1515 | {
1516 | "name": "sebastian/diff",
1517 | "version": "4.0.1",
1518 | "source": {
1519 | "type": "git",
1520 | "url": "https://github.com/sebastianbergmann/diff.git",
1521 | "reference": "3e523c576f29dacecff309f35e4cc5a5c168e78a"
1522 | },
1523 | "dist": {
1524 | "type": "zip",
1525 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3e523c576f29dacecff309f35e4cc5a5c168e78a",
1526 | "reference": "3e523c576f29dacecff309f35e4cc5a5c168e78a",
1527 | "shasum": ""
1528 | },
1529 | "require": {
1530 | "php": "^7.3"
1531 | },
1532 | "require-dev": {
1533 | "phpunit/phpunit": "^9.0",
1534 | "symfony/process": "^4.2 || ^5"
1535 | },
1536 | "type": "library",
1537 | "extra": {
1538 | "branch-alias": {
1539 | "dev-master": "4.0-dev"
1540 | }
1541 | },
1542 | "autoload": {
1543 | "classmap": [
1544 | "src/"
1545 | ]
1546 | },
1547 | "notification-url": "https://packagist.org/downloads/",
1548 | "license": [
1549 | "BSD-3-Clause"
1550 | ],
1551 | "authors": [
1552 | {
1553 | "name": "Sebastian Bergmann",
1554 | "email": "sebastian@phpunit.de"
1555 | },
1556 | {
1557 | "name": "Kore Nordmann",
1558 | "email": "mail@kore-nordmann.de"
1559 | }
1560 | ],
1561 | "description": "Diff implementation",
1562 | "homepage": "https://github.com/sebastianbergmann/diff",
1563 | "keywords": [
1564 | "diff",
1565 | "udiff",
1566 | "unidiff",
1567 | "unified diff"
1568 | ],
1569 | "funding": [
1570 | {
1571 | "url": "https://github.com/sebastianbergmann",
1572 | "type": "github"
1573 | }
1574 | ],
1575 | "time": "2020-05-08T05:01:12+00:00"
1576 | },
1577 | {
1578 | "name": "sebastian/environment",
1579 | "version": "5.1.0",
1580 | "source": {
1581 | "type": "git",
1582 | "url": "https://github.com/sebastianbergmann/environment.git",
1583 | "reference": "c753f04d68cd489b6973cf9b4e505e191af3b05c"
1584 | },
1585 | "dist": {
1586 | "type": "zip",
1587 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/c753f04d68cd489b6973cf9b4e505e191af3b05c",
1588 | "reference": "c753f04d68cd489b6973cf9b4e505e191af3b05c",
1589 | "shasum": ""
1590 | },
1591 | "require": {
1592 | "php": "^7.3"
1593 | },
1594 | "require-dev": {
1595 | "phpunit/phpunit": "^9.0"
1596 | },
1597 | "suggest": {
1598 | "ext-posix": "*"
1599 | },
1600 | "type": "library",
1601 | "extra": {
1602 | "branch-alias": {
1603 | "dev-master": "5.0-dev"
1604 | }
1605 | },
1606 | "autoload": {
1607 | "classmap": [
1608 | "src/"
1609 | ]
1610 | },
1611 | "notification-url": "https://packagist.org/downloads/",
1612 | "license": [
1613 | "BSD-3-Clause"
1614 | ],
1615 | "authors": [
1616 | {
1617 | "name": "Sebastian Bergmann",
1618 | "email": "sebastian@phpunit.de"
1619 | }
1620 | ],
1621 | "description": "Provides functionality to handle HHVM/PHP environments",
1622 | "homepage": "http://www.github.com/sebastianbergmann/environment",
1623 | "keywords": [
1624 | "Xdebug",
1625 | "environment",
1626 | "hhvm"
1627 | ],
1628 | "funding": [
1629 | {
1630 | "url": "https://github.com/sebastianbergmann",
1631 | "type": "github"
1632 | }
1633 | ],
1634 | "time": "2020-04-14T13:36:52+00:00"
1635 | },
1636 | {
1637 | "name": "sebastian/exporter",
1638 | "version": "4.0.0",
1639 | "source": {
1640 | "type": "git",
1641 | "url": "https://github.com/sebastianbergmann/exporter.git",
1642 | "reference": "80c26562e964016538f832f305b2286e1ec29566"
1643 | },
1644 | "dist": {
1645 | "type": "zip",
1646 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/80c26562e964016538f832f305b2286e1ec29566",
1647 | "reference": "80c26562e964016538f832f305b2286e1ec29566",
1648 | "shasum": ""
1649 | },
1650 | "require": {
1651 | "php": "^7.3",
1652 | "sebastian/recursion-context": "^4.0"
1653 | },
1654 | "require-dev": {
1655 | "ext-mbstring": "*",
1656 | "phpunit/phpunit": "^9.0"
1657 | },
1658 | "type": "library",
1659 | "extra": {
1660 | "branch-alias": {
1661 | "dev-master": "4.0-dev"
1662 | }
1663 | },
1664 | "autoload": {
1665 | "classmap": [
1666 | "src/"
1667 | ]
1668 | },
1669 | "notification-url": "https://packagist.org/downloads/",
1670 | "license": [
1671 | "BSD-3-Clause"
1672 | ],
1673 | "authors": [
1674 | {
1675 | "name": "Sebastian Bergmann",
1676 | "email": "sebastian@phpunit.de"
1677 | },
1678 | {
1679 | "name": "Jeff Welch",
1680 | "email": "whatthejeff@gmail.com"
1681 | },
1682 | {
1683 | "name": "Volker Dusch",
1684 | "email": "github@wallbash.com"
1685 | },
1686 | {
1687 | "name": "Adam Harvey",
1688 | "email": "aharvey@php.net"
1689 | },
1690 | {
1691 | "name": "Bernhard Schussek",
1692 | "email": "bschussek@gmail.com"
1693 | }
1694 | ],
1695 | "description": "Provides the functionality to export PHP variables for visualization",
1696 | "homepage": "http://www.github.com/sebastianbergmann/exporter",
1697 | "keywords": [
1698 | "export",
1699 | "exporter"
1700 | ],
1701 | "time": "2020-02-07T06:10:52+00:00"
1702 | },
1703 | {
1704 | "name": "sebastian/global-state",
1705 | "version": "4.0.0",
1706 | "source": {
1707 | "type": "git",
1708 | "url": "https://github.com/sebastianbergmann/global-state.git",
1709 | "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72"
1710 | },
1711 | "dist": {
1712 | "type": "zip",
1713 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bdb1e7c79e592b8c82cb1699be3c8743119b8a72",
1714 | "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72",
1715 | "shasum": ""
1716 | },
1717 | "require": {
1718 | "php": "^7.3",
1719 | "sebastian/object-reflector": "^2.0",
1720 | "sebastian/recursion-context": "^4.0"
1721 | },
1722 | "require-dev": {
1723 | "ext-dom": "*",
1724 | "phpunit/phpunit": "^9.0"
1725 | },
1726 | "suggest": {
1727 | "ext-uopz": "*"
1728 | },
1729 | "type": "library",
1730 | "extra": {
1731 | "branch-alias": {
1732 | "dev-master": "4.0-dev"
1733 | }
1734 | },
1735 | "autoload": {
1736 | "classmap": [
1737 | "src/"
1738 | ]
1739 | },
1740 | "notification-url": "https://packagist.org/downloads/",
1741 | "license": [
1742 | "BSD-3-Clause"
1743 | ],
1744 | "authors": [
1745 | {
1746 | "name": "Sebastian Bergmann",
1747 | "email": "sebastian@phpunit.de"
1748 | }
1749 | ],
1750 | "description": "Snapshotting of global state",
1751 | "homepage": "http://www.github.com/sebastianbergmann/global-state",
1752 | "keywords": [
1753 | "global state"
1754 | ],
1755 | "time": "2020-02-07T06:11:37+00:00"
1756 | },
1757 | {
1758 | "name": "sebastian/object-enumerator",
1759 | "version": "4.0.0",
1760 | "source": {
1761 | "type": "git",
1762 | "url": "https://github.com/sebastianbergmann/object-enumerator.git",
1763 | "reference": "e67516b175550abad905dc952f43285957ef4363"
1764 | },
1765 | "dist": {
1766 | "type": "zip",
1767 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67516b175550abad905dc952f43285957ef4363",
1768 | "reference": "e67516b175550abad905dc952f43285957ef4363",
1769 | "shasum": ""
1770 | },
1771 | "require": {
1772 | "php": "^7.3",
1773 | "sebastian/object-reflector": "^2.0",
1774 | "sebastian/recursion-context": "^4.0"
1775 | },
1776 | "require-dev": {
1777 | "phpunit/phpunit": "^9.0"
1778 | },
1779 | "type": "library",
1780 | "extra": {
1781 | "branch-alias": {
1782 | "dev-master": "4.0-dev"
1783 | }
1784 | },
1785 | "autoload": {
1786 | "classmap": [
1787 | "src/"
1788 | ]
1789 | },
1790 | "notification-url": "https://packagist.org/downloads/",
1791 | "license": [
1792 | "BSD-3-Clause"
1793 | ],
1794 | "authors": [
1795 | {
1796 | "name": "Sebastian Bergmann",
1797 | "email": "sebastian@phpunit.de"
1798 | }
1799 | ],
1800 | "description": "Traverses array structures and object graphs to enumerate all referenced objects",
1801 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
1802 | "time": "2020-02-07T06:12:23+00:00"
1803 | },
1804 | {
1805 | "name": "sebastian/object-reflector",
1806 | "version": "2.0.0",
1807 | "source": {
1808 | "type": "git",
1809 | "url": "https://github.com/sebastianbergmann/object-reflector.git",
1810 | "reference": "f4fd0835cabb0d4a6546d9fe291e5740037aa1e7"
1811 | },
1812 | "dist": {
1813 | "type": "zip",
1814 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/f4fd0835cabb0d4a6546d9fe291e5740037aa1e7",
1815 | "reference": "f4fd0835cabb0d4a6546d9fe291e5740037aa1e7",
1816 | "shasum": ""
1817 | },
1818 | "require": {
1819 | "php": "^7.3"
1820 | },
1821 | "require-dev": {
1822 | "phpunit/phpunit": "^9.0"
1823 | },
1824 | "type": "library",
1825 | "extra": {
1826 | "branch-alias": {
1827 | "dev-master": "2.0-dev"
1828 | }
1829 | },
1830 | "autoload": {
1831 | "classmap": [
1832 | "src/"
1833 | ]
1834 | },
1835 | "notification-url": "https://packagist.org/downloads/",
1836 | "license": [
1837 | "BSD-3-Clause"
1838 | ],
1839 | "authors": [
1840 | {
1841 | "name": "Sebastian Bergmann",
1842 | "email": "sebastian@phpunit.de"
1843 | }
1844 | ],
1845 | "description": "Allows reflection of object attributes, including inherited and non-public ones",
1846 | "homepage": "https://github.com/sebastianbergmann/object-reflector/",
1847 | "time": "2020-02-07T06:19:40+00:00"
1848 | },
1849 | {
1850 | "name": "sebastian/recursion-context",
1851 | "version": "4.0.0",
1852 | "source": {
1853 | "type": "git",
1854 | "url": "https://github.com/sebastianbergmann/recursion-context.git",
1855 | "reference": "cdd86616411fc3062368b720b0425de10bd3d579"
1856 | },
1857 | "dist": {
1858 | "type": "zip",
1859 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cdd86616411fc3062368b720b0425de10bd3d579",
1860 | "reference": "cdd86616411fc3062368b720b0425de10bd3d579",
1861 | "shasum": ""
1862 | },
1863 | "require": {
1864 | "php": "^7.3"
1865 | },
1866 | "require-dev": {
1867 | "phpunit/phpunit": "^9.0"
1868 | },
1869 | "type": "library",
1870 | "extra": {
1871 | "branch-alias": {
1872 | "dev-master": "4.0-dev"
1873 | }
1874 | },
1875 | "autoload": {
1876 | "classmap": [
1877 | "src/"
1878 | ]
1879 | },
1880 | "notification-url": "https://packagist.org/downloads/",
1881 | "license": [
1882 | "BSD-3-Clause"
1883 | ],
1884 | "authors": [
1885 | {
1886 | "name": "Sebastian Bergmann",
1887 | "email": "sebastian@phpunit.de"
1888 | },
1889 | {
1890 | "name": "Jeff Welch",
1891 | "email": "whatthejeff@gmail.com"
1892 | },
1893 | {
1894 | "name": "Adam Harvey",
1895 | "email": "aharvey@php.net"
1896 | }
1897 | ],
1898 | "description": "Provides functionality to recursively process PHP variables",
1899 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
1900 | "time": "2020-02-07T06:18:20+00:00"
1901 | },
1902 | {
1903 | "name": "sebastian/resource-operations",
1904 | "version": "3.0.0",
1905 | "source": {
1906 | "type": "git",
1907 | "url": "https://github.com/sebastianbergmann/resource-operations.git",
1908 | "reference": "8c98bf0dfa1f9256d0468b9803a1e1df31b6fa98"
1909 | },
1910 | "dist": {
1911 | "type": "zip",
1912 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/8c98bf0dfa1f9256d0468b9803a1e1df31b6fa98",
1913 | "reference": "8c98bf0dfa1f9256d0468b9803a1e1df31b6fa98",
1914 | "shasum": ""
1915 | },
1916 | "require": {
1917 | "php": "^7.3"
1918 | },
1919 | "require-dev": {
1920 | "phpunit/phpunit": "^9.0"
1921 | },
1922 | "type": "library",
1923 | "extra": {
1924 | "branch-alias": {
1925 | "dev-master": "3.0-dev"
1926 | }
1927 | },
1928 | "autoload": {
1929 | "classmap": [
1930 | "src/"
1931 | ]
1932 | },
1933 | "notification-url": "https://packagist.org/downloads/",
1934 | "license": [
1935 | "BSD-3-Clause"
1936 | ],
1937 | "authors": [
1938 | {
1939 | "name": "Sebastian Bergmann",
1940 | "email": "sebastian@phpunit.de"
1941 | }
1942 | ],
1943 | "description": "Provides a list of PHP built-in functions that operate on resources",
1944 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
1945 | "time": "2020-02-07T06:13:02+00:00"
1946 | },
1947 | {
1948 | "name": "sebastian/type",
1949 | "version": "2.0.0",
1950 | "source": {
1951 | "type": "git",
1952 | "url": "https://github.com/sebastianbergmann/type.git",
1953 | "reference": "9e8f42f740afdea51f5f4e8cec2035580e797ee1"
1954 | },
1955 | "dist": {
1956 | "type": "zip",
1957 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/9e8f42f740afdea51f5f4e8cec2035580e797ee1",
1958 | "reference": "9e8f42f740afdea51f5f4e8cec2035580e797ee1",
1959 | "shasum": ""
1960 | },
1961 | "require": {
1962 | "php": "^7.3"
1963 | },
1964 | "require-dev": {
1965 | "phpunit/phpunit": "^9.0"
1966 | },
1967 | "type": "library",
1968 | "extra": {
1969 | "branch-alias": {
1970 | "dev-master": "2.0-dev"
1971 | }
1972 | },
1973 | "autoload": {
1974 | "classmap": [
1975 | "src/"
1976 | ]
1977 | },
1978 | "notification-url": "https://packagist.org/downloads/",
1979 | "license": [
1980 | "BSD-3-Clause"
1981 | ],
1982 | "authors": [
1983 | {
1984 | "name": "Sebastian Bergmann",
1985 | "email": "sebastian@phpunit.de",
1986 | "role": "lead"
1987 | }
1988 | ],
1989 | "description": "Collection of value objects that represent the types of the PHP type system",
1990 | "homepage": "https://github.com/sebastianbergmann/type",
1991 | "time": "2020-02-07T06:13:43+00:00"
1992 | },
1993 | {
1994 | "name": "sebastian/version",
1995 | "version": "3.0.0",
1996 | "source": {
1997 | "type": "git",
1998 | "url": "https://github.com/sebastianbergmann/version.git",
1999 | "reference": "0411bde656dce64202b39c2f4473993a9081d39e"
2000 | },
2001 | "dist": {
2002 | "type": "zip",
2003 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/0411bde656dce64202b39c2f4473993a9081d39e",
2004 | "reference": "0411bde656dce64202b39c2f4473993a9081d39e",
2005 | "shasum": ""
2006 | },
2007 | "require": {
2008 | "php": "^7.3"
2009 | },
2010 | "type": "library",
2011 | "extra": {
2012 | "branch-alias": {
2013 | "dev-master": "3.0-dev"
2014 | }
2015 | },
2016 | "autoload": {
2017 | "classmap": [
2018 | "src/"
2019 | ]
2020 | },
2021 | "notification-url": "https://packagist.org/downloads/",
2022 | "license": [
2023 | "BSD-3-Clause"
2024 | ],
2025 | "authors": [
2026 | {
2027 | "name": "Sebastian Bergmann",
2028 | "email": "sebastian@phpunit.de",
2029 | "role": "lead"
2030 | }
2031 | ],
2032 | "description": "Library that helps with managing the version number of Git-hosted PHP projects",
2033 | "homepage": "https://github.com/sebastianbergmann/version",
2034 | "time": "2020-01-21T06:36:37+00:00"
2035 | },
2036 | {
2037 | "name": "theseer/tokenizer",
2038 | "version": "1.1.3",
2039 | "source": {
2040 | "type": "git",
2041 | "url": "https://github.com/theseer/tokenizer.git",
2042 | "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9"
2043 | },
2044 | "dist": {
2045 | "type": "zip",
2046 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9",
2047 | "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9",
2048 | "shasum": ""
2049 | },
2050 | "require": {
2051 | "ext-dom": "*",
2052 | "ext-tokenizer": "*",
2053 | "ext-xmlwriter": "*",
2054 | "php": "^7.0"
2055 | },
2056 | "type": "library",
2057 | "autoload": {
2058 | "classmap": [
2059 | "src/"
2060 | ]
2061 | },
2062 | "notification-url": "https://packagist.org/downloads/",
2063 | "license": [
2064 | "BSD-3-Clause"
2065 | ],
2066 | "authors": [
2067 | {
2068 | "name": "Arne Blankerts",
2069 | "email": "arne@blankerts.de",
2070 | "role": "Developer"
2071 | }
2072 | ],
2073 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
2074 | "time": "2019-06-13T22:48:21+00:00"
2075 | }
2076 | ],
2077 | "aliases": [],
2078 | "minimum-stability": "stable",
2079 | "stability-flags": [],
2080 | "prefer-stable": false,
2081 | "prefer-lowest": false,
2082 | "platform": {
2083 | "php": ">=7.1.0",
2084 | "ext-curl": "*"
2085 | },
2086 | "platform-dev": [],
2087 | "plugin-api-version": "1.1.0"
2088 | }
2089 |
--------------------------------------------------------------------------------
/controllers/BuildController.php:
--------------------------------------------------------------------------------
1 | sourceDirs) {
51 | $context->addDirs($this->sourceDirs);
52 | }
53 | if ($this->sourceModules) {
54 | $context->addModules($this->sourceModules);
55 | }
56 | if ($this->sortProperty) {
57 | $context->sortControllers($this->sortProperty);
58 | }
59 | $result = $this->renderPartial(Yii::getAlias($this->template), ['controllers' => $context->controllers]);
60 | if ($this->targetFile) {
61 | file_put_contents(Yii::getAlias($this->targetFile), $result);
62 | } else {
63 | echo $result;
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/helpers/DocBlockHelper.php:
--------------------------------------------------------------------------------
1 | getTagsByName('inheritdoc') || $docBlock->getTagsByName('inherited');
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/models/ControllerDoc.php:
--------------------------------------------------------------------------------
1 | _longDescription;
56 | }
57 |
58 | /**
59 | * @return string
60 | */
61 | public function getShortDescription()
62 | {
63 | return $this->_shortDescription;
64 | }
65 |
66 | /**
67 | * @param $value
68 | * @return bool If label attached to doc
69 | */
70 | public function hasLabel($value)
71 | {
72 | return isset($this->_labels[$value]);
73 | }
74 |
75 | /**
76 | * Prepares doc
77 | */
78 | public function prepare()
79 | {
80 | parent::prepare();
81 |
82 | foreach ($this->getTagsByName('label') as $tag) {
83 | $this->_labels[$tag->getContent()] = true;
84 | }
85 |
86 | $this->query = $this->getTagsByName('query');
87 |
88 | if ($this->model) {
89 | $this->model->prepare();
90 | }
91 | }
92 |
93 | /**
94 | * @param $value
95 | */
96 | public function setShortDescription($value)
97 | {
98 | if (!$this->_shortDescription && $value) {
99 | $this->_shortDescription = $value;
100 | }
101 | }
102 |
103 | /**
104 | * @param $value
105 | */
106 | public function setLongDescription($value)
107 | {
108 | if (!$this->_longDescription && $value) {
109 | $this->_longDescription = $value;
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/models/ControllerParser.php:
--------------------------------------------------------------------------------
1 | reflection->isAbstract()) {
44 | $this->error = $this->reflection->name . " is abstract";
45 | return false;
46 | }
47 |
48 | $this->parseClass($doc);
49 |
50 | if ($doc->getTagsByName('ignore')) {
51 | $this->error = $this->reflection->name . " has ignore tag";
52 | return false;
53 | }
54 |
55 | $doc->path = Inflector::camel2id(substr($this->reflection->getShortName(), 0, -strlen('Controller')));
56 | $doc->actions = $this->parseActions();
57 |
58 | // Parse model
59 | $modelParser = Yii::createObject(
60 | [
61 | 'class' => '\pahanini\restdoc\models\ModelParser',
62 | 'reflection' => new \ReflectionClass($this->getObject()->modelClass),
63 | ]
64 | );
65 | $doc->model = new ModelDoc();
66 | $modelParser->parse($doc->model);
67 |
68 | return true;
69 | }
70 |
71 | /**
72 | * @param $doc
73 | * @return bool
74 | */
75 | public function parseClass(ControllerDoc $doc)
76 | {
77 | if (!$docBlock = new DocBlock($this->reflection)) {
78 | return false;
79 | }
80 |
81 | $doc->longDescription = $docBlock->getLongDescription()->getContents();
82 | $doc->shortDescription = $docBlock->getShortDescription();
83 |
84 | $doc->populateTags($docBlock);
85 |
86 | if (DocBlockHelper::isInherit($docBlock)) {
87 | $parentParser = $this->getParentParser();
88 | $parentParser->parseClass($doc);
89 | }
90 | }
91 |
92 | /**
93 | * include actions defined in controller, as well as those returned by `Controller::actions()` method
94 | *
95 | * @return array
96 | */
97 | private function parseActions()
98 | {
99 | // default controller actions
100 | $actions = array_keys($this->getObject()->actions());
101 | $actionMethods = array_filter($this->reflection->getMethods(),
102 | function ($method) {
103 | // should match all methods named actionSomeAction
104 | return preg_match('/action([A-Z]{1}[a-zA-Z]+)/', $method->name, $matches);
105 | });
106 | $actionMethods = array_map(function ($method) {
107 | return Inflector::slug(str_replace('action', '', $method->name));
108 | }, $actionMethods);
109 | $actionMethods = array_merge($actions, $actionMethods);
110 |
111 | return array_intersect(['index', 'view', 'create', 'update', 'delete', 'options'], $actionMethods);
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/models/Doc.php:
--------------------------------------------------------------------------------
1 | _parent;
32 | }
33 |
34 | /**
35 | * Returns tags with given name.
36 | *
37 | * @param $name
38 | * @return array
39 | */
40 | public function getTagsByName($name)
41 | {
42 | return isset($this->_tags[$name]) ? $this->_tags[$name] : [];
43 | }
44 |
45 | /**
46 | * @param Doc $value
47 | */
48 | public function setParent(Doc $value)
49 | {
50 | $this->_parent = $value;
51 | }
52 |
53 | /**
54 | * Extracts tags from docBlock and adds it to document.
55 | *
56 | * @param DocBlock $docBlock
57 | */
58 | public function populateTags(DocBlock $docBlock)
59 | {
60 | $tags = $docBlock->getTags();
61 | $offset = strlen(self::TAG_PREFIX);
62 | foreach ($tags as $tag) {
63 | $name = $tag->getName();
64 | if (strpos($name, self::TAG_PREFIX) === 0) {
65 | $key = substr($name, $offset);
66 | if (!isset($this->_tags)) {
67 | $this->_tags[$key] = [];
68 | }
69 | $this->_tags[$key][] = $tag;
70 | }
71 | }
72 | }
73 |
74 | /**
75 | * Prepares doc.
76 | */
77 | public function prepare()
78 | {
79 | null;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/models/FieldDoc.php:
--------------------------------------------------------------------------------
1 | _description;
18 | }
19 |
20 | public function getName()
21 | {
22 | return $this->_name;
23 | }
24 |
25 | public function getType()
26 | {
27 | return $this->_type;
28 | }
29 |
30 | public function isInScenario($name)
31 | {
32 | return isset($this->_scenarios[$name]);
33 | }
34 |
35 | public function setDescription($value)
36 | {
37 | if ($value) {
38 | $this->_description = $value;
39 | }
40 | }
41 |
42 | public function setName($value)
43 | {
44 | if ($value) {
45 | $this->_name = $value;
46 | }
47 | }
48 |
49 | public function setType($value)
50 | {
51 | if ($value) {
52 | $this->_type = $value;
53 | }
54 | }
55 |
56 | public function setScenarios(array $value)
57 | {
58 | $this->_scenarios = array_merge($this->_scenarios, $value);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/models/ModelDoc.php:
--------------------------------------------------------------------------------
1 | setName($name);
39 | $field->setParent($this);
40 | $fields[$name] = $field;
41 | }
42 | $fields[$name]->setScenarios($scenarios);
43 | $fields[$name]->setDescription($description);
44 | $fields[$name]->setType($type);
45 | }
46 |
47 | /**
48 | * @param array $fields
49 | * @param string $name
50 | */
51 | private function _removeField(&$fields, $name)
52 | {
53 | if (isset($fields[$name])) {
54 | unset($fields[$name]);
55 | }
56 | }
57 |
58 | /**
59 | * @param string $name
60 | * @param string $type
61 | * @param string $description
62 | * @param array $scenarios
63 | */
64 | public function addField($name, $type = '', $description = '', $scenarios = [])
65 | {
66 | $this->_addField($this->_fields, $name, $type, $description, $scenarios);
67 | }
68 |
69 | /**
70 | * @param string $name
71 | * @param string $type
72 | * @param string $description
73 | */
74 | public function addExtraField($name, $type = '', $description = '')
75 | {
76 | $this->_addField($this->_extraFields, $name, $type, $description);
77 | }
78 |
79 | /**
80 | * @param string $name
81 | */
82 | public function removeField($name)
83 | {
84 | $this->_removeField($this->_fields, $name);
85 | }
86 |
87 | /**
88 | * @param string $name
89 | */
90 | public function removeExtraField($name)
91 | {
92 | $this->_removeField($this->_extraFields, $name);
93 | }
94 |
95 | /**
96 | * @param $name
97 | */
98 | public function addSortField($name)
99 | {
100 | $this->_addField($this->_sortFields, $name);
101 | }
102 |
103 | /**
104 | * Adds scenario info
105 | *
106 | * @param $key
107 | * @param array $fields
108 | */
109 | public function addScenario($key, array $fields)
110 | {
111 | $this->_scenarios[$key] = $fields;
112 | }
113 |
114 | /**
115 | * @return \pahanini\restdoc\models\FieldDoc[]
116 | */
117 | public function getExtraFields()
118 | {
119 | return $this->_extraFields;
120 | }
121 |
122 | /**
123 | * @return \pahanini\restdoc\models\FieldDoc[]
124 | */
125 | public function getFields()
126 | {
127 | return $this->_fields;
128 | }
129 |
130 | /**
131 | * @return \pahanini\restdoc\models\FieldDoc[]
132 | */
133 | public function getSortFields()
134 | {
135 | return $this->_sortFields;
136 | }
137 |
138 | /**
139 | * @return \pahanini\restdoc\models\ControllerDoc
140 | */
141 | public function getParent()
142 | {
143 | return $this->_parent;
144 | }
145 |
146 | /**
147 | * Returns property tag
148 | *
149 | * @param $name
150 | * @return mixed
151 | */
152 | protected function getProperty($name)
153 | {
154 | return isset($this->_properties[$name]) ? $this->_properties[$name] : null;
155 | }
156 |
157 | /**
158 | * Returns scenario
159 | *
160 | * @return array
161 | */
162 | public function getScenario($name)
163 | {
164 | return isset($this->_scenarios[$name]) ? $this->_scenarios[$name] : null;
165 | }
166 |
167 | /**
168 | * Returns scenarios
169 | *
170 | * @return array
171 | */
172 | public function getScenarios()
173 | {
174 | return $this->_scenarios;
175 | }
176 |
177 | /**
178 | * Returns array scenarios having given variable name
179 | *
180 | * @return array
181 | */
182 | public function getScenariosHaving($name)
183 | {
184 | $result = [];
185 | foreach ($this->getScenarios() as $key => $values) {
186 | if (in_array($name, $values)) {
187 | $result[$key] = $values;
188 | }
189 | }
190 | return $result;
191 | }
192 |
193 | /**
194 | * @return bool If model has extra fields
195 | */
196 | public function hasExtraFields()
197 | {
198 | return !empty($this->_extraFields);
199 | }
200 |
201 | /**
202 | * @return bool If model has fields
203 | */
204 | public function hasFields()
205 | {
206 | return !empty($this->_fields);
207 | }
208 |
209 | /**
210 | * @return bool If model has sort fields
211 | */
212 | public function hasSortFields()
213 | {
214 | return !empty($this->_sortFields);
215 | }
216 |
217 | /**
218 | * @param string $name
219 | * @return bool
220 | */
221 | public function hasScenario($name)
222 | {
223 | return isset($this->_scenarios[$name]);
224 | }
225 |
226 | /**
227 | * @param DocBlock $docBlock
228 | */
229 | public function populateProperties(DocBlock $docBlock)
230 | {
231 | foreach ($docBlock->getTagsByName('property') as $tag) {
232 | $name = trim($tag->getVariableName(), '$');
233 | $this->_properties[$name] = $tag;
234 | }
235 | }
236 |
237 | /**
238 | * @todo refactor this code, may be it is a good idea to join fields and extra fields in one array
239 | */
240 | public function prepare()
241 | {
242 | foreach ($this->getFields() as $field) {
243 | $field->setScenarios($this->getScenariosHaving($field->getName()));
244 | }
245 |
246 | foreach ($this->getTagsByName('field') as $tag) {
247 | $name = trim($tag->getVariableName(), '$');
248 | $this->addField($name, $tag->getType(), $tag->getDescription(), $this->getScenariosHaving($name));
249 | }
250 |
251 | foreach ($this->getTagsByName('extraField') as $tag) {
252 | $name = trim($tag->getVariableName(), '$');
253 | $this->addExtraField($name, $tag->getType(), $tag->getDescription());
254 | }
255 |
256 | foreach ($this->getTagsByName('sortField') as $tag) {
257 | $name = trim($tag->getContent(), '$');
258 | $this->addSortField($name);
259 | }
260 |
261 | foreach ($this->getTagsByName('link') as $tag) {
262 | $name = trim($tag->getVariableName(), '$');
263 | $propertyName = $tag->getType() ? trim($tag->getType(), '\\') : $name;
264 | if ($propertyTag = $this->getProperty($propertyName)) {
265 | $this->addField(
266 | $name,
267 | $propertyTag->getType(),
268 | $propertyTag->getDescription(),
269 | array_merge(
270 | $this->getScenariosHaving($name),
271 | $this->getScenariosHaving($propertyName)
272 | )
273 | );
274 | }
275 | }
276 |
277 | foreach ($this->getTagsByName('extraLink') as $tag) {
278 | $name = trim($tag->getVariableName(), '$');
279 | $propertyName = $tag->getType() ? trim($tag->getType(), '\\') : $name;
280 | if ($propertyTag = $this->getProperty($propertyName)) {
281 | $this->addExtraField(
282 | $name,
283 | $propertyTag->getType(),
284 | $propertyTag->getDescription(),
285 | array_merge(
286 | $this->getScenariosHaving($name),
287 | $this->getScenariosHaving($propertyName)
288 | )
289 | );
290 | }
291 | }
292 |
293 | foreach ($this->getTagsByName('ignore') as $key => $tag) {
294 | $name = trim($tag->getVariableName(), '$');
295 | $this->removeField($name);
296 | $this->removeExtraField($name);
297 | }
298 |
299 | foreach ($this->_fields as $field) {
300 | $field->prepare();
301 | }
302 | foreach ($this->_extraFields as $field) {
303 | $field->prepare();
304 | }
305 | foreach ($this->_sortFields as $field) {
306 | $field->prepare();
307 | }
308 | }
309 |
310 | public function setParent(Doc $value)
311 | {
312 | $this->_parent = $value;
313 | }
314 | }
315 |
--------------------------------------------------------------------------------
/models/ModelParser.php:
--------------------------------------------------------------------------------
1 | getObject();
21 |
22 | foreach ($object->scenarios() as $key => $fields) {
23 | $doc->addScenario($key, $fields);
24 | }
25 |
26 | foreach ($object->extraFields() as $key => $value) {
27 | $doc->addExtraField(is_numeric($key) ? $value : $key);
28 | }
29 |
30 | foreach ($object->fields() as $key => $value) {
31 | $doc->addField(is_numeric($key) ? $value : $key);
32 | }
33 |
34 | $this->parseClass($doc);
35 | $this->parseFields($doc, 'fields');
36 | $this->parseFields($doc, 'extraFields');
37 |
38 | return true;
39 | }
40 |
41 | /**
42 | * @param $doc
43 | * @return bool
44 | */
45 | public function parseClass($doc)
46 | {
47 | if (!$docBlock = new DocBlock($this->reflection)) {
48 | return false;
49 | }
50 |
51 | $doc->populateProperties($docBlock);
52 | $doc->populateTags($docBlock);
53 |
54 | if (DocBlockHelper::isInherit($docBlock)) {
55 | $parentParser = $this->getParentParser();
56 | $parentParser->parseClass($doc);
57 | }
58 | }
59 |
60 | /**
61 | * @param \pahanini\restdoc\models\ModelDoc $doc
62 | * @param string $methodName
63 | * @return bool
64 | */
65 | public function parseFields(ModelDoc $doc, $methodName)
66 | {
67 | if (!$docBlock = new DocBlock($this->reflection->getMethod($methodName))) {
68 | return false;
69 | }
70 |
71 | $doc->populateTags($docBlock);
72 |
73 | if (DocBlockHelper::isInherit($docBlock)) {
74 | $parentParser = $this->getParentParser();
75 | $parentParser->parseFields($doc, $methodName);
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/models/ObjectParser.php:
--------------------------------------------------------------------------------
1 | reflection->newInstanceArgs($this->objectArgs);
35 | if ($this->objectConfig) {
36 | $object = Yii::configure($object, $this->objectConfig);
37 | }
38 | return $object;
39 | }
40 |
41 | /**
42 | * Returns object based on reflection
43 | */
44 | public function getObject()
45 | {
46 | if (!$this->_object) {
47 | $this->_object = $this->createObject();
48 | }
49 | return $this->_object;
50 | }
51 |
52 | /**
53 | * @return bool|object|ReflectionDoc
54 | * @throws InvalidConfigException
55 | */
56 | public function getParentParser()
57 | {
58 | if (!$reflection = $this->reflection->getParentClass()) {
59 | return false;
60 | }
61 | return Yii::createObject(
62 | [
63 | 'class' => static::className(),
64 | 'reflection' => $reflection,
65 | ]
66 | );
67 | }
68 |
69 | /**
70 | * Extracts data from reflection's docBlock and adds it to current $doc.
71 | *
72 | * @param $doc
73 | * @return bool $doc If docBlock
74 | * @throws \Exception
75 | */
76 | protected function parseDocBlock($doc)
77 | {
78 | if (!$docBlock = new DocBlock($this->reflection)) {
79 | return false;
80 | }
81 |
82 | if ($docBlock->getTagsByName(self::TAG_PREFIX . 'ignore')) {
83 | throw new \Exception("Ignoring due tag");
84 | }
85 |
86 | if (!$doc->shortDescription && ($value = $docBlock->getShortDescription())) {
87 | $doc->shortDescription = $value;
88 | }
89 |
90 | if (!$doc->longDescription && ($value = $docBlock->getLongDescription()->getContents())) {
91 | $doc->longDescription = $value;
92 | }
93 |
94 | $tags = $docBlock->getTags();
95 |
96 | $offset = strlen(self::TAG_PREFIX);
97 | foreach ($tags as $tag) {
98 | $name = $tag->getName();
99 | if (strpos($name, self::TAG_PREFIX) === 0) {
100 | $doc->addTag(substr($name, $offset), $tag);
101 | }
102 | }
103 |
104 | return (bool)$docBlock->getTagsByName('inherited') || (bool)$docBlock->getTagsByName('inheritdoc');
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/models/Parser.php:
--------------------------------------------------------------------------------
1 | reflection instanceof \Reflector)) {
32 | throw new InvalidConfigException("Reflection property must be set");
33 | }
34 | }
35 |
36 | /**
37 | * @param \pahanini\restdoc\models\Doc $doc
38 | * @return bool Weather parse was successful
39 | */
40 | public function parse(Doc $doc)
41 | {
42 | return false;
43 | }
44 |
45 | /**
46 | * Registers all tags handlers.
47 | */
48 | public static function registerTagHandlers()
49 | {
50 | static $isRegistered;
51 |
52 | if (!$isRegistered) {
53 | $mapping = [
54 | 'query' => '\pahanini\restdoc\tags\QueryTag',
55 | 'field' => '\phpDocumentor\Reflection\DocBlock\Tag\ParamTag',
56 | 'link' => '\phpDocumentor\Reflection\DocBlock\Tag\ParamTag',
57 | 'label' => '\phpDocumentor\Reflection\DocBlock\Tag',
58 | 'extraField' => '\phpDocumentor\Reflection\DocBlock\Tag\ParamTag',
59 | 'extraLink' => '\phpDocumentor\Reflection\DocBlock\Tag\ParamTag',
60 | 'ignore' => '\phpDocumentor\Reflection\DocBlock\Tag\ParamTag',
61 | ];
62 | foreach ($mapping as $suffix => $class) {
63 | $tagName = Doc::TAG_PREFIX . $suffix;
64 | Tag::registerTagHandler($tagName, $class);
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 | tests
13 |
14 |
15 |
16 |
17 | src
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/tags/QueryTag.php:
--------------------------------------------------------------------------------
1 | description, 2);
20 | $tmp = explode('=', array_shift($parts));
21 | if (count($tmp) == 2) {
22 | $this->defaultValue = $tmp[1];
23 | $this->variableName = $tmp[0];
24 | } else {
25 | $this->variableName = $tmp[0];
26 | }
27 | $this->setDescription(join(' ', str_replace("\n", " ", $parts)));
28 |
29 | return $this;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | 'unit',
5 | 'basePath' => dirname(__DIR__),
6 | ];
7 |
--------------------------------------------------------------------------------
/tests/controllers/BrandController.php:
--------------------------------------------------------------------------------
1 | function () {
23 | return 'title';
24 | }
25 | ];
26 | }
27 |
28 | public function scenarios()
29 | {
30 | return [
31 | 'api' => ['title']
32 | ];
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tests/models/NewSpecialOffer.php:
--------------------------------------------------------------------------------
1 | Detail link.
9 | * @restdoc-extraLink $full_name
10 | */
11 | class NewSpecialOffer extends SpecialOffer
12 | {
13 | /**
14 | * @inheritdoc
15 | *
16 | * @restdoc-extraField string $alpha2 Code country. Detail link.
17 | * @restdoc-ignore $ignore
18 | */
19 | public function extraFields()
20 | {
21 | return [
22 | 'alpha2' => function () {
23 | return 'RU';
24 | },
25 | 'full_name' => function () {
26 | return 'full_name';
27 | },
28 | 'ignore' => function () {
29 | return 'ignore';
30 | }
31 | ];
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/models/Product.php:
--------------------------------------------------------------------------------
1 | Details link.
11 | */
12 | class Product extends ActiveRecord
13 | {
14 | /**
15 | * @restdoc-field int $id
16 | * @restdoc-field string $title
17 | * @restdoc-sortField $title
18 | */
19 | public function fields()
20 | {
21 | return [
22 | 'id',
23 | 'title' => function () {
24 | return 'title';
25 | }
26 | ];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/models/SpecialOffer.php:
--------------------------------------------------------------------------------
1 | Detail link.
9 | *
10 | * @restdoc-link comment $note
11 | */
12 | class SpecialOffer extends Product
13 | {
14 | public $comment = 'MyComment';
15 |
16 | /**
17 | * @inheritdoc
18 | *
19 | * @restdoc-field string $title
20 | * @restdoc-link comment $text
21 | * @restdoc-link $comment
22 | * @restdoc-sortField $text
23 | * @restdoc-ignore $is_ignore
24 | */
25 | public function fields()
26 | {
27 | return [
28 | 'id',
29 | 'title' => function () {
30 | return 'title';
31 | },
32 | 'text' => 'Comment',
33 | 'is_ignore'
34 | ];
35 | }
36 |
37 | public function scenarios()
38 | {
39 | return [
40 | 'api-create' => ['id', 'title', 'note', 'is_ignore'],
41 | 'api-update' => ['comment'],
42 | ];
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/modules/api/Module.php:
--------------------------------------------------------------------------------
1 | 'tests\controllers\BrandController',
11 | 'product' => [
12 | 'class' => 'tests\controllers\ProductController',
13 | 'modelClass' => 'tests\models\SpecialOffer'
14 | ],
15 | ];
16 | }
17 |
--------------------------------------------------------------------------------
/tests/modules/api/controllers/CountryController.php:
--------------------------------------------------------------------------------
1 | function () {
25 | return 'title';
26 | }
27 | ];
28 | }
29 |
30 | public function scenarios()
31 | {
32 | return [
33 | 'api' => ['title']
34 | ];
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/unit/components/ContextTest.php:
--------------------------------------------------------------------------------
1 | addFile(Yii::getAlias('@tests/controllers/ProductController.php'));
15 |
16 | $doc = $context->getControllers()['product'];
17 | $this->assertEquals('Product Controller.', $doc->shortDescription);
18 | $this->assertEquals(
19 | 'Product controller allows to manipulate with products. Second line of description.',
20 | str_replace("\n", " ", $doc->longDescription)
21 | );
22 | $this->assertEquals('product', $doc->path);
23 | $this->assertEquals('name', $doc->query[0]->variableName);
24 | }
25 |
26 | public function testBrand()
27 | {
28 | $context = new Context();
29 | $context->addFile(Yii::getAlias('@tests/controllers/BrandController.php'));
30 |
31 | $product = $context->getControllers()['brand'];
32 | $this->assertEquals('Brand Controller.', $product->shortDescription);
33 | $this->assertEquals('brand', $product->path);
34 | }
35 |
36 | public function testSort()
37 | {
38 | $context = new Context();
39 | $context->addDirs(Yii::getAlias('@tests/controllers'));
40 | $context->sortControllers('shortDescription');
41 | $controllers = $context->getControllers();
42 | $this->assertEquals(['brand', 'new-brand', 'product'], array_keys($controllers));
43 | }
44 |
45 | public function testModule()
46 | {
47 | $context = new Context();
48 | $context->addModule('tests\modules\api\Module');
49 |
50 | $controllers = $context->getControllers();
51 | $this->assertEquals(3, count($controllers));
52 |
53 | $this->assertEquals('Manager\'s comment Detail link.', $controllers['product']->model->fields['note']->description);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/tests/unit/models/ControllerParserTest.php:
--------------------------------------------------------------------------------
1 | ControllerParser::className(),
17 | 'reflection' => new \ReflectionClass('\tests\controllers\NewBrandController'),
18 | ]
19 | );
20 | $doc = new ControllerDoc();
21 |
22 | $parser->parse($doc);
23 | $doc->prepare();
24 |
25 | $this->assertEquals('New brand Controller.', $doc->shortDescription);
26 | $this->assertEquals('Brand info.', $doc->longDescription);
27 | $this->assertEquals(2, count($doc->query));
28 | }
29 |
30 |
31 | public function testTags()
32 | {
33 | $parser = Yii::createObject(
34 | [
35 | 'class' => ControllerParser::className(),
36 | 'reflection' => new \ReflectionClass('\tests\controllers\ProductController'),
37 | ]
38 | );
39 | $doc = new ControllerDoc();
40 |
41 | $parser->parseClass($doc);
42 | $doc->prepare();
43 |
44 | $this->assertEquals('name', $doc->query[0]->variableName);
45 | $this->assertEquals('false', $doc->query[0]->defaultValue);
46 | $this->assertTrue($doc->hasLabel('labelA'));
47 | $this->assertFalse($doc->hasLabel('labelB'));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tests/unit/models/ModelParserTest.php:
--------------------------------------------------------------------------------
1 | ModelParser::className(),
17 | 'reflection' => new \ReflectionClass('\tests\models\SpecialOffer'),
18 | ]
19 | );
20 | $doc = new ModelDoc();
21 |
22 | $parser->parse($doc);
23 | $doc->prepare();
24 |
25 | $this->assertTrue($doc->hasFields());
26 | $this->assertFalse($doc->hasExtraFields());
27 | $this->assertTrue($doc->hasSortFields());
28 | }
29 |
30 | public function testInherit()
31 | {
32 | $parser = Yii::createObject(
33 | [
34 | 'class' => ModelParser::className(),
35 | 'reflection' => new \ReflectionClass('\tests\models\NewSpecialOffer'),
36 | ]
37 | );
38 | $doc = new ModelDoc();
39 |
40 | $parser->parse($doc);
41 | $doc->prepare();
42 |
43 | $this->assertEquals(2, count($doc->scenarios));
44 |
45 | $this->assertEquals(2, count($doc->extraFields));
46 | $this->assertEquals('string', $doc->extraFields['alpha2']->type);
47 | $this->assertEquals('Code country. Detail link.', $doc->extraFields['alpha2']->description);
48 | $this->assertEquals('string|null', $doc->extraFields['full_name']->type);
49 | $this->assertEquals('Full name. Detail link.', $doc->extraFields['full_name']->description);
50 | $this->assertArrayNotHasKey('ignore', $doc->extraFields);
51 |
52 | $this->assertEquals(5, count($doc->fields));
53 | $this->assertEquals('int', $doc->fields['id']->type);
54 | $this->assertEquals('string', $doc->fields['title']->type);
55 | $this->assertEquals('string', $doc->fields['comment']->type);
56 | $this->assertArrayNotHasKey('is_ignore', $doc->fields);
57 |
58 | $this->assertEquals('string', $doc->fields['note']->type);
59 | $this->assertEquals('string', $doc->fields['text']->type);
60 |
61 | $this->assertEquals(2, count($doc->sortFields));
62 | $this->assertEquals('title', $doc->sortFields['title']->name);
63 | $this->assertEquals('text', $doc->sortFields['text']->name);
64 |
65 | $this->assertTrue($doc->fields['id']->isInScenario('api-create'));
66 | $this->assertFalse($doc->fields['id']->isInScenario('api-update'));
67 |
68 | $this->assertTrue($doc->fields['text']->isInScenario('api-update'));
69 | $this->assertFalse($doc->fields['text']->isInScenario('api-create'));
70 |
71 | $this->assertTrue($doc->hasFields());
72 | $this->assertTrue($doc->hasExtraFields());
73 | $this->assertTrue($doc->hasSortFields());
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/views/slate.php:
--------------------------------------------------------------------------------
1 | ---
2 | title: API Reference
3 |
4 | language_tabs:
5 | - shell
6 | - ruby
7 | - python
8 |
9 | toc_footers:
10 | - Sign Up for a Developer Key
11 | - Documentation Powered by Slate
12 |
13 | includes:
14 | - errors
15 |
16 | search: true
17 | ---
18 |
19 | # Introduction
20 |
21 | Welcome to the Kittn API! You can use our API to access Kittn API endpoints, which can get information on various cats, kittens, and breeds in our database.
22 |
23 | We have language bindings in Shell, Ruby, and Python! You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.
24 |
25 | This example API documentation page was created with [Slate](http://github.com/tripit/slate). Feel free to edit it and use it as a base for your own API's documentation.
26 |
27 | # Authentication
28 |
29 | > To authorize, use this code:
30 |
31 | ```ruby
32 | require 'kittn'
33 |
34 | api = Kittn::APIClient.authorize!('meowmeowmeow')
35 | ```
36 |
37 | ```python
38 | import kittn
39 |
40 | api = kittn.authorize('meowmeowmeow')
41 | ```
42 |
43 | ```shell
44 | # With shell, you can just pass the correct header with each request
45 | curl "api_endpoint_here"
46 | -H "Authorization: meowmeowmeow"
47 | ```
48 |
49 | > Make sure to replace `meowmeowmeow` with your API key.
50 |
51 | Kittn uses API keys to allow access to the API. You can register a new Kittn API key at our [developer portal](http://example.com/developers).
52 |
53 | Kittn expects for the API key to be included in all API requests to the server in a header that looks like the following:
54 |
55 | `Authorization: meowmeowmeow`
56 |
57 |
60 |
61 |
62 |
63 | #=$controller->shortDesc?>
64 |
65 | =$controller->longDesc?>
66 |
67 |
68 |
69 | # Kittens
70 |
71 | ## Get All Kittens
72 |
73 | ```ruby
74 | require 'kittn'
75 |
76 | api = Kittn::APIClient.authorize!('meowmeowmeow')
77 | api.kittens.get
78 | ```
79 |
80 | ```python
81 | import kittn
82 |
83 | api = kittn.authorize('meowmeowmeow')
84 | api.kittens.get()
85 | ```
86 |
87 | ```shell
88 | curl "http://example.com/api/kittens"
89 | -H "Authorization: meowmeowmeow"
90 | ```
91 |
92 | > The above command returns JSON structured like this:
93 |
94 | ```json
95 | [
96 | {
97 | "id": 1,
98 | "name": "Fluffums",
99 | "breed": "calico",
100 | "fluffiness": 6,
101 | "cuteness": 7
102 | },
103 | {
104 | "id": 2,
105 | "name": "Isis",
106 | "breed": "unknown",
107 | "fluffiness": 5,
108 | "cuteness": 10
109 | }
110 | ]
111 | ```
112 |
113 | This endpoint retrieves all kittens.
114 |
115 | ### HTTP Request
116 |
117 | `GET http://example.com/kittens`
118 |
119 | ### Query Parameters
120 |
121 | Parameter | Default | Description
122 | --------- | ------- | -----------
123 | include_cats | false | If set to true, the result will also include cats.
124 | available | true | If set to false, the result will include kittens that have already been adopted.
125 |
126 |
129 |
130 | ## Get a Specific Kitten
131 |
132 | ```ruby
133 | require 'kittn'
134 |
135 | api = Kittn::APIClient.authorize!('meowmeowmeow')
136 | api.kittens.get(2)
137 | ```
138 |
139 | ```python
140 | import kittn
141 |
142 | api = kittn.authorize('meowmeowmeow')
143 | api.kittens.get(2)
144 | ```
145 |
146 | ```shell
147 | curl "http://example.com/api/kittens/3"
148 | -H "Authorization: meowmeowmeow"
149 | ```
150 |
151 | > The above command returns JSON structured like this:
152 |
153 | ```json
154 | {
155 | "id": 2,
156 | "name": "Isis",
157 | "breed": "unknown",
158 | "fluffiness": 5,
159 | "cuteness": 10
160 | }
161 | ```
162 |
163 | This endpoint retrieves a specific kitten.
164 |
165 |
166 |
167 | ### HTTP Request
168 |
169 | `GET http://example.com/kittens/`
170 |
171 | ### URL Parameters
172 |
173 | Parameter | Description
174 | --------- | -----------
175 | ID | The ID of the cat to retrieve
176 |
177 |
--------------------------------------------------------------------------------