PHP Packages - Requiring Self For Testing
I like to be able to test code before I push it out onto the Internet. Some might say this is a good idea. Unfortunately, this has always been a hassle when developing PHP packages. I shall now explain why and the solution.
The Problem
Package Structure
When developing a package, I would always create it with the following structure:
|- README
|- composer.json
|- LICENSE.txt
|
|- src/
| |- Class1.php
| |- Class2.php
|
|- testing/
|- composer.json
|- main.php // entry point to kick off all tests
|- tests/
|- TestClass1.php
|- TestClass2.php
All the package's code is within src/
with testing of that src/
code within a separate /testing
folder.
All the metadata, such as thel license and composer.json
file, which describes the package, is on the top layer outside of src and testing.
Autoloading Package Source Files
For loading all of the classes within src/
for testing, I was forced to do one of three options:
Manually include all the
src/
files in themain.php
script so that they were loaded (no autoloading).- This is tedious, especially as classes are added/removed or renamed in
src/
.
- This is tedious, especially as classes are added/removed or renamed in
Include the package as a requirement inside the
composer.json
file within testing, then keep pushing the package every time there was a change, and then perform a composer update.- This was a very slow cycle.
- This was a very slow cycle.
Include the package as a requirement inside the composer.json file, then manually add a symlink of
../../../
for the package within the testing area's vendor directory.- This worked well but was manual and couldn't rely on others to do it.
Composer Paths
I looked online for what others are doing. It seems that a lot of people are testing their packages from outside the package with an external application. I don't like this approach as it means your testing folder can easily get out of sync, and less likely to get maintained.
I read about using relative paths [1][2] which looked promising, but it didn't work for me as I would always get error messages like so:
[RuntimeException]
Package programster/my-package cannot install to
"/home/stuart/Seafile/programster/programming/packages/package-my-package/testing/vendor/programster/my-package"
inside its source at "/home/stuart/Seafile/programster/programming/packages/package-my-package"
The Solution - Script Hooks
The solution came from weotch in a Gigthub issue thread. Composer supports script hooks, which I had completely forgotten about. This means we can just automate the third option I was doing before (replacing the package with a symlink).
{
"require": {
"programster/my-package": "@dev"
},
"scripts": {
"post-install-cmd": [
"rm -rf vendor/programster/my-package && ln -s ../../../ vendor/programster/my-package"
],
"post-update-cmd": [
"rm -rf vendor/programster/my-package && ln -s ../../../ vendor/programster/my-package"
]
}
}
programster
with whatever your vendor name is, and my-package
with the name of your package.
Now you can work away on your src/
classes without having to push code and they will automatically load when you kick off your tests in your testing area.
References
First published: 16th August 2018