API Consuming library - How to structure a composer package - php

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.

Related

Yii2 Advanced Template use model from frontend in console

I have a long list of models in frontend. Some of these have functions that are required to be run in batch. For this console is fine.
I can include the models by copying over the code, however this is not a decent approach.
What Im looking for a way to import models from the frontend submodule in console command so I can make changes in one place.
To clarify,
the standard way of including
use app\models\Mymodelname;
in the console\model results in the following error
'Class 'app\models\Mymodelname' not found'
use app\models\Mymodelname;
Have not worked with this include statement before. I prefer to use the frontend/backend as is. If I had to make a wild guess though, this looks for models within console. #app is an alias for current application.
Usually, I keep anything used by more than 1 application under common. As you pointed out, maintaining two copies of the same code is not a good practice.
Try using frontend\models\Mymodelname directly if moving to common is not an option
I don't know if you have two separate applications, or could benefit from this, as you are already using submodules, but depending on your desire to separate concerns with some console commands this might be advantageous.
If you are using composer to manage your dependencies then you can create a separate repository in git, for example, and add a new dependency in your project which contains these common models.
Then, include your dependency in both projects. This introduces some troubles while developing since both apps share this dependency and it can be frustrating at times; I have shared common functionality between multiple interval laravel projects in this fashion with great success.
Currently you seem to be using submodules so this might require restructuring which could be difficult or impossible.
Another option if you want to keep to submodules is to keep common models at a higher level (not inside a submodule) so that you can import the models into both submodules and use them in both places. I shared common models between modules with yii 1.1.16 using this strategy over several years with much success.
Both options have their advantages so weigh carefully your desired outcomes. Feel free to ask for clarification.
How to add private github repository as Composer dependency
#app is an alias of current running application. It can be frontend or backend or console. If you want to access model across applications, add it to commen\models. Or change app\models to frontend\models. That way, you can access frontend models on console. Better way is moving it to common\models.

Where should I put a custom class file in zend framework 3?

I have created a set of class files that helps to create the route configuration array. I, however, do not know where to put the source files. I browsed around a little and found some answers that suggested I put up the code in packagist and install it via composer, but my classes are relatively small. So, I wanted to ask if there is another way to do it. The files must be accessible in all the modules.
Your application code is organised into modules and lives in module/<Modulename>/src/. If the code is something you might want to reuse in other applications, then it might make more sense to have it as a standalone library that you install via. Composer.
You're code is accessibly through all the application if it is configured in the composer.json's autoload section.
Code structure in ZF is quite simple. You have your modules and in every module you have an src directory. This src directory should have its own namespace. And there you can place your custom route configurator under this namespace, like 'ModuleName\RouteConfigurator'.
But if you use this logic through multiple modules, I suggest you to create a separate module for it. In this case, after a long road, you may consider creating a separate composer package from it. But it's not necessary.
If you're not familiar with defining modules, please read the zend-modulemanager's documentation (https://docs.zendframework.com/zend-modulemanager/intro/)

ZF2 Trouble using dependancy injection in Vendor library

So I have the following dilemma. I want to have a common library that all my ZF2 applications will use. This library will contain all the business logic for my website. Each application will consume different parts of the library to properly display/perform whatever actions are necessary. Now so far I've managed to create a library. Lets call it Foo. Foo has a Module.php which does the basic autoloading required to load the entire library.
Now here is where I start to have problems. I want to take advantage of dependency injection, the service manager, etc from ZF2 inside Foo. The problem is I only have the one Module.php that loads Foo. This means as my library grows so will Module.php since as far as I can tell I can't have sub modules. Is there any way around this issue?
Essentially I want every app to just include Foo and Foo to have several Module.php so that at least the dependency stuff can be handled on a module by module basis.
You're probably swimming against the current to try and do sub-modules -- and you probably don't need to.
If you've written your module nicely, loading it won't be a very expensive operation. Remember, the whole point of the service manager is that all those services are lazily created. So if the calling code never asks for a particular service in a particular request, that service's classfile is never autoloaded, the object is never instantiated, etc. So you may be fine staying with a big, monolithic, module.
The one place that things might get a little tricky is if you're leaning heavily on the EventManager, and your module is attaching a bunch listeners. But you can probably get around that by setting up some module configuration directives, and then just conditionally attach listeners.
Having said that, it probably makes sense to try to split your module up. So you could have FooBar and FooBaz modules.
If you really, really, want sub-modules, you can dig into the ModuleManager and try to figure it out. I went a little ways down that road once -- and then got distracted. In my case, I was dealing with shipping physical items. I wanted a "Fulfillment" module that could be configured to load a bunch of similar shipping modules (Fulfillment\Courier\USPSModule, Fulfillment\Courier\FedExModule, etc), so that my main Fulfillment module could iterate over all loaded submodules, without specific knowledge about any of them. If I recall correctly, the best way to do it was to essentially mirror what ZF2 does, but inside my Fulfillment\Module class. However, I can't think of many situations where you'd want to do that, unless you want a set of similar submodules that all implement the same interface, and want them to be consumed by a super-module that has no specific knowledge of them. I also looked at this because was thinking about runtime enabling/disabling of those submodules by end-users (sort of like a plugin system).
If you're not doing that, I'd say stick to FooBarModule, FooBazModule, etc, so far as it makes sense. And remember even if your module contains a ton of code, the ServiceManager will only autoload, parse, and instantiate classes that are needed to satisfy the dependencies of any given request.

Security component from Symfony 2.0 as standalone

I'm trying to add Symfony 2.0 ACL to my frameworkless PHP application. Because of the lack of documentation on how to use Security component as standalone I've got totally confused and I've got stucked with questions: What class to include first? Which object to instance? Is it possible to be used without models and controllers?
Any suggestion on how to start or any good link?
Thanks
The SecurityServiceProvider for Silex might be a good place to start, as it integrates all of the essential component services in a single file. Although large, you'll probably find it much easier to digest than Symfony2's SecurityBundle.
In the interest of maintaining your sanity, you should consider using a service container to organize all of these objects. In the aforementioned provider class, the Silex Application class is a Pimple instance, so you should be able to port it stand-alone Pimple with modest effort. I saw this because integrating a Pimple service container into your application should be less invasive than adopting the Silex framework.
Once you have the essential security component classes working, you should be able to following along with the ACL documentation and add additional services to your container as needed. At that point, the ACL-specific sections of the SecurityBundle might prove helpful, as you can focus in on the relevant bits. Keep in mind that there are multiple cookbook entries for ACL in the documentation.
What class to include first?
You will most likely need to include at least parts if not all of the security core, then which ever ACL implementation that you are wanting to use. You can look at the dependencies that are listed in the beginning of the ACL implementation and see what they extend. For instance, the ACL/DBAL has the following dependencies called in the header:
namespace Symfony\Component\Security\Acl\Dbal;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\Statement;
use Symfony\Component\Security\Acl\Model\AclInterface;
use Symfony\Component\Security\Acl\Domain\Acl;
use Symfony\Component\Security\Acl\Domain\Entry;
use Symfony\Component\Security\Acl\Domain\FieldEntry;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Exception\AclNotFoundException;
use Symfony\Component\Security\Acl\Exception\NotAllAclsFoundException;
use Symfony\Component\Security\Acl\Model\AclCacheInterface;
use Symfony\Component\Security\Acl\Model\AclProviderInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
But you would probably need to check each of those listed for their dependencies, and load those as well.
I would back-track through the dependencies, and keep track of what needs what. Cull those classes out into a separate location so that you have only what you need, and use some error trapping to determine that you have it all.
Which object to instance?
Your ACL. If the dependencies are all determined, and loaded, then you should be able to instantiate the ACL class object.
Is it possible to be used without models and controllers?
To be honest, I am not sure that using ACL outside of S2 is possible without a WHOLE lot of work, but if you can get it instantiated with everything it needs, then you should be able to use the object without an MVC model.
Unfortunately, from what I understand of S2, it is a full stack framework, and meant to be an all or nothing kind of thing. but if I were going to try and make it work, this would be the way I would go about it.
If u want to understand how to use use symfony2 component and how to integrate that within your project then read Fabien Potencier blog 'create your own framework'
post that will definitely help u to understand core of framework from and how to bootstrap symfony2 component in your project
there is also good document for ACL on symfony website

Integrating external scripts with Zend Framework

What is the best way to integrate an external script into the Zend Framework? Let me explain because I may be asking this the wrong way. I have a script that downloads and parses an XML file. This script, which runs as a daily cron job, needs to dump its data into the database.
I am using Zend Framework for the site which uses this script and it seems to me that it would be best to use my subclassed model of Zend_Db_Abstract to do the adding and updating of the database. How does one go about doing this? Does my script go in the library next to the Zend Components (i.e. library/Mine/Xmlparse.php) and thus have access to the various ZF components? Do I simply need to include the correct model files and the Zend DB component in the file itself? What is the best way to handle this sort of integration?
Yes, you should put your own classes that maybe inherit Zend Framework classes or add further classes into your own folder next to the Zend Framework folder in library.
When you have Zend_Loader s auto-loading enabled, the class names will automatically map to the class you created, e.g.:
My_Db_Abstract will map to My/Db/Abstract.php .
In your library directory you should have your own library next to the Zend library folder. Whatever you call it (Mylib, Project, ...) you should include it into the Zend Autoloader and that's done as follows:
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
$loader->registerNamespace('Project_');
$loader->setFallbackAutoloader(true);
if ($configSection == 'development')
{
$loader->suppressNotFoundWarnings(false);
}
In order for you library to integrate nicely with ZF and the Autoloader you should stick to the ZF naming conventions. This means two things:
if you extend an existing ZF class, replicate the ZF folder structure so that your file has the same path and name except for the library name. E.g. /library/Zend/Db/Abstract.php => /library/Project/Db/Abstract.php.
if you write your own classes, still stick to the ZF naming conventions for the autoloader to find them.
I just came across something that may be germane to this question. This IBM developerWorks article.
The author recommends simply creating a scripts folder in the ZF hierarchy and the using it as one normally would within ZF (though he does set the ini path and call autoload). Is it that simple? Does simply being in the hierarchy of the framework and including the path and autoloader grant your script access to all of the goodies?
I'm not 100% sure what you're trying to ask but I will try to help. If at any point you add a reference to "/path/to/zend/framework" into your php include path then you have in essence enabled the Zend Framework. From there if you do:
require_once('Zend/Loader.php');
Zend_Loader::registerAutoload();
Then at any point in your script you can pretty much just create new Zend Framework objects and Zend_Loader will handle the rest.
One of the big things about the Zend Framework though is not forcing you to do things a certain way. That's why sometimes there are several ways to accomplish the same thing. So, if you feel you need to make your script use the Zend Framework just for the sake of doing so this is not really necessary. But if you think it may improve your script in some way then go for it.
I usually put custom stuff that I think could be used across projects in a custom folder in the library. So I have a library/Ak33m folder that has scripts that may be outside of the framework.
As a ZF noob myself, I think I understand some of what the OP is trying to figure out. So, I'll just explain a bit of what I understand in the hope that it is helpful either to the OP (or more likely, to a future reader, since the original question is so old and I imagine that OP is now a ZF guru).
I understand that ZF claims to be largely "use at will", so that you need no buy into an entire structure, like the Zend_Application, the Zend_Bootstrap class, the entire MVC approach, etc.
Further, I understand conventions for class naming and file locations that enable easy autoloading. Ex: class App_Model_User resides in a folder App/Model/User.php
I think what can be potentially confusing is that in the script context, where you have not yet
done the .htaccess magic that pushes all request to public/index.php
set your APPLICATION_PATH and include paths in public/index.php
created your Application or Bootstrap object tied to a config file
it can be a little bit unclear how best to avail yourself of most of the ZF goodness we get in that context and want in another context.
I guess my answer to the original question would be that the usual entry point sequence of
http request -> .htaccess -> index.php -> config
sets up much of our environment for us, we would need to duplicate some of that for different entry path.
So, for your script, my first instinct would be to create a common include file that mirrors much of what happens in index.php - set the include paths, the APPLICATION_PATH, instantiates and calls a bootstrap, and then does your script-specific processing.
Even better, it might be desirable to create a single entry point for all your scripts, like we do in the http/web context. Extend Zend_Application for your own script purposes so that $application->run(); no longer starts up the MVC router-controller-dispatch processing, but rather does your own stuff. In that way, this single script entry point would look almost identical to the web entry point, the only difference being which application object gets instantiated. Then pass the name of your desired Application class as a command line parameter to the script.
But here I confess to being less confident and just throwing out ideas.
Hope all this helps someone. It actually helped me to write it all down. Thanks and cheers!
Update 2009-09-29: Just ran across this article: Using Zend Framework from the Command Line
Update 2009-11-20: And another article: Cron jobs in Zend Framework | GS Design
Update 2010-02-25: Easy command line scripts with Zend Application - David Caunt

Categories