Is this considered a misuse of composer? - php

Given the following directories at the root of a project:
app/, A combination of static resources and class-mapped project code
src/, Configured to load namespaced PHP code
vendor/, Packages managed by composer.json
Regardless of what framework I happen to be using, would it be correct to make use of the src directory for portable code intended to be usable outside of the project, or is that the role of the vendor directory?
Are there any issues that might arise as a result of using the src directory for code intended to be shared?

This seems like a reasonable design approach. Composer lets you do this by putting your own classes to be autoloaded into a directory and then referring to it in your composer.json . See this question for how: Using Composer's Autoload
However, this won't handle versioning of your code under src/ . If you are going to be separately publishing this, it might be worth learning how to make your library installable through Composer and once you have checked it in to a Git repo somewhere, reference it like this:
"require": {
"me/testlib": "1.0.*"
}
"repositories": [
{
"type": "vcs",
"url": "https://github.com/username/hello-world"
}
]
Sure, then you'll be maintanining multiple source trees, one for your project and one for each library, but that's a good thing right? ("Separation of concerns".)

Your approach looks like a valid one in the general case.
It will however become invalid if the amount of data app or anywhere else outweighs the amount of usable code in src. In other words: If you only host about one shared class in src, and one gigabyte of assets in app that isn't needed for the class, it would be stupid to make this a library.
But in such situation, it would be easy to simply move that class into a composer library on it's own and again include it. Because of autoloading the class will still be there (although the file changed it's location) and be usable in other code. Any any other software requiring the whole bunch of assets will continue to work even if that class is moved.
When moving code into libraries, it might be worth considering that smaller usually is better, but too small is worthless. You don't want to require every single class on it's own - but a reasonable collection of classes with the same topic make an excellent candidate.

Related

Do I need to restructure my project directories to work with composer?

For the past 5 years or so, I've settled into the habit of structuring my web projects as such:
/var/www/project/
/project.com/
/index.php
/images/
/project.inc/
/vendor/
/classes/
/pages/
/models/
You get the idea. It's my own hacked up mvc-like system. project.com is the only directory that's web-accessible. Most other things are behind the scenes, and I like it like that. However - lately I've started tinkering with composer. I cannot find any feasible way to house composer under project.inc. Looking through composer's setup and reading through the docs ... am I correct in assuming that composer absolutely has to be in the projects webroot? Is there no way around this?
To be clear, you are referring to the composer.json which is just a build configuration file. I would argue that it doesn't belong in either of your directories because it is not a web file (project.com) nor is it php code to be included at execution time (project.inc).
Be that as it may, it doesn't matter where you place it. As for setting the location of the vendor directory you can do that in the config section of the composer.json
{
"config": {
"vendor-dir": "project.inc/vendor"
}
}
I'd still recommend you take a look at symfony and laravel and the structure and conventions they use. They address the same things you wanted to address, and even a few things you don't explicitly address.

Composer optimization level 1

On Composer's autoload optimization page:
Note: You should not enable any of these optimizations in development as they all will cause various problems when adding/removing classes. The performance gains are not worth the trouble in a development setting.
I can definitely see problems for the level 2 optimizations (authoritative class map) on a development environment, but I can't determine what the problems are for level 1 optimizations (class map generation) if I follow the PSR-4 standard.
If I add a class that didn't get generated in the class map, it will fall back to PSR-4 rules to look for the class.
If I refactor (move) a class to a different namespace, it will also not find it in the class map and attempt to resolve it using PSR-4 rules.
What are the potential issues with the generated class map on dev environment with a project that complies with PSR-4?
Level 1 optimizations may create problems if you will move class to different directory without changing namespace. Since there may be multiple ways to resolve single namespace, such changes will be properly handled by Composer, but may fail when you have a outdated classmap.
Example:
"autoload": {
"psr-4": {
"app\\": "src",
"app\\db\\": "src/drafts/db"
}
},
Class app\db\Entity may be placed in src/drafts/db/Entity.php or src/db/Entity.php and in this order Composer will search for class file. Normally if you move a file from src/drafts/db to src/db Composer will finally find this class. But if you have outdated classmap, Composer will blindly include non-existing file and you will get a fatal error.
In addition to this apcu-autoloader option will also cache misses. So if you request a non-existent app/db/NewEntity class, and then add this class, Composer will not detect this change since it has cached info that this class does not exist.
These are generally edge cases, usually you will never notice such nuances. But this is still possible and unnoticeable performance boost on development environment is not worth the risk of losing a few hours on debugging cache-related issues of Composer autoloader.

API Consuming library - How to structure a composer package

One simple service offers an API to use some of its features. I want to create a composer package which will consume the following API and I want it to be compatible with other PHP projects. I read about the topic and came up with the idea to to use GuzzleHttp to make the requests (I saw it in few other libraries). However I'm confused about the structure of an API consuming library. (It's a REST API).
The API gives access to two resources: Customers and Products.
Products resource has the following methods:
List all available products - GET
Add products - POST
Delete product - DELETE
Customers resources has the same methods.
What I've done so far is the following structure (I'm following psr-4 as suggested):
src/
--MyName/
----PackageName/
------Resources/
------Containers/
------Exceptions/
------Client.php
src/MyName/PackageName is the structure I read in a tutorial about creating a composer package. MyName\PackageName will be my namespace throught it.
File Client.php is a class which loads some configuration about authorization (Basic Auth) and creates new instance of GuzzleHttp\Client. Also I have two methods for building a request (setting HTTP Method, URL & additional parameters).
Also I have a __call() method which instantiates new object from Folder Resources and the first element of the array passed as second argument is the method which should be called.
Folder Resources contains two files Products.php and Customers.php which are classes for handling all methods for those two resources I mentioned above. Every class extends Client.php.
Folder Containers contains files for processing the response data from every resource.
Folder Exceptions contains classes for custom exceptions which might be thrown in the process.
Is that a good approach to a easily maintainable library or I'm missing some of the concepts here?
How to structure a composer package
To cut a long story short: stick to PSR-4, decide for a folder layout and expose this layout in the autoloading section of your composer.json file. The rest is: pick clear and understandable class and method names to expose the API.
Your question is a mix of different things and some things overlap each other.
When talking about the structure of your project, we have to split between source (object-oriented design) and the folder layout (autoloading relevant) and the composer integration (with autoloading description).
Let's go through this in order...
a) source-code
However I'm confused about the structure of an API consuming library.
Is that a good approach to a easily maintainable library or I'm missing some of the concepts here?
The questions is: Is my code clear and precise enough (for myself and for others, e.g. to be consumed in another project)?
The advises to give here are:
Picking clear class and method names makes use easier, like Company\PhotoApi\Client.php
Namespace and Class could probably expose the vendor, e.g person or company producing the source and then you could include the API name, finally the classname.
Follow some basic OO principles
How you fetch the data from the API is taste based. Going with Guzzle is ok, while going with a lighter solutions, like file_get_contents or curl, would probably work out, too. It depends.
in regard to maintainability:
The lower the number of files and the less complex your code is, the better the maintainability. Do you need an Exceptions folder? How many files are there? Why not simply stick to PHP's default exceptions?
You might also consider, that your lib has to change if the API changes, right? And, then if your lib changes, all the code in projects using your lib has to change, right? If there is only a small set of endpoints exposed by the API, then it might be better to use just one object and provide accessor methods for them, instead of using multiple objects as accessors, which might be too fine-grained. This means that projects using your API will (possibly) have fewer lines changes when upgrading. Anyway: your users will tell you, if your API lib is too difficult to use.
While you have something like:
$PhotoApiProducts = new Company\PhotoApi\Products;
$products = $PhotoApiProducts->get();
This is also possible:
$api = new Company\PhotoApi\Client;
$products = $api->getProducts();
$consumers = $api->getConsumers();
b) folder structure
I'm following psr-4 as suggested
In regard to the folder layout, my suggestion is to stick with PSR-4.
But you have to decide the exact folder layout yourself. You might take a look at the examples section of the PSR-4 standard to see different folder layouts respecting PSR-4. http://www.php-fig.org/psr/psr-4/
c) Composer integration
And then finally.. you add a composer.json file describing your project.
The autoloading section is the most important part, because this is were you expose the structure of your project to Composer.
When you have decided to use PSR-4 for your project, then simply say so in the autoloading section and add the mapping from your namespace to source, like
"autoload": {
"psr-4": {
"Foo\\Bar\\": "src/Foo/Bar/"
}
}
Now, a user of your Composer project has to load the composer autoloader during the bootstrap and then he might start using your lib, by just using a namespaced classname from it - then the autoloader will do its work.

Can we use Composer with sparse SVN checkout to share dependencies?

Our current development setup uses a single Subversion repository containing multiple projects, each with branches, tags, and trunk. We then use a "sparse checkout" to select the projects, and branches of those projects, to work with.
The result is that the directory structure of a working copy matches that of the repository, including branch information, and we never use svn switch. (This style of working will probably be familiar to anyone who uses SVN, but may be surprising to those who don't.)
We are thinking of using Composer to manage both external and internal dependencies, but I'm not sure how this can work with the sparse checkout style of working.
I would like some way of using a directory within the existing checkout to satisfy a dependency, rather than each "root project" needing a separate copy.
For example:
sites/Foo/trunk
depends on lib Aaa, so references lib/Aaa/trunk
depends on lib Bbb 1.5.*, so references lib/Bbb/branches/release-1.5
sites/Bar/trunk
depends on lib Aaa 1.0.*, so references lib/Aaa/branches/release-1.0
depends on lib Bbb 1.5.*, so references lib/Bbb/branches/release-1.5
At present, if I edit the code in lib/Bbb/branches/release-1.5, I can test those changes on both sites, without needing to commit one and update the other.
Is there any way of using Composer to manage these dependencies?
(PS: Please don't answer with "give up on SVN, use Git, it is teh awesomez"; that is an answer to a different question.)
No - I do not believe that you can do this with Composer as standard: it expects to copy the files from whichever source (Packagist/VCS/Zips) to the local vendor folder, which is not what you want.
That said, I believe there are two potential ways you could get this working (at least in part):
Autoloader
You could try using the autoload field in the composer.json file to include the correct files into the project. You would still need to manage the checkouts of the relevant branches/versions manually (like I assume you do now), but you would be able to manage the inclusion of the internal libraries through Composer. This will probably require that your libraries are properly namespaced. The paths to the files for each namespace are relative to the root of the project, but can go below the root (via the /../ path) if required.
To be honest though, if you already have an autoloader for these files, there may not be much advantage to this solution. Relevant Docs
Composer Plugin
You could also write a composer plugin/"custom installer" that could probably manage this. This would have the advantage that you could have it manage checking out the correct parts of the sparse repository to have the correct version available, as well as doing correct wildstar version checking, but would be a much more difficult and riskier venture.
The basic process would be that you would define a new package type (e.g. 'internal-svn-package'). You would create the plugin as an external library that gets installed normally via Composer, which declares (via it's composer.json) that it handles this new type of package. Your custom logic would then be used for any packages that are listed with this custom type. I'm not sure how much of the internal composer logic for SVN checkouts you would be able to reuse however. Relevant Docs

Composer Namespace Collisions in WordPress Plugin Development

I'm encountering a wholly predictable yet incredibly annoying and tough to resolve problem.
I've been working on a PHP framework for developing WordPress plugins. It's using Composer for dependency management. Of course, the problem is if you have two instances of my framework in the same installation of WordPress, you have two vendor folders, and two copies of any packages required by the framework. Which leads to an error.
The framework functions as a separate plugin which is then inherited by any apps/plugins that are build on it.
Move the vendor folder to the core framework folder?
Problems: I don't know what would happen if I have two composer.json files and two composer.phar files writing to the same vendor folder and using the same autoloader. Presumably it wouldn't be good. Besides that, it doesn't solve the problem of collisions with composer packages that could be used by any other script or plugin outside of what I'm trying to handle.
So I'm stuck. Is this a problem that can be solved, or is it just inherent in PHP?
Composer is not really meant to be used multiple times in same project. On other hand there is nothing terribly wrong with it either, however you lose its dependencies features and need to treat this like generic case of dependencies in WordPress environment.
In other words - if you are not doing dependencies Composer way and WordPress is not doing dependencies at all, it becomes your personal problem how to deal with it.
I don't know what would happen if I have two composer.json files and two composer.phar files writing to the same vendor folder and using the same autoloader
I am not following why the vendor folder would be same if you are using multiple composer installs... Could you elaborate on how you structure it and is it meant for public or private use?
I'm not very familar with Composer or the plugin framework you are using, but in general - avoiding function/class name collisions in WordPress plugins is done in the following manner:
Assuming that your plugin (e.g. MyCoolPlugin) is written object-oriented, e.g. as a class named MyCoolPlugin, you may include the helper class/library as a subclass of MyCoolPlugin.
class_exists(), this is PHPs way of finding if a class has been defined. Assuming your helper class the following:
class MyHelperClass{
}
You may use the following check before declaring the class in each of your plugins:
if(!class_exists('MyHelperClass')){
class MyHelperClass{
}
}
Of course, there is a trade-off here, because only the first instance of the class will be used throughour WordPress. E.g. if you have two plugins with two different versions of the helper class - only one of them will be active and available at any given moment.
A global variable - e.g. define('MY_HELPER_IS_LOADED', true); in the helper files (in case you are including them via include() or require()). Then in the beginning of each included helper file check with if(defined('MY_HELPER_IS_LOADED')) return;, which will cause the currently requested file for include/require to NOT be included.
Again the tactics above are used in PHP in general, I am not sure how your plugin framework is set up exactly.

Categories