diff --git a/.env b/.env
deleted file mode 100644
index fd57cda..0000000
--- a/.env
+++ /dev/null
@@ -1,21 +0,0 @@
-PLUGIN_NAME=plugin
-BASE_PATH=/opt/projects/wp-oop/plugin
-PROJECT_MOUNT_PATH=/var/www/html/wp-content/plugins/plugin
-DOCROOT_PATH=/var/www/html
-BUILD_ROOT_PATH=/app/
-PROJECT_NAME=me_plugin
-
-PHP_BUILD_VERSION=7.1
-PHP_TEST_VERSION=7.4
-
-DB_ROOT_PASSWORD=am@n0fData
-DB_NAME=wordpress
-DB_USER_NAME=wordpress
-DB_USER_PASSWORD=UDG@F!oy8g37921f
-
-WP_DOMAIN=plugin.myhost
-WP_TITLE=plugin Test
-
-ADMIN_USER=admin
-ADMIN_PASS=admin
-ADMIN_EMAIL=me@my.com
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
new file mode 100644
index 0000000..d4fe57c
--- /dev/null
+++ b/.github/workflows/continuous-integration.yml
@@ -0,0 +1,34 @@
+name: Continuous Integration
+on: [push, pull_request]
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ php-versions: ['7.1', '7.2', '7.3', '7.4']
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-versions }}
+
+ - name: Analysing source code
+ run: find ./src/ ./inc/ ./tests/ -type f -name '*.php' -print0 | xargs -0 -L 1 -P 4 -- php -l
+
+ - name: Validate composer.json and composer.lock
+ run: composer validate
+
+ - name: Install dependencies
+ run: composer install --prefer-dist --no-progress --no-suggest
+
+ - name: PhpUnit
+ run: ./vendor/bin/phpunit
+
+ - name: Psalm
+ run: ./vendor/bin/psalm --show-info=false --threads=8 --diff --diff-methods
+
+ - name: PHPCS
+ run: ./vendor/bin/phpcs -s --report-source --runtime-set ignore_warnings_on_exit 1
diff --git a/.gitignore b/.gitignore
index 5c0eb49..f72d218 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@
/.idea/codeStyles/
/.idea/inspectionProfiles/
/.idea/misc.xml
+/.env
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 0000000..8327928
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,11 @@
+
+
+
+
+ mysql.8
+ true
+ com.mysql.cj.jdbc.Driver
+ jdbc:mysql://plugin.myhost:3306/wordpress
+
+
+
\ No newline at end of file
diff --git a/.idea/deployment.xml b/.idea/deployment.xml
new file mode 100644
index 0000000..e570866
--- /dev/null
+++ b/.idea/deployment.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/php-test-framework.xml b/.idea/php-test-framework.xml
new file mode 100644
index 0000000..096cfc5
--- /dev/null
+++ b/.idea/php-test-framework.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/php.xml b/.idea/php.xml
index 5681ecc..de1e2c9 100644
--- a/.idea/php.xml
+++ b/.idea/php.xml
@@ -3,11 +3,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -16,11 +80,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+ /usr/local/etc/php/php.ini
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/usr/local/etc/php/php.ini
@@ -69,7 +194,8 @@
-
+
+
\ No newline at end of file
diff --git a/.idea/phpunit.xml b/.idea/phpunit.xml
new file mode 100644
index 0000000..5ba64b9
--- /dev/null
+++ b/.idea/phpunit.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/plugin.iml b/.idea/plugin.iml
index 2d6ad0e..b5be0b4 100644
--- a/.idea/plugin.iml
+++ b/.idea/plugin.iml
@@ -2,7 +2,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/remote-mappings.xml b/.idea/remote-mappings.xml
index d9f6e9d..3ca66a6 100644
--- a/.idea/remote-mappings.xml
+++ b/.idea/remote-mappings.xml
@@ -10,6 +10,13 @@
+
+
+
+
+
+
+
diff --git a/.idea/webServers.xml b/.idea/webServers.xml
new file mode 100644
index 0000000..c0d65dd
--- /dev/null
+++ b/.idea/webServers.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..942d8be
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,8 @@
+# Change log
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/)
+and this project adheres to [Semantic Versioning](http://semver.org/).
+
+## [[*next-version*]] - YYYY-MM-DD
+Initial version.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/README.md b/README.md
index 9fd18fc..7318f33 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,26 @@ Use this project as a starter for your modular WordPress plugin!
a Docker image containing a complete WordPress installation with your
plugin and all pre-requisites.
+- **PHPStorm** - Configuration for integrations of arguably the best PHP
+ IDE out there, including:
+
+ * **Database client** - View and manipulate the database from PHPStorm.
+ * **Composer** - Install and manage PHP dependencies on the correct version of PHP without leaving the IDE.
+ * **PHPUnit** - Run tests and get reports directly in PHPStorm.
+ * **xDebug** - Set breakpoints and inspect your code in PHPStorm.
+ * **Code coverage** - See what has not been tested yet in a friendly GUI.
+
+- **Static Code Analysis** - Maintain a consistent coding style, and catch problems early.
+
+ * **[Psalm][]** - Inspects your code for problems.
+ * **[PHPCS][]** - Checks your code style. [PHPCBF][] can fix some of them automatically.
+
+- **Continuous Integration** - Automatically verify that all contributions comply with
+ project standards with [GitHub Actions][].
+
+- **Modularity** - Keep concerns separated into modules, which can be freely
+ moved out of the package at any time thanks to the [`composer-merge-plugin`][].
+
### Usage
#### Getting Started
@@ -49,10 +69,12 @@ Use Composer to bootstrap your project.
to the WordPress database. Change these if you want to secure your deployed application.
* `WP_DOMAIN`* - The domain name of the WordPress application, which contains your plugin.
Among other things, used to set up the local dev image. Corresponds to the alias
- used in the `hosts` file, if local.
+ used in the `hosts` file, if local. This value is also used in the PHPStorm's DB integration.
+ If this value is changed, PHPStorm's configuration must be updated.
* `WP_TITLE`* - The title of the WordPress application, which contains your plugin.
- No quotes, because Docker does not expand variables in this file. Used during automatic
- installation of WordPress inside the local dev image.
+ No quotes, because Docker does not expand variables in this file. It is used during automatic
+ installation of WordPress inside the local dev image. This value is also used in the
+ PHPStorm's DB integration. If this value is changed, PHPStorm's configuration must be updated.
* `ADMIN_USER`* - This and other `ADMIN_*` variables are used to determine WordPress admin
details during automatic WordPress installation with [WP-CLI][].
@@ -83,6 +105,17 @@ Use Composer to bootstrap your project.
the plugin _does_ actually require other plugins, but they should not be shipped with
the plugin. Otherwise, completely Composer-managed WordPress installations will not
automatically install other required plugins.
+
+ - Module `composer.json`:
+ This bootstrap uses the awesome [`composer-merge-plugin`][] to keep module depedencies
+ together with modules. This allows keeping track of which dependencies belong to which
+ modules, detect dependency incompatibilities, and moving modules out of the package
+ into packages of their own when necessary.
+
+ Modules can be installed from other packages, or included in the package. In the latter
+ case, they should be added to the directory `modules.local`. One such module, the `core`
+ module of the plugin, is already included in the package. Its `composer.json` should
+ also be personalized, just like the `composer.json` of this package.
3. Spin up the dev environment
@@ -102,7 +135,7 @@ Use Composer to bootstrap your project.
the value of `WP_DOMAIN` from the `.env` file. The IP would be Docker machine's IP
address. On Linux, this is the same as [your machine's IP address][] on the local
network, and usually `127.0.0.1` (localhost) works. If you are using Docker
- Machine (in a non-Linux environment), use [`docker-machine ip`] to find it.
+ Machine (in a non-Linux environment), use `docker-machine ip` to find it.
Now you should be able to visit that domain, and see the website. The admin username
and password are both `admin` by default, and are determined by the `ADMIN_USER`
@@ -110,28 +143,170 @@ Use Composer to bootstrap your project.
installed and active, and no other plugins should be installed. If this is not
the case, inspect the output you got from `docker-compose up`.
-#### Updating dependencies
+#### Updating Dependencies
Composer is installed into the `build` service's image. To run composer commands,
use `docker-compose run`. For example, to update dependencies you can run the following:
```bash
-docker-compose run --rm build composer update
+docker-compose run --rm build composer update
```
-If you use PHPStorm, you can use the [composer integration][], as the project
-is already configured for this.
+~~If you use PHPStorm, you can use the [composer integration][], as the project
+is already configured for this.~~
+
+Currently, it is not possible to use PHPStorm's [composer integration][] because
+managing local modules with the [`composer-merge-plugin`][] require running
+`composer update --lock` instead of simply `composer update`. This is currently
+unsupported by PHPStorm, but a [feature request][WI-54242] has been submitted.
+
+**Do not run `composer update` for the modules' `composer.json` file!**
+All Composer operations must be performed on the root package's `composer.json` file.
Any changes to the project folder are immediately reflected in the dev environment,
and this includes the `vendor` folder and `composer.lock` file. This is because
the project's folder is mounted into the correct place in the WordPress container.
+
+#### Adding Modules
+This boilerplate promotes modularity, and supports [Dhii modules][] out of the box.
+Any such module that exposes a [`ModuleInterface`][] implementation can be loaded,
+allowing it to run in the application, and making its services available.
+
+The list of modules returned by `inc/modules.php` is the authoritative source
+of modules in the application. Because it is PHP code, modules can be loaded
+in any required way, including:
+
+- Simple instantiation of a module class that will be autoloaded.
+
+ If your module class is on one of the autoload paths registered with e.g. Composer,
+ you can just instantiate it as you would any other class. This is a
+ very quick and simple way to load some modules.
+
+
+- Usage of a factory class or file.
+
+ In order to make modules de-coupled from the application, but to still be able
+ to provide dependencies from the application to the module, it is sometimes
+ desirable to use a "padding" between the application and the module's
+ initialization. In this project, as well as in some others, we use a
+ `module.php` file. This file returns a function which, given some parameters
+ like the root project path, will return a `ModuleInterface` instance.
+ Another approach could be to use a named constructor, or even a dedicated
+ factory class.
+
+- Scanning certain paths.
+
+ If modules do not conflict in any way, the module load order may be irrelevant.
+ In this case, it is possible to auto-discover modules by, for example, scanning
+ certain folders for some entrypoints or config files. Implement whatever
+ auto-discovery mechanism you wish, as long as the module instances
+ end up in the authoritative list.
+
+##### External Modules
+To add a module from another package, require that package with Composer
+and add the `ModuleInterface` instance to the list.
+
+##### Local Modules
+To add a local module, add the module to the `modules.local` folder,
+and do the same as for any other module. Local modules may also declare their own
+dependencies by adding a `composer.json` file to their root folder.
+These files will be picked up by Composer when updating dependencies in
+the project root, thanks to the [`composer-merge-plugin`][], provided
+that `composer update --lock` is run before `composer update`. This is
+a great way to separate module dependencies from other dependencies.
+Consult that Composer plugin's documentation for more information.
+
+#### Testing Code
+This bootstrap includes PHPUnit. It is already configured, and you can test
+that it's working by running the sample tests:
+
+```bash
+docker-compose run --rm build vendor/bin/phpunit
+```
+
+If you use PHPStorm, you can use its PHPUnit integration: right-click on any
+test or folder inside the `tests` directory, and choose "Run". This will do
+the same as the above command. Because the `build` service is used for tests,
+they will be run with its PHP version, which should correspond to your project's
+minimal requirements.
+
+#### Debugging
+The bootstrap includes xDebug in the `test` service of the Docker environment,
+and PHPStorm configuration. To use it, right click on any test or folder within
+the `tests` directory, and choose "Debug". This will run the tests with xDebug
+enabled. If you receive the error about [`xdebug.remote_host`][] being set
+incorrectly and suggesting to fix the error, fix it by setting that variable
+to [your machine's IP address][] on the local network in the window that
+pops up. After this, breakpoints in any code reachable by PHPUnit tests,
+including the code of tests themselves, will cause execution to pause,
+allowing inspection of code.
+
+At this time, inspection of code that runs _during a web request_ is not available.
+
+#### Database UI
+This bootstrap includes [phpMyAdmin][], which provides a GUI for your database.
+To start working with it, you must first bring up the related container,
+as it is not brought up together with the dev environment:
+
+```bash
+docker-compose up db_admin
+```
+
+You can now head over to the application's domain, defined usually by the
+`WP_DOMAIN` value from the `.env` file, but access it on port `1234`, e.g.
+`http://plugin.myhost:1234`. The username is `root`, and password is the one
+specified by the `DB_ROOT_PASSWORD` variable in the `.env` file.
+
+This bootstrap comes ready with configuration for PHPStorm's [database integration][].
+With it, it's possible to completely avoid bringing up the `db_admin` service.
+To use it, its settings must be up to date from the value of `DB_USER_PASSWORD`.
+Using it is highly recommended, as it is an integrated DB client, and will
+provide assistance during coding.
+
+#### Static Analysis
+- **Psalm**
+
+ Run Psalm in project root:
+
+ ```bash
+ docker-compose run --rm test vendor/bin/psalm
+ ```
+
+ Will also be run automatically on CI.
+
+- **PHPCS**
+
+ Run PHPCS/PHPCBF in project root:
+
+ ```bash
+ docker-compose run --rm test vendor/bin/phpcs -s --report-source --runtime-set ignore_warnings_on_exit 1
+ docker-compose run --rm test vendor/bin/phpcbf
+ ```
+
+ By default, uses [PSR-12][] and some rules from the [Slevomat Coding Standard][].
+
+ Will also be run automatically on CI.
+
[Docker Machine]: https://github.com/docker/machine
[WP-CLI]: https://wp-cli.org/
+[phpMyAdmin]: https://www.phpmyadmin.net/
+[PSR-12]: https://www.php-fig.org/psr/psr-12/
+[Slevomat Coding Standard]: https://github.com/slevomat/coding-standard
+[Psalm]: https://psalm.dev/
+[PHPCS]: https://github.com/squizlabs/PHP_CodeSniffer
+[PHPCBF]: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Fixing-Errors-Automatically
+[GitHub Actions]: https://github.com/features/actions
+[Dhii modules]: https://github.com/Dhii/module-interface
[hosts file]: https://www.howtogeek.com/howto/27350/beginner-geek-how-to-edit-your-hosts-file/
[your machine's IP address]: https://www.whatismybrowser.com/detect/what-is-my-local-ip-address
[composer integration]: https://www.jetbrains.com/help/phpstorm/using-the-composer-dependency-manager.html#updating-dependencies
+[database integration]: https://www.jetbrains.com/help/phpstorm/configuring-database-connections.html
[`container_name`]: https://docs.docker.com/compose/compose-file/#container_name
+[`composer-merge-plugin`]: https://github.com/wikimedia/composer-merge-plugin
[`php`]: https://hub.docker.com/_/php
[`wordpress`]: https://hub.docker.com/_/wordpress
[`docker-machine start`]: https://docs.docker.com/machine/reference/start/]
[`docker-machine env`]: https://docs.docker.com/machine/reference/env/
+[`xdebug.remote_host`]: https://xdebug.org/docs/all_settings#remote_host
+[`ModuleInterface`]: https://github.com/Dhii/module-interface/blob/develop/src/ModuleInterface.php
+[WI-54242]: https://youtrack.jetbrains.com/issue/WI-54242
diff --git a/composer.lock b/composer.lock
index 70d245f..347e234 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,3631 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "63186eb28c8ea0b5620ecb02c48114a6",
- "packages": [],
+ "content-hash": "a7fea5668b70082f4530e82bd66b4fc3",
+ "packages": [
+ {
+ "name": "amphp/amp",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/amp.git",
+ "reference": "e2c63c83eb8394306ca39a0790a22aebe2248da1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/amp/zipball/e2c63c83eb8394306ca39a0790a22aebe2248da1",
+ "reference": "e2c63c83eb8394306ca39a0790a22aebe2248da1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7"
+ },
+ "require-dev": {
+ "amphp/php-cs-fixer-config": "dev-master",
+ "amphp/phpunit-util": "^1",
+ "ext-json": "*",
+ "jetbrains/phpstorm-stubs": "^2019.3",
+ "phpunit/phpunit": "^6.0.9 | ^7",
+ "react/promise": "^2",
+ "vimeo/psalm": "^3.11@dev"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Amp\\": "lib"
+ },
+ "files": [
+ "lib/functions.php",
+ "lib/Internal/functions.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Daniel Lowrey",
+ "email": "rdlowrey@php.net"
+ },
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ },
+ {
+ "name": "Bob Weinand",
+ "email": "bobwei9@hotmail.com"
+ },
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ }
+ ],
+ "description": "A non-blocking concurrency framework for PHP applications.",
+ "homepage": "http://amphp.org/amp",
+ "keywords": [
+ "async",
+ "asynchronous",
+ "awaitable",
+ "concurrency",
+ "event",
+ "event-loop",
+ "future",
+ "non-blocking",
+ "promise"
+ ],
+ "time": "2020-05-06T16:57:29+00:00"
+ },
+ {
+ "name": "amphp/byte-stream",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/amphp/byte-stream.git",
+ "reference": "f0c20cf598a958ba2aa8c6e5a71c697d652c7088"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/amphp/byte-stream/zipball/f0c20cf598a958ba2aa8c6e5a71c697d652c7088",
+ "reference": "f0c20cf598a958ba2aa8c6e5a71c697d652c7088",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^2",
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "amphp/php-cs-fixer-config": "dev-master",
+ "amphp/phpunit-util": "^1.4",
+ "friendsofphp/php-cs-fixer": "^2.3",
+ "jetbrains/phpstorm-stubs": "^2019.3",
+ "phpunit/phpunit": "^6 || ^7 || ^8",
+ "psalm/phar": "^3.11.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Amp\\ByteStream\\": "lib"
+ },
+ "files": [
+ "lib/functions.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Aaron Piotrowski",
+ "email": "aaron@trowski.com"
+ },
+ {
+ "name": "Niklas Keller",
+ "email": "me@kelunik.com"
+ }
+ ],
+ "description": "A stream abstraction to make working with non-blocking I/O simple.",
+ "homepage": "http://amphp.org/byte-stream",
+ "keywords": [
+ "amp",
+ "amphp",
+ "async",
+ "io",
+ "non-blocking",
+ "stream"
+ ],
+ "time": "2020-06-29T18:35:05+00:00"
+ },
+ {
+ "name": "composer/semver",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/semver.git",
+ "reference": "00915994bb1de62e750ae279669c9c5a57379957"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/semver/zipball/00915994bb1de62e750ae279669c9c5a57379957",
+ "reference": "00915994bb1de62e750ae279669c9c5a57379957",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.2 || ^7.0 || ^8.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^0.12.19",
+ "symfony/phpunit-bridge": "^4.2 || ^5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Semver\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ },
+ {
+ "name": "Rob Bast",
+ "email": "rob.bast@gmail.com",
+ "homepage": "http://robbast.nl"
+ }
+ ],
+ "description": "Semver library that offers utilities, version constraint parsing and validation.",
+ "keywords": [
+ "semantic",
+ "semver",
+ "validation",
+ "versioning"
+ ],
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-05-31T11:44:06+00:00"
+ },
+ {
+ "name": "composer/xdebug-handler",
+ "version": "1.4.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/xdebug-handler.git",
+ "reference": "fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51",
+ "reference": "fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.2 || ^7.0 || ^8.0",
+ "psr/log": "^1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Composer\\XdebugHandler\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "John Stevenson",
+ "email": "john-stevenson@blueyonder.co.uk"
+ }
+ ],
+ "description": "Restarts a process without Xdebug.",
+ "keywords": [
+ "Xdebug",
+ "performance"
+ ],
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-06-04T11:16:35+00:00"
+ },
+ {
+ "name": "container-interop/service-provider",
+ "version": "v0.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/container-interop/service-provider.git",
+ "reference": "4969b9e49460690b7430b3f1a87cab07be61418a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/container-interop/service-provider/zipball/4969b9e49460690b7430b3f1a87cab07be61418a",
+ "reference": "4969b9e49460690b7430b3f1a87cab07be61418a",
+ "shasum": ""
+ },
+ "require": {
+ "psr/container": "^1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Interop\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Promoting container interoperability through standard service providers",
+ "homepage": "https://github.com/container-interop/service-provider",
+ "time": "2017-09-20T14:13:36+00:00"
+ },
+ {
+ "name": "dealerdirect/phpcodesniffer-composer-installer",
+ "version": "v0.7.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git",
+ "reference": "e8d808670b8f882188368faaf1144448c169c0b7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/e8d808670b8f882188368faaf1144448c169c0b7",
+ "reference": "e8d808670b8f882188368faaf1144448c169c0b7",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "^1.0 || ^2.0",
+ "php": ">=5.3",
+ "squizlabs/php_codesniffer": "^2 || ^3 || 4.0.x-dev"
+ },
+ "require-dev": {
+ "composer/composer": "*",
+ "phpcompatibility/php-compatibility": "^9.0",
+ "sensiolabs/security-checker": "^4.1.0"
+ },
+ "type": "composer-plugin",
+ "extra": {
+ "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
+ },
+ "autoload": {
+ "psr-4": {
+ "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Franck Nijhof",
+ "email": "franck.nijhof@dealerdirect.com",
+ "homepage": "http://www.frenck.nl",
+ "role": "Developer / IT Manager"
+ }
+ ],
+ "description": "PHP_CodeSniffer Standards Composer Installer Plugin",
+ "homepage": "http://www.dealerdirect.com",
+ "keywords": [
+ "PHPCodeSniffer",
+ "PHP_CodeSniffer",
+ "code quality",
+ "codesniffer",
+ "composer",
+ "installer",
+ "phpcs",
+ "plugin",
+ "qa",
+ "quality",
+ "standard",
+ "standards",
+ "style guide",
+ "stylecheck",
+ "tests"
+ ],
+ "time": "2020-06-25T14:57:39+00:00"
+ },
+ {
+ "name": "dhii/containers",
+ "version": "dev-develop",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Dhii/containers.git",
+ "reference": "3dd6e407e86cf19f7a40989eeb802cf751082902"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Dhii/containers/zipball/3dd6e407e86cf19f7a40989eeb802cf751082902",
+ "reference": "3dd6e407e86cf19f7a40989eeb802cf751082902",
+ "shasum": ""
+ },
+ "require": {
+ "container-interop/service-provider": "^0.4",
+ "dhii/data-container-interface": "^0.2",
+ "php": "^7.0 | ^8.0"
+ },
+ "require-dev": {
+ "gmazzap/andrew": "^1.1",
+ "phpunit/phpunit": "^6",
+ "psr/container": "^1.0",
+ "slevomat/coding-standard": "~4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-develop": "0.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Dhii\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Dhii Team",
+ "email": "development@dhii.co"
+ }
+ ],
+ "description": "A selection of PSR-11 containers for utility, simplicity, and ease.",
+ "keywords": [
+ "PSR-11",
+ "container"
+ ],
+ "time": "2020-03-18T17:36:56+00:00"
+ },
+ {
+ "name": "dhii/data-container-interface",
+ "version": "dev-develop",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Dhii/data-container-interface.git",
+ "reference": "f3b36758e236784a8c70c34e149f26982b2539d7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Dhii/data-container-interface/zipball/f3b36758e236784a8c70c34e149f26982b2539d7",
+ "reference": "f3b36758e236784a8c70c34e149f26982b2539d7",
+ "shasum": ""
+ },
+ "require": {
+ "dhii/exception-interface": "^0.1 | ^0.2",
+ "dhii/factory-interface": "^0.1-alpha1",
+ "php": "^5.3 | ^7.0",
+ "psr/container": "^1.0"
+ },
+ "require-dev": {
+ "codeclimate/php-test-reporter": "<=0.3.2",
+ "dhii/php-cs-fixer-config": "dev-php-5.3",
+ "dhii/stringable-interface": "^0.1",
+ "phpunit/phpunit": "^4.8",
+ "ptrofimov/xpmock": "^1.1"
+ },
+ "suggest": {
+ "dhii/stringable-interface": "To be able to pass Stringables as keys"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-develop": "0.2.1-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Dhii\\Data\\Container\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Dhii Team",
+ "email": "development@dhii.co"
+ }
+ ],
+ "description": "Interfaces for working with data containers",
+ "abandoned": "dhii/collections-interface",
+ "time": "2020-03-11T12:42:43+00:00"
+ },
+ {
+ "name": "dhii/exception-interface",
+ "version": "v0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Dhii/exception-interface.git",
+ "reference": "b69feebf7cb2879cd43977a03342e2393b73f7fb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Dhii/exception-interface/zipball/b69feebf7cb2879cd43977a03342e2393b73f7fb",
+ "reference": "b69feebf7cb2879cd43977a03342e2393b73f7fb",
+ "shasum": ""
+ },
+ "require": {
+ "dhii/stringable-interface": "^0.1",
+ "php": "^5.3 | ^7.0"
+ },
+ "require-dev": {
+ "codeclimate/php-test-reporter": "<=0.3.2",
+ "dhii/php-cs-fixer-config": "dev-php-5.3",
+ "phpunit/phpunit": "^4.8",
+ "ptrofimov/xpmock": "^1.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-develop": "0.2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Dhii\\Exception\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Dhii Team",
+ "email": "development@dhii.co"
+ }
+ ],
+ "description": "Interfaces for most common exceptions",
+ "time": "2018-08-29T10:42:04+00:00"
+ },
+ {
+ "name": "dhii/factory-interface",
+ "version": "v0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Dhii/factory-interface.git",
+ "reference": "b8d217aec8838e64ccaa770cb03dc164bf6f0515"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Dhii/factory-interface/zipball/b8d217aec8838e64ccaa770cb03dc164bf6f0515",
+ "reference": "b8d217aec8838e64ccaa770cb03dc164bf6f0515",
+ "shasum": ""
+ },
+ "require": {
+ "dhii/exception-interface": "^0.1|^0.2",
+ "php": "^5.3 | ^7.0"
+ },
+ "require-dev": {
+ "codeclimate/php-test-reporter": "<=0.3.2",
+ "dhii/php-cs-fixer-config": "dev-php-5.3",
+ "dhii/stringable-interface": "^0.1",
+ "phpunit/phpunit": "^4.8",
+ "psr/container": "^1.0",
+ "ptrofimov/xpmock": "^1.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-develop": "0.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Dhii\\Factory\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Dhii Team",
+ "email": "development@dhii.co"
+ }
+ ],
+ "description": "Interfaces for working with factories.",
+ "time": "2018-08-29T11:15:09+00:00"
+ },
+ {
+ "name": "dhii/human-readable-interface",
+ "version": "dev-develop",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Dhii/human-readable-interface.git",
+ "reference": "a892c35394eebc627ff81f5112b09ab9da727754"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Dhii/human-readable-interface/zipball/a892c35394eebc627ff81f5112b09ab9da727754",
+ "reference": "a892c35394eebc627ff81f5112b09ab9da727754",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3 | ^7.0"
+ },
+ "require-dev": {
+ "codeclimate/php-test-reporter": "<=0.3.2",
+ "dhii/php-cs-fixer-config": "dev-php-5.3",
+ "dhii/stringable-interface": "^0.1.0",
+ "phpunit/phpunit": "^4.8",
+ "ptrofimov/xpmock": "^1.1"
+ },
+ "suggest": {
+ "dhii/i18n-interface": "For internationalizing and translating human readable strings."
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-develop": "0.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Dhii\\Util\\String\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Dhii Team",
+ "email": "development@dhii.co"
+ }
+ ],
+ "description": "Interfaces for human readable string interoperation.",
+ "time": "2020-05-14T18:39:55+00:00"
+ },
+ {
+ "name": "dhii/module-interface",
+ "version": "dev-develop",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Dhii/module-interface.git",
+ "reference": "cb2eaaac0fa4bd4a82bc2b38c10e3a794ce32d52"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Dhii/module-interface/zipball/cb2eaaac0fa4bd4a82bc2b38c10e3a794ce32d52",
+ "reference": "cb2eaaac0fa4bd4a82bc2b38c10e3a794ce32d52",
+ "shasum": ""
+ },
+ "require": {
+ "container-interop/service-provider": "^0.4",
+ "php": "^7.1",
+ "psr/container": "^1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0 | ^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-develop": "0.2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Dhii\\Modular\\Module\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Dhii Team",
+ "email": "development@dhii.co"
+ }
+ ],
+ "description": "Interfaces for modules",
+ "time": "2020-04-10T14:27:05+00:00"
+ },
+ {
+ "name": "dhii/package-interface",
+ "version": "dev-develop",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Dhii/package-interface.git",
+ "reference": "8169f4f08d7709ba850d8a2befeff5f1d208ca54"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Dhii/package-interface/zipball/8169f4f08d7709ba850d8a2befeff5f1d208ca54",
+ "reference": "8169f4f08d7709ba850d8a2befeff5f1d208ca54",
+ "shasum": ""
+ },
+ "require": {
+ "dhii/stringable-interface": "^0.1",
+ "dhii/validation-interface": "^0.3-alpha1",
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.0 | ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-develop": "0.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Dhii\\Package\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Anton Ukhanev",
+ "email": "xedin.unknown@gmail.com"
+ }
+ ],
+ "description": "Interfaces for package-related interop",
+ "time": "2020-05-14T19:54:39+00:00"
+ },
+ {
+ "name": "dhii/stringable-interface",
+ "version": "v0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Dhii/stringable-interface.git",
+ "reference": "b6653905eef2ebf377749feb80a6d18abbe913ef"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Dhii/stringable-interface/zipball/b6653905eef2ebf377749feb80a6d18abbe913ef",
+ "reference": "b6653905eef2ebf377749feb80a6d18abbe913ef",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3 | ^7.0"
+ },
+ "require-dev": {
+ "codeclimate/php-test-reporter": "<=0.3.2",
+ "dhii/php-cs-fixer-config": "dev-php-5.3",
+ "phpunit/phpunit": "^4.8",
+ "ptrofimov/xpmock": "^1.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Dhii\\Util\\String\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Dhii Team",
+ "email": "development@dhii.co"
+ }
+ ],
+ "description": "Interoperability interface for objects that can be cast to string",
+ "time": "2017-01-23T15:08:20+00:00"
+ },
+ {
+ "name": "dhii/validation-interface",
+ "version": "dev-develop",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Dhii/validation-interface.git",
+ "reference": "f5c15606b1387df2381134e4fc6e1971cbc284a0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Dhii/validation-interface/zipball/f5c15606b1387df2381134e4fc6e1971cbc284a0",
+ "reference": "f5c15606b1387df2381134e4fc6e1971cbc284a0",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "dhii/stringable-interface": "^0.1",
+ "phpunit/phpunit": "^7.0 | ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-develop": "0.3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Dhii\\Validation\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Anton Ukhanev",
+ "email": "xedin.unknown@gmail.com"
+ }
+ ],
+ "description": "A base interface for validators",
+ "time": "2020-05-14T00:22:48+00:00"
+ },
+ {
+ "name": "dhii/versions",
+ "version": "dev-develop",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Dhii/versions.git",
+ "reference": "40933debe1d77f26a381a47abfb256e0e974e439"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Dhii/versions/zipball/40933debe1d77f26a381a47abfb256e0e974e439",
+ "reference": "40933debe1d77f26a381a47abfb256e0e974e439",
+ "shasum": ""
+ },
+ "require": {
+ "dhii/package-interface": "^0.1",
+ "dhii/stringable-interface": "^0.1",
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.0 | ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-develop": "0.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Dhii\\Versions\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Anton Ukhanev",
+ "email": "xedin.unknown@gmail.com"
+ }
+ ],
+ "description": "Implementation for dealing with SemVer-compliant versions",
+ "time": "2020-05-14T19:25:38+00:00"
+ },
+ {
+ "name": "doctrine/instantiator",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/instantiator.git",
+ "reference": "3e7a22aed197e9333cc929e7f6b4300bdae91fcc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/3e7a22aed197e9333cc929e7f6b4300bdae91fcc",
+ "reference": "3e7a22aed197e9333cc929e7f6b4300bdae91fcc",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^6.0",
+ "ext-pdo": "*",
+ "ext-phar": "*",
+ "phpbench/phpbench": "^0.13",
+ "phpstan/phpstan-phpunit": "^0.11",
+ "phpstan/phpstan-shim": "^0.11",
+ "phpunit/phpunit": "^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com",
+ "homepage": "http://ocramius.github.com/"
+ }
+ ],
+ "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
+ "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
+ "keywords": [
+ "constructor",
+ "instantiate"
+ ],
+ "funding": [
+ {
+ "url": "https://www.doctrine-project.org/sponsorship.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.patreon.com/phpdoctrine",
+ "type": "patreon"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-06-15T18:51:04+00:00"
+ },
+ {
+ "name": "felixfbecker/advanced-json-rpc",
+ "version": "v3.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git",
+ "reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/0ed363f8de17d284d479ec813c9ad3f6834b5c40",
+ "reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40",
+ "shasum": ""
+ },
+ "require": {
+ "netresearch/jsonmapper": "^1.0 || ^2.0",
+ "php": ">=7.0",
+ "phpdocumentor/reflection-docblock": "^4.0.0 || ^5.0.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "AdvancedJsonRpc\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "ISC"
+ ],
+ "authors": [
+ {
+ "name": "Felix Becker",
+ "email": "felix.b@outlook.com"
+ }
+ ],
+ "description": "A more advanced JSONRPC implementation",
+ "time": "2020-03-11T15:21:41+00:00"
+ },
+ {
+ "name": "felixfbecker/language-server-protocol",
+ "version": "v1.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/felixfbecker/php-language-server-protocol.git",
+ "reference": "378801f6139bb74ac215d81cca1272af61df9a9f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/378801f6139bb74ac215d81cca1272af61df9a9f",
+ "reference": "378801f6139bb74ac215d81cca1272af61df9a9f",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "*",
+ "phpunit/phpunit": "^6.3",
+ "squizlabs/php_codesniffer": "^3.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "LanguageServerProtocol\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "ISC"
+ ],
+ "authors": [
+ {
+ "name": "Felix Becker",
+ "email": "felix.b@outlook.com"
+ }
+ ],
+ "description": "PHP classes for the Language Server Protocol",
+ "keywords": [
+ "language",
+ "microsoft",
+ "php",
+ "server"
+ ],
+ "time": "2019-06-23T21:03:50+00:00"
+ },
+ {
+ "name": "johnpbloch/wordpress-core",
+ "version": "5.4.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/johnpbloch/wordpress-core.git",
+ "reference": "3e67d8b6ee6c11e8ce404da4627117fb7fbf9266"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/johnpbloch/wordpress-core/zipball/3e67d8b6ee6c11e8ce404da4627117fb7fbf9266",
+ "reference": "3e67d8b6ee6c11e8ce404da4627117fb7fbf9266",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "php": ">=5.6.20"
+ },
+ "provide": {
+ "wordpress/core-implementation": "5.4.2"
+ },
+ "type": "wordpress-core",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "GPL-2.0-or-later"
+ ],
+ "authors": [
+ {
+ "name": "WordPress Community",
+ "homepage": "https://wordpress.org/about/"
+ }
+ ],
+ "description": "WordPress is open source software you can use to create a beautiful website, blog, or app.",
+ "homepage": "https://wordpress.org/",
+ "keywords": [
+ "blog",
+ "cms",
+ "wordpress"
+ ],
+ "time": "2020-06-10T22:05:38+00:00"
+ },
+ {
+ "name": "myclabs/deep-copy",
+ "version": "1.x-dev",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/969b211f9a51aa1f6c01d1d2aef56d3bd91598e5",
+ "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "replace": {
+ "myclabs/deep-copy": "self.version"
+ },
+ "require-dev": {
+ "doctrine/collections": "^1.0",
+ "doctrine/common": "^2.6",
+ "phpunit/phpunit": "^7.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "DeepCopy\\": "src/DeepCopy/"
+ },
+ "files": [
+ "src/DeepCopy/deep_copy.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Create deep copies (clones) of your objects",
+ "keywords": [
+ "clone",
+ "copy",
+ "duplicate",
+ "object",
+ "object graph"
+ ],
+ "funding": [
+ {
+ "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-06-29T13:22:24+00:00"
+ },
+ {
+ "name": "netresearch/jsonmapper",
+ "version": "v2.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cweiske/jsonmapper.git",
+ "reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/e0f1e33a71587aca81be5cffbb9746510e1fe04e",
+ "reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "ext-pcre": "*",
+ "ext-reflection": "*",
+ "ext-spl": "*",
+ "php": ">=5.6"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4 || ~7.0",
+ "squizlabs/php_codesniffer": "~3.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "JsonMapper": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "OSL-3.0"
+ ],
+ "authors": [
+ {
+ "name": "Christian Weiske",
+ "email": "cweiske@cweiske.de",
+ "homepage": "http://github.com/cweiske/jsonmapper/",
+ "role": "Developer"
+ }
+ ],
+ "description": "Map nested JSON structures onto PHP classes",
+ "time": "2020-04-16T18:48:43+00:00"
+ },
+ {
+ "name": "nikic/php-parser",
+ "version": "v4.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nikic/PHP-Parser.git",
+ "reference": "c346bbfafe2ff60680258b631afb730d186ed864"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c346bbfafe2ff60680258b631afb730d186ed864",
+ "reference": "c346bbfafe2ff60680258b631afb730d186ed864",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "ircmaxell/php-yacc": "0.0.5",
+ "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0"
+ },
+ "bin": [
+ "bin/php-parse"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpParser\\": "lib/PhpParser"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Nikita Popov"
+ }
+ ],
+ "description": "A PHP parser written in PHP",
+ "keywords": [
+ "parser",
+ "php"
+ ],
+ "time": "2020-07-02T17:12:47+00:00"
+ },
+ {
+ "name": "ocramius/package-versions",
+ "version": "1.4.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Ocramius/PackageVersions.git",
+ "reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/44af6f3a2e2e04f2af46bcb302ad9600cba41c7d",
+ "reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "^1.0.0",
+ "php": "^7.1.0"
+ },
+ "require-dev": {
+ "composer/composer": "^1.6.3",
+ "doctrine/coding-standard": "^5.0.1",
+ "ext-zip": "*",
+ "infection/infection": "^0.7.1",
+ "phpunit/phpunit": "^7.5.17"
+ },
+ "type": "composer-plugin",
+ "extra": {
+ "class": "PackageVersions\\Installer",
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PackageVersions\\": "src/PackageVersions"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com"
+ }
+ ],
+ "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
+ "time": "2019-11-15T16:17:10+00:00"
+ },
+ {
+ "name": "openlss/lib-array2xml",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nullivex/lib-array2xml.git",
+ "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90",
+ "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "LSS": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Bryan Tong",
+ "email": "bryan@nullivex.com",
+ "homepage": "https://www.nullivex.com"
+ },
+ {
+ "name": "Tony Butler",
+ "email": "spudz76@gmail.com",
+ "homepage": "https://www.nullivex.com"
+ }
+ ],
+ "description": "Array2XML conversion library credit to lalit.org",
+ "homepage": "https://www.nullivex.com",
+ "keywords": [
+ "array",
+ "array conversion",
+ "xml",
+ "xml conversion"
+ ],
+ "time": "2019-03-29T20:06:56+00:00"
+ },
+ {
+ "name": "phar-io/manifest",
+ "version": "1.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/manifest.git",
+ "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
+ "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-phar": "*",
+ "phar-io/version": "^2.0",
+ "php": "^5.6 || ^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+ "time": "2018-07-08T19:23:20+00:00"
+ },
+ {
+ "name": "phar-io/version",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/version.git",
+ "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6",
+ "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Library for handling version information and constraints",
+ "time": "2018-07-08T19:19:57+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-common",
+ "version": "2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
+ "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a",
+ "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~6"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jaap van Otterdijk",
+ "email": "opensource@ijaap.nl"
+ }
+ ],
+ "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
+ "homepage": "http://www.phpdoc.org",
+ "keywords": [
+ "FQSEN",
+ "phpDocumentor",
+ "phpdoc",
+ "reflection",
+ "static analysis"
+ ],
+ "time": "2018-08-07T13:53:10+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-docblock",
+ "version": "5.0.0-alpha5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+ "reference": "8fcadfe5f85c38705151c9ab23b4781f23e6a70e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8fcadfe5f85c38705151c9ab23b4781f23e6a70e",
+ "reference": "8fcadfe5f85c38705151c9ab23b4781f23e6a70e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1",
+ "phpdocumentor/type-resolver": "^0",
+ "webmozart/assert": "^1"
+ },
+ "require-dev": {
+ "doctrine/instantiator": "^1",
+ "mockery/mockery": "^1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ }
+ ],
+ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
+ "time": "2019-06-15T20:45:01+00:00"
+ },
+ {
+ "name": "phpdocumentor/type-resolver",
+ "version": "0.7.x-dev",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/TypeResolver.git",
+ "reference": "e424cdf9bbab5bccdede5f123f706083b11bcef9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e424cdf9bbab5bccdede5f123f706083b11bcef9",
+ "reference": "e424cdf9bbab5bccdede5f123f706083b11bcef9",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1",
+ "phpdocumentor/reflection-common": "~2.0.0-beta1"
+ },
+ "require-dev": {
+ "mockery/mockery": "~1",
+ "phpunit/phpunit": "~6"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "me@mikevanriel.com"
+ }
+ ],
+ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
+ "time": "2019-12-20T14:34:12+00:00"
+ },
+ {
+ "name": "phpspec/prophecy",
+ "version": "v1.10.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpspec/prophecy.git",
+ "reference": "451c3cd1418cf640de218914901e51b064abb093"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093",
+ "reference": "451c3cd1418cf640de218914901e51b064abb093",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.0.2",
+ "php": "^5.3|^7.0",
+ "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
+ "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0",
+ "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0"
+ },
+ "require-dev": {
+ "phpspec/phpspec": "^2.5 || ^3.2",
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.10.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Prophecy\\": "src/Prophecy"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Konstantin Kudryashov",
+ "email": "ever.zet@gmail.com",
+ "homepage": "http://everzet.com"
+ },
+ {
+ "name": "Marcello Duarte",
+ "email": "marcello.duarte@gmail.com"
+ }
+ ],
+ "description": "Highly opinionated mocking framework for PHP 5.3+",
+ "homepage": "https://github.com/phpspec/prophecy",
+ "keywords": [
+ "Double",
+ "Dummy",
+ "fake",
+ "mock",
+ "spy",
+ "stub"
+ ],
+ "time": "2020-03-05T15:02:03+00:00"
+ },
+ {
+ "name": "phpstan/phpdoc-parser",
+ "version": "0.4.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpstan/phpdoc-parser.git",
+ "reference": "1948aa842a94170b408963a9768a102f19cbf1b7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1948aa842a94170b408963a9768a102f19cbf1b7",
+ "reference": "1948aa842a94170b408963a9768a102f19cbf1b7",
+ "shasum": ""
+ },
+ "require": {
+ "php": "~7.1"
+ },
+ "require-dev": {
+ "consistence/coding-standard": "^3.5",
+ "ergebnis/composer-normalize": "^2.0.2",
+ "jakub-onderka/php-parallel-lint": "^0.9.2",
+ "phing/phing": "^2.16.0",
+ "phpstan/extension-installer": "^1.0",
+ "phpstan/phpstan": "^0.12.26",
+ "phpstan/phpstan-strict-rules": "^0.12",
+ "phpunit/phpunit": "^6.3",
+ "slevomat/coding-standard": "^4.7.2",
+ "symfony/process": "^4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PHPStan\\PhpDocParser\\": [
+ "src/"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "PHPDoc parser with support for nullable, intersection and generic types",
+ "time": "2020-06-10T05:04:41+00:00"
+ },
+ {
+ "name": "phpunit/php-code-coverage",
+ "version": "6.1.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d",
+ "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.1",
+ "phpunit/php-file-iterator": "^2.0",
+ "phpunit/php-text-template": "^1.2.1",
+ "phpunit/php-token-stream": "^3.0",
+ "sebastian/code-unit-reverse-lookup": "^1.0.1",
+ "sebastian/environment": "^3.1 || ^4.0",
+ "sebastian/version": "^2.0.1",
+ "theseer/tokenizer": "^1.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.0"
+ },
+ "suggest": {
+ "ext-xdebug": "^2.6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "6.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "time": "2018-10-31T16:06:48+00:00"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "050bedf145a257b1ff02746c31894800e5122946"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946",
+ "reference": "050bedf145a257b1ff02746c31894800e5122946",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+ "keywords": [
+ "filesystem",
+ "iterator"
+ ],
+ "time": "2018-09-13T20:33:42+00:00"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "1.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "time": "2015-06-21T13:50:34+00:00"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "2.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "1038454804406b0b5f5f520358e78c1c2f71501e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e",
+ "reference": "1038454804406b0b5f5f520358e78c1c2f71501e",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "time": "2019-06-07T04:22:29+00:00"
+ },
+ {
+ "name": "phpunit/php-token-stream",
+ "version": "3.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-token-stream.git",
+ "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff",
+ "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Wrapper around PHP's tokenizer extension.",
+ "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
+ "keywords": [
+ "tokenizer"
+ ],
+ "time": "2019-09-17T06:23:10+00:00"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "7.5.20",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "9467db479d1b0487c99733bb1e7944d32deded2c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9467db479d1b0487c99733bb1e7944d32deded2c",
+ "reference": "9467db479d1b0487c99733bb1e7944d32deded2c",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.1",
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "myclabs/deep-copy": "^1.7",
+ "phar-io/manifest": "^1.0.2",
+ "phar-io/version": "^2.0",
+ "php": "^7.1",
+ "phpspec/prophecy": "^1.7",
+ "phpunit/php-code-coverage": "^6.0.7",
+ "phpunit/php-file-iterator": "^2.0.1",
+ "phpunit/php-text-template": "^1.2.1",
+ "phpunit/php-timer": "^2.1",
+ "sebastian/comparator": "^3.0",
+ "sebastian/diff": "^3.0",
+ "sebastian/environment": "^4.0",
+ "sebastian/exporter": "^3.1",
+ "sebastian/global-state": "^2.0",
+ "sebastian/object-enumerator": "^3.0.3",
+ "sebastian/resource-operations": "^2.0",
+ "sebastian/version": "^2.0.1"
+ },
+ "conflict": {
+ "phpunit/phpunit-mock-objects": "*"
+ },
+ "require-dev": {
+ "ext-pdo": "*"
+ },
+ "suggest": {
+ "ext-soap": "*",
+ "ext-xdebug": "*",
+ "phpunit/php-invoker": "^2.0"
+ },
+ "bin": [
+ "phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "7.5-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "https://phpunit.de/",
+ "keywords": [
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "time": "2020-01-08T08:45:45+00:00"
+ },
+ {
+ "name": "psr/container",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "fc1bc363ecf887921e3897c7b1dad3587ae154eb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/fc1bc363ecf887921e3897c7b1dad3587ae154eb",
+ "reference": "fc1bc363ecf887921e3897c7b1dad3587ae154eb",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "time": "2019-10-04T14:07:35+00:00"
+ },
+ {
+ "name": "psr/log",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
+ "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "Psr/Log/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "time": "2020-03-23T09:12:05+00:00"
+ },
+ {
+ "name": "sebastian/code-unit-reverse-lookup",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+ "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+ "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7 || ^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Looks up which function or method a line of code belongs to",
+ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+ "time": "2017-03-04T06:30:41+00:00"
+ },
+ {
+ "name": "sebastian/comparator",
+ "version": "3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
+ "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1",
+ "sebastian/diff": "^3.0",
+ "sebastian/exporter": "^3.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides the functionality to compare PHP values for equality",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
+ "keywords": [
+ "comparator",
+ "compare",
+ "equality"
+ ],
+ "time": "2018-07-12T15:12:46+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29",
+ "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.5 || ^8.0",
+ "symfony/process": "^2 || ^3.3 || ^4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "time": "2019-02-04T06:01:07+00:00"
+ },
+ {
+ "name": "sebastian/environment",
+ "version": "4.2.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/environment.git",
+ "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368",
+ "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.5"
+ },
+ "suggest": {
+ "ext-posix": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.2-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides functionality to handle HHVM/PHP environments",
+ "homepage": "http://www.github.com/sebastianbergmann/environment",
+ "keywords": [
+ "Xdebug",
+ "environment",
+ "hhvm"
+ ],
+ "time": "2019-11-20T08:46:58+00:00"
+ },
+ {
+ "name": "sebastian/exporter",
+ "version": "3.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/exporter.git",
+ "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e",
+ "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0",
+ "sebastian/recursion-context": "^3.0"
+ },
+ "require-dev": {
+ "ext-mbstring": "*",
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.1.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Provides the functionality to export PHP variables for visualization",
+ "homepage": "http://www.github.com/sebastianbergmann/exporter",
+ "keywords": [
+ "export",
+ "exporter"
+ ],
+ "time": "2019-09-14T09:02:43+00:00"
+ },
+ {
+ "name": "sebastian/global-state",
+ "version": "2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
+ "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "suggest": {
+ "ext-uopz": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Snapshotting of global state",
+ "homepage": "http://www.github.com/sebastianbergmann/global-state",
+ "keywords": [
+ "global state"
+ ],
+ "time": "2017-04-27T15:39:26+00:00"
+ },
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "3.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5",
+ "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0",
+ "sebastian/object-reflector": "^1.1.1",
+ "sebastian/recursion-context": "^3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "time": "2017-08-03T12:35:26+00:00"
+ },
+ {
+ "name": "sebastian/object-reflector",
+ "version": "1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "773f97c67f28de00d397be301821b06708fca0be"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be",
+ "reference": "773f97c67f28de00d397be301821b06708fca0be",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "time": "2017-03-29T09:07:27+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
+ "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides functionality to recursively process PHP variables",
+ "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+ "time": "2017-03-03T06:23:57+00:00"
+ },
+ {
+ "name": "sebastian/resource-operations",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/resource-operations.git",
+ "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9",
+ "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides a list of PHP built-in functions that operate on resources",
+ "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+ "time": "2018-10-04T04:07:39+00:00"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
+ "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+ "homepage": "https://github.com/sebastianbergmann/version",
+ "time": "2016-10-03T07:35:21+00:00"
+ },
+ {
+ "name": "slevomat/coding-standard",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/slevomat/coding-standard.git",
+ "reference": "85399de612702d8fd30a05ff6242030f8c2dceb4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/85399de612702d8fd30a05ff6242030f8c2dceb4",
+ "reference": "85399de612702d8fd30a05ff6242030f8c2dceb4",
+ "shasum": ""
+ },
+ "require": {
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7",
+ "php": "^7.1",
+ "phpstan/phpdoc-parser": "0.4.5 - 0.4.8",
+ "squizlabs/php_codesniffer": "^3.5.5"
+ },
+ "require-dev": {
+ "phing/phing": "2.16.3",
+ "php-parallel-lint/php-parallel-lint": "1.2.0",
+ "phpstan/phpstan": "0.12.32",
+ "phpstan/phpstan-deprecation-rules": "0.12.4",
+ "phpstan/phpstan-phpunit": "0.12.11",
+ "phpstan/phpstan-strict-rules": "0.12.2",
+ "phpunit/phpunit": "7.5.20|8.5.2|9.2.5"
+ },
+ "type": "phpcodesniffer-standard",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "6.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "SlevomatCodingStandard\\": "SlevomatCodingStandard"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.",
+ "funding": [
+ {
+ "url": "https://github.com/kukulich",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-07-01T12:31:03+00:00"
+ },
+ {
+ "name": "squizlabs/php_codesniffer",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
+ "reference": "a957a73e3533353451eb9fd62ee58bd0aba2773c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/a957a73e3533353451eb9fd62ee58bd0aba2773c",
+ "reference": "a957a73e3533353451eb9fd62ee58bd0aba2773c",
+ "shasum": ""
+ },
+ "require": {
+ "ext-simplexml": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
+ },
+ "bin": [
+ "bin/phpcs",
+ "bin/phpcbf"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Greg Sherwood",
+ "role": "lead"
+ }
+ ],
+ "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
+ "homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
+ "keywords": [
+ "phpcs",
+ "standards"
+ ],
+ "time": "2020-06-22T05:29:29+00:00"
+ },
+ {
+ "name": "symfony/console",
+ "version": "4.4.x-dev",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/console.git",
+ "reference": "55d07021da933dd0d633ffdab6f45d5b230c7e02"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/console/zipball/55d07021da933dd0d633ffdab6f45d5b230c7e02",
+ "reference": "55d07021da933dd0d633ffdab6f45d5b230c7e02",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.3",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/polyfill-php73": "^1.8",
+ "symfony/polyfill-php80": "^1.15",
+ "symfony/service-contracts": "^1.1|^2"
+ },
+ "conflict": {
+ "symfony/dependency-injection": "<3.4",
+ "symfony/event-dispatcher": "<4.3|>=5",
+ "symfony/lock": "<4.4",
+ "symfony/process": "<3.3"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0"
+ },
+ "require-dev": {
+ "psr/log": "~1.0",
+ "symfony/config": "^3.4|^4.0|^5.0",
+ "symfony/dependency-injection": "^3.4|^4.0|^5.0",
+ "symfony/event-dispatcher": "^4.3",
+ "symfony/lock": "^4.4|^5.0",
+ "symfony/process": "^3.4|^4.0|^5.0",
+ "symfony/var-dumper": "^4.3|^5.0"
+ },
+ "suggest": {
+ "psr/log": "For using the console logger",
+ "symfony/event-dispatcher": "",
+ "symfony/lock": "",
+ "symfony/process": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Console\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Console Component",
+ "homepage": "https://symfony.com",
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-07-06T13:18:39+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
+ "reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.17-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-06-06T08:46:27+00:00"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "7110338d81ce1cbc3e273136e4574663627037a7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7110338d81ce1cbc3e273136e4574663627037a7",
+ "reference": "7110338d81ce1cbc3e273136e4574663627037a7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.17-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-06-06T08:46:27+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php73",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php73.git",
+ "reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fa0837fe02d617d31fbb25f990655861bb27bd1a",
+ "reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.17-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php73\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ],
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-06-06T08:46:27+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php80",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php80.git",
+ "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4a5b6bba3259902e386eb80dd1956181ee90b5b2",
+ "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0.8"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.17-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php80\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ],
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ion Bazan",
+ "email": "ion.bazan@gmail.com"
+ },
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-06-06T08:46:27+00:00"
+ },
+ {
+ "name": "symfony/service-contracts",
+ "version": "v1.1.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/service-contracts.git",
+ "reference": "b776d18b303a39f56c63747bcb977ad4b27aca26"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/b776d18b303a39f56c63747bcb977ad4b27aca26",
+ "reference": "b776d18b303a39f56c63747bcb977ad4b27aca26",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.3",
+ "psr/container": "^1.0"
+ },
+ "suggest": {
+ "symfony/service-implementation": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1-dev"
+ },
+ "thanks": {
+ "name": "symfony/contracts",
+ "url": "https://github.com/symfony/contracts"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Service\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to writing services",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2020-07-06T13:19:58+00:00"
+ },
+ {
+ "name": "theseer/tokenizer",
+ "version": "1.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theseer/tokenizer.git",
+ "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9",
+ "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+ "time": "2019-06-13T22:48:21+00:00"
+ },
+ {
+ "name": "vimeo/psalm",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/vimeo/psalm.git",
+ "reference": "0119cd09c11ea1630d4fe2c99f9b5c52d8063272"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/vimeo/psalm/zipball/0119cd09c11ea1630d4fe2c99f9b5c52d8063272",
+ "reference": "0119cd09c11ea1630d4fe2c99f9b5c52d8063272",
+ "shasum": ""
+ },
+ "require": {
+ "amphp/amp": "^2.1",
+ "amphp/byte-stream": "^1.5",
+ "composer/semver": "^1.4 || ^2.0 || ^3.0",
+ "composer/xdebug-handler": "^1.1",
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-simplexml": "*",
+ "ext-tokenizer": "*",
+ "felixfbecker/advanced-json-rpc": "^3.0.3",
+ "felixfbecker/language-server-protocol": "^1.4",
+ "netresearch/jsonmapper": "^1.0 || ^2.0",
+ "nikic/php-parser": "^4.3",
+ "ocramius/package-versions": "^1.2",
+ "openlss/lib-array2xml": "^1.0",
+ "php": "^7.1.3|^8",
+ "sebastian/diff": "^3.0 || ^4.0",
+ "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0",
+ "webmozart/glob": "^4.1",
+ "webmozart/path-util": "^2.3"
+ },
+ "provide": {
+ "psalm/psalm": "self.version"
+ },
+ "require-dev": {
+ "amphp/amp": "^2.4.2",
+ "bamarni/composer-bin-plugin": "^1.2",
+ "brianium/paratest": "^4.0.0",
+ "ext-curl": "*",
+ "php-coveralls/php-coveralls": "^2.2",
+ "phpmyadmin/sql-parser": "5.1.0",
+ "phpspec/prophecy": ">=1.9.0",
+ "phpunit/phpunit": "^7.5.16 || ^8.5 || ^9.0",
+ "psalm/plugin-phpunit": "^0.10",
+ "slevomat/coding-standard": "^5.0",
+ "squizlabs/php_codesniffer": "^3.5",
+ "symfony/process": "^4.3"
+ },
+ "suggest": {
+ "ext-igbinary": "^2.0.5"
+ },
+ "bin": [
+ "psalm",
+ "psalm-language-server",
+ "psalm-plugin",
+ "psalm-refactor",
+ "psalter"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev",
+ "dev-2.x": "2.x-dev",
+ "dev-1.x": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psalm\\": "src/Psalm/"
+ },
+ "files": [
+ "src/functions.php",
+ "src/spl_object_id.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Matthew Brown"
+ }
+ ],
+ "description": "A static analysis tool for finding errors in PHP applications",
+ "keywords": [
+ "code",
+ "inspection",
+ "php"
+ ],
+ "time": "2020-07-08T21:42:51+00:00"
+ },
+ {
+ "name": "webmozart/assert",
+ "version": "1.9.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/webmozart/assert.git",
+ "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389",
+ "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.3 || ^7.0 || ^8.0",
+ "symfony/polyfill-ctype": "^1.8"
+ },
+ "conflict": {
+ "phpstan/phpstan": "<0.12.20",
+ "vimeo/psalm": "<3.9.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.36 || ^7.5.13"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Webmozart\\Assert\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Assertions to validate method input/output with nice error messages.",
+ "keywords": [
+ "assert",
+ "check",
+ "validate"
+ ],
+ "time": "2020-07-08T17:02:28+00:00"
+ },
+ {
+ "name": "webmozart/glob",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/webmozart/glob.git",
+ "reference": "8da14867b709e8776d9f6272faaf844aefc695e3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/webmozart/glob/zipball/8da14867b709e8776d9f6272faaf844aefc695e3",
+ "reference": "8da14867b709e8776d9f6272faaf844aefc695e3",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.3|^7.0",
+ "webmozart/path-util": "^2.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.6",
+ "sebastian/version": "^1.0.1",
+ "symfony/filesystem": "^2.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.1-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Webmozart\\Glob\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "A PHP implementation of Ant's glob.",
+ "time": "2016-08-15T15:31:26+00:00"
+ },
+ {
+ "name": "webmozart/path-util",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/webmozart/path-util.git",
+ "reference": "95a8f7ad150c2a3773ff3c3d04f557a24c99cfd2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/webmozart/path-util/zipball/95a8f7ad150c2a3773ff3c3d04f557a24c99cfd2",
+ "reference": "95a8f7ad150c2a3773ff3c3d04f557a24c99cfd2",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.3|^7.0",
+ "webmozart/assert": "~1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.6",
+ "sebastian/version": "^1.0.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Webmozart\\PathUtil\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.",
+ "time": "2016-08-15T15:31:42+00:00"
+ },
+ {
+ "name": "wikimedia/composer-merge-plugin",
+ "version": "v1.4.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wikimedia/composer-merge-plugin.git",
+ "reference": "81c6ac72a24a67383419c7eb9aa2b3437f2ab100"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wikimedia/composer-merge-plugin/zipball/81c6ac72a24a67383419c7eb9aa2b3437f2ab100",
+ "reference": "81c6ac72a24a67383419c7eb9aa2b3437f2ab100",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "^1.0",
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "composer/composer": "~1.0.0",
+ "jakub-onderka/php-parallel-lint": "~0.8",
+ "phpunit/phpunit": "~4.8|~5.0",
+ "squizlabs/php_codesniffer": "~2.1.0"
+ },
+ "type": "composer-plugin",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.3.x-dev"
+ },
+ "class": "Wikimedia\\Composer\\MergePlugin"
+ },
+ "autoload": {
+ "psr-4": {
+ "Wikimedia\\Composer\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Bryan Davis",
+ "email": "bd808@wikimedia.org"
+ }
+ ],
+ "description": "Composer plugin to merge multiple composer.json files",
+ "time": "2017-04-25T02:31:25+00:00"
+ },
+ {
+ "name": "wp-oop/wordpress-interface",
+ "version": "dev-task/initial-interfaces",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wp-oop/wordpress-interface.git",
+ "reference": "a5062fd9f3e48b63d659c5dd1db32207c1a628b9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wp-oop/wordpress-interface/zipball/a5062fd9f3e48b63d659c5dd1db32207c1a628b9",
+ "reference": "a5062fd9f3e48b63d659c5dd1db32207c1a628b9",
+ "shasum": ""
+ },
+ "require": {
+ "dhii/human-readable-interface": "^0.1",
+ "dhii/package-interface": "^0.1-alpha1",
+ "php": "^7.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.0 | ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-task/initial-interfaces": "0.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "WpOop\\WordPress\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Anton Ukhanev",
+ "email": "xedin.unknown@gmail.com"
+ }
+ ],
+ "description": "Interfaces for interop within WordPress",
+ "time": "2020-05-20T13:24:44+00:00"
+ }
+ ],
"packages-dev": [],
"aliases": [],
"minimum-stability": "dev",
diff --git a/docker-compose.yml b/docker-compose.yml
index 82cc099..aed0053 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -49,6 +49,19 @@ services:
volumes:
- db:/var/lib/mysql
+ db_admin:
+ image: phpmyadmin/phpmyadmin:latest
+ container_name: "${PROJECT_NAME}_db_admin"
+ restart: unless-stopped
+ environment:
+ MYSQL_ROOT_PASSWORD: $DB_ROOT_PASSWORD
+ depends_on:
+ - db
+ ports:
+ - 1234:80
+# volumes:
+# - db_admin
+
build:
build:
context: ./
@@ -58,9 +71,24 @@ services:
PHP_BUILD_VERSION: $PHP_BUILD_VERSION
BUILD_ROOT_PATH: $BUILD_ROOT_PATH
container_name: "${PROJECT_NAME}_build"
+ working_dir: ${BUILD_ROOT_PATH}
volumes:
- ${BASE_PATH}:${BUILD_ROOT_PATH}
+ test:
+ build:
+ context: ./
+ dockerfile: docker/Dockerfile_wp
+ target: test
+ args:
+ BUILD_ROOT_PATH: $BUILD_ROOT_PATH
+ PHP_BUILD_VERSION: $PHP_BUILD_VERSION
+ container_name: "${PROJECT_NAME}_test"
+ working_dir: ${BUILD_ROOT_PATH}
+ volumes:
+ - ${BASE_PATH}:${BUILD_ROOT_PATH}
+
volumes:
wordpress:
db:
+ db_admin:
diff --git a/docker/Dockerfile_wp b/docker/Dockerfile_wp
index dca98ad..c26b4c9 100644
--- a/docker/Dockerfile_wp
+++ b/docker/Dockerfile_wp
@@ -17,6 +17,19 @@ WORKDIR ${BUILD_ROOT_PATH}
COPY . ./
+FROM php:${PHP_BUILD_VERSION}-cli as test
+
+ARG BUILD_ROOT_PATH
+
+RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
+RUN pecl install xdebug-2.6.0
+RUN docker-php-ext-install pcntl
+RUN docker-php-ext-install posix
+
+WORKDIR ${BUILD_ROOT_PATH}
+COPY --from=build ${BUILD_ROOT_PATH} ${BUILD_ROOT_PATH}
+
+
# Install PHP dev dependencies
FROM build as vendor-dev
diff --git a/inc/bootstrap.php b/inc/bootstrap.php
new file mode 100644
index 0000000..58f22b5
--- /dev/null
+++ b/inc/bootstrap.php
@@ -0,0 +1,24 @@
+setup();
+
+ $proxyContainer = new ProxyContainer();
+ $container = new DelegatingContainer($provider, $proxyContainer);
+ $appContainer = new CompositeContainer([
+ $container
+ ]);
+ $proxyContainer->setInnerContainer($appContainer);
+
+ $module->run($appContainer);
+
+ return $appContainer;
+};
diff --git a/inc/modules.php b/inc/modules.php
new file mode 100644
index 0000000..6439890
--- /dev/null
+++ b/inc/modules.php
@@ -0,0 +1,12 @@
+ function (ContainerInterface $c) use ($mainFile): PluginInterface {
+ $f = $c->get('wordpress/plugin_factory');
+ assert($f instanceof FilePathPluginFactoryInterface);
+ $plugin = $f->createPluginFromFilePath($mainFile);
+
+ return $plugin;
+ },
+ 'me/plugin/plugin_factory' => function (ContainerInterface $c): FilePathPluginFactoryInterface {
+ return $c->get('wordpress/plugin_factory');
+ },
+ 'wordpress/plugin_factory' => function (ContainerInterface $c): FilePathPluginFactoryInterface {
+ return new FilePathPluginFactory($c->get('package/version_factory'));
+ },
+ 'me/plugin/version_factory' => function (ContainerInterface $c): StringVersionFactoryInterface {
+ return $c->get('package/version_factory');
+ },
+ 'package/version_factory' => function (): StringVersionFactoryInterface {
+ return new StringVersionFactory();
+ },
+ ];
+};
diff --git a/modules.local/core/module.php b/modules.local/core/module.php
new file mode 100644
index 0000000..77d31eb
--- /dev/null
+++ b/modules.local/core/module.php
@@ -0,0 +1,17 @@
+versionFactory = $versionFactory;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function createPluginFromFilePath(string $filePath): PluginInterface
+ {
+ if (!is_readable($filePath)) {
+ throw new RuntimeException(sprintf('Plugin file "%1$s" does not exist or is not readable', $filePath));
+ }
+
+ $pluginData = get_plugin_data($filePath);
+ if (empty($pluginData)) {
+ throw new UnexpectedValueException(sprintf('Plugin file "%1$s" does not have a valid plugin header', $filePath));
+ }
+
+ $pluginData = array_merge([
+ 'Name' => '',
+ 'Version' => '0.1.0-alpha1+default',
+ 'Title' => '',
+ 'Description' => '',
+ 'TextDomain' => '',
+ 'RequiresWP' => '5.0',
+ 'RequiresPHP' => '5.6',
+ ], $pluginData);
+
+ $baseDir = dirname($filePath);
+ $baseName = plugin_basename($filePath);
+ $slug = $this->getPluginSlug($baseName);
+ $textDomain = !empty($pluginData['TextDomain']) ? $pluginData['TextDomain'] : $slug;
+
+ return new Plugin(
+ $pluginData['Name'],
+ $this->createVersion($pluginData['Version']),
+ $baseDir,
+ $baseName,
+ $pluginData['Title'],
+ $pluginData['Description'],
+ $textDomain,
+ $this->createVersion($pluginData['RequiresPHP']),
+ $this->createVersion($pluginData['RequiresWP'])
+ );
+ }
+
+ /**
+ * Creates a new version from a version string.
+ *
+ * @param string $versionString The SemVer-compliant version string.
+ *
+ * @return VersionInterface The new version.
+ *
+ * @throws DomainException If version string is malformed.
+ */
+ protected function createVersion(string $versionString): VersionInterface
+ {
+ return $this->versionFactory->createVersionFromString($versionString);
+ }
+
+ /**
+ * Retrieves a plugin slug from its basename.
+ *
+ * @param string $baseName The plugin's basename.
+ *
+ * @return string The plugin's slug.
+ */
+ protected function getPluginSlug(string $baseName): string
+ {
+ $directorySeparator = '/';
+
+ // If plugin is in a directory, use directory name
+ if (strstr($baseName, $directorySeparator) !== false) {
+ $parts = explode($directorySeparator, $baseName);
+ return $parts[0];
+ }
+
+ // If plugin is not in a directory, return plugin file basename
+ return basename($baseName);
+ }
+}
diff --git a/modules.local/core/src/Module.php b/modules.local/core/src/Module.php
new file mode 100644
index 0000000..9d2bd36
--- /dev/null
+++ b/modules.local/core/src/Module.php
@@ -0,0 +1,37 @@
+serviceProvider = $serviceProvider;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function setup(): ServiceProviderInterface
+ {
+ return $this->serviceProvider;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function run(ContainerInterface $c): void
+ {
+ // Nothing to do
+ }
+}
diff --git a/modules.local/core/src/Plugin.php b/modules.local/core/src/Plugin.php
new file mode 100644
index 0000000..a33e4db
--- /dev/null
+++ b/modules.local/core/src/Plugin.php
@@ -0,0 +1,155 @@
+name = $name;
+ $this->description = $description;
+ $this->version = $version;
+ $this->baseDir = $baseDir;
+ $this->baseName = $baseName;
+ $this->title = $title;
+ $this->textDomain = $textDomain;
+ $this->minPhpVersion = $minPhpVersion;
+ $this->minWpVersion = $minWpVersion;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getDescription()
+ {
+ return $this->description;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getVersion(): VersionInterface
+ {
+ return $this->version;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getBaseDir(): string
+ {
+ return $this->baseDir;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getBaseName(): string
+ {
+ return $this->baseName;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getTextDomain(): string
+ {
+ return $this->textDomain;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getTitle()
+ {
+ return $this->title;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getMinPhpVersion(): VersionInterface
+ {
+ return $this->minPhpVersion;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getMinWpVersion(): VersionInterface
+ {
+ return $this->minWpVersion;
+ }
+}
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
new file mode 100644
index 0000000..44d9489
--- /dev/null
+++ b/phpcs.xml.dist
@@ -0,0 +1,50 @@
+
+
+
+ ./src
+
+
+
+
+
+
+
+ warning
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..0017811
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+ ./tests/unit/
+
+
+ ./tests/functional/
+
+
+
+
+ src
+
+
+
diff --git a/plugin.php b/plugin.php
index 406c64a..824bc32 100644
--- a/plugin.php
+++ b/plugin.php
@@ -13,3 +13,19 @@
* Text Domain: plugin
* Domain Path: /languages
*/
+
+(function (string $mainFile): void {
+ $rootDir = dirname($mainFile);
+ $autoload = "$rootDir/vendor/composer/autoload.php";
+
+ if (file_exists($autoload)) {
+ require $autoload;
+ }
+
+ add_action('plugins_loaded', function () use ($mainFile, $rootDir) {
+ $incDir = "$rootDir/inc";
+ $bootstrap = require "$incDir/bootstrap.php";
+
+ $appContainer = $bootstrap($rootDir, $mainFile);
+ });
+})(__FILE__);
diff --git a/psalm.xml.dist b/psalm.xml.dist
new file mode 100644
index 0000000..51ea1ff
--- /dev/null
+++ b/psalm.xml.dist
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ModularModule.php b/src/ModularModule.php
new file mode 100644
index 0000000..57b2531
--- /dev/null
+++ b/src/ModularModule.php
@@ -0,0 +1,54 @@
+modules = $modules;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function setup(): ServiceProviderInterface
+ {
+ $providers = [];
+ foreach ($this->modules as $module) {
+ assert($module instanceof ModuleInterface);
+ $providers[] = $module->setup();
+ }
+
+ return new CompositeCachingServiceProvider($providers);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function run(ContainerInterface $c): void
+ {
+ foreach ($this->modules as $module) {
+ assert($module instanceof ModuleInterface);
+ $module->run($c);
+ }
+ }
+}
diff --git a/tests/Func/MainModuleTest.php b/tests/Func/MainModuleTest.php
new file mode 100644
index 0000000..a865466
--- /dev/null
+++ b/tests/Func/MainModuleTest.php
@@ -0,0 +1,29 @@
+bootstrapModule();
+ $this->assertInstanceOf(ContainerInterface::class, $appContainer);
+ $this->assertTrue($appContainer->has('me/plugin/plugin'));
+ $this->assertFalse($appContainer->has(uniqid('non-existing-service')));
+ }
+
+ protected function bootstrapModule(): ContainerInterface
+ {
+ $rootDir = ROOT_DIR;
+ $mainFile = "$rootDir/plugin.php";
+ $bootstrap = require ("$rootDir/inc/bootstrap.php");
+ $appContainer = $bootstrap($rootDir, $mainFile);
+
+ return $appContainer;
+ }
+}
diff --git a/tests/Func/ModularModuleTest.php b/tests/Func/ModularModuleTest.php
new file mode 100644
index 0000000..1f993f9
--- /dev/null
+++ b/tests/Func/ModularModuleTest.php
@@ -0,0 +1,140 @@
+createModule(
+ [
+ $service1Name => function (): string {
+ return uniqid('service1-1');
+ }
+ ],
+ [],
+ function () use ($output1): void {
+ echo $output1;
+ }
+ );
+ $module2 = $this->createModule(
+ [
+ $service1Name => function () use ($service1Value): string {
+ return $service1Value;
+ }
+ ],
+ [],
+ function () use ($output2): void {
+ echo $output2;
+ }
+ );
+ $module3 = $this->createModule(
+ [
+ $service2Name => function () use ($service2Value): string {
+ return $service2Value;
+ }
+ ],
+ [
+ $service1Name => function (ContainerInterface $c, string $prev) use ($extension1Value): string {
+ return $prev . $extension1Value;
+ },
+ ],
+ function () use ($output3): void {
+ echo $output3;
+ }
+ );
+
+ $subject = $this->createSubject([$module1, $module2, $module3]);
+ }
+
+ {
+ $this->expectOutputString(implode('', [$output1, $output2, $output3]));
+ }
+
+ {
+ $provider = $subject->setup();
+ $container = $this->createContainer($provider);
+ $subject->run($container);
+
+ $this->assertEquals($service1Value . $extension1Value, $container->get($service1Name));
+ $this->assertEquals($service2Value, $container->get($service2Name));
+ }
+ }
+
+ /**
+ * @param iterable|ModuleInterface[] $modules The modules to load.
+ *
+ * @return Subject|MockObject
+ */
+ protected function createSubject(iterable $modules): Subject
+ {
+ $mock = $this->getMockBuilder(Subject::class)
+ ->setConstructorArgs([$modules])
+ ->enableProxyingToOriginalMethods()
+ ->getMock();
+
+ return $mock;
+ }
+
+ /**
+ * @return ContainerInterface|MockObject
+ */
+ protected function createContainer(ServiceProviderInterface $provider): ContainerInterface
+ {
+ $mock = $this->getMockBuilder(DelegatingContainer::class)
+ ->enableProxyingToOriginalMethods()
+ ->setConstructorArgs([$provider])
+ ->getMock();
+
+ return $mock;
+ }
+
+ /**
+ * @param array $factories
+ * @param array $extensions
+ * @param callable $action
+ *
+ * @return ModuleInterface|MockObject
+ */
+ protected function createModule(array $factories, array $extensions, callable $action): ModuleInterface
+ {
+ $module = $this->getMockBuilder(ModuleInterface::class)
+ ->setMethods(['setup', 'run'])
+ ->getMock();
+ $provider = $this->getMockBuilder(ServiceProviderInterface::class)
+ ->setMethods(['getFactories', 'getExtensions'])
+ ->getMock();
+
+ $provider->method('getFactories')
+ ->will($this->returnValue($factories));
+ $provider->method('getExtensions')
+ ->will($this->returnValue($extensions));
+
+ $module->method('setup')
+ ->will($this->returnValue($provider));
+ $module->method('run')
+ ->will($this->returnCallback($action));
+
+ return $module;
+ }
+}
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 0000000..90ba2aa
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,13 @@
+