I feel like I have searched the entire internet through and through, but cannot seem to figure this one out. I'm using Silex (the latest version) and cannot seem to figure out how to use Silex's ServiceProvider system to return an instance of a class for use.
I do know how to create a basic service provider.
What I do not know how to do is how to have this service provider use a custom class. I've tried everything I can think of or find on the web. Part of the problem is that Silex's documentation on this is not very extensive, and most of the questions that have been ask about this type of issue were asked/answered before a pretty large change to how it was done (or so it seems) so the answers are not current.
So, put briefly:
I want to use Silex's $app['myclass'] type system to access my class, so that I can do things like $app['myclass']->myMethod().
Where I'm hung up is this, while I can create a service provider, I can't figure out how to get the service provider to recognize the class. I've tried the whole namespace thing with the composer auto-load pso-0 set up, and have tried use MyClass/MyClass type things.
Haha, basically, because there is so little documentation, there could be any part of it that I am doing wrong.
Would someone write a current step-by-step process for hooking up a custom library/class to the $app variable? I think this would help not only me, but also others. Thanks!
Seems to me like you are having issues with class loading. This is something that used to be handled by the autoload service in silex. That service was removed however, in favour of composer's autoloading.
You were on the right track with specifying the autoloading in composer.json. In case you're not familiar with composer, read the introduction. For details on how the autoloading works, see the autoloading section of the basic usage chapter.
I will give you the short version here. Make sure your filenames comply with the PSR-0 naming standard. Add this to your composer.json:
{
"autoload": {
"psr-0": {"Acme": "src/"}
}
}
You need to replace Acme with your namespace and src with the base directory for your classes. For example, the class Acme\Foo\Bar would be located in src/Acme/Foo/Bar.php.
Then run php composer.phar update to get the autoload files re-dumped and you should be able to access your classes.
Related
I am using these two libraries from composer
"require": {
"alterfw/php-form-generator": "^0.1.2",
"rlanvin/php-form": "dev-master"
},
Biggest issue is both has the same class name Form with no namespace defined. Now no matter either I am instantiating only one class or both on the same page it is giving me an error as below
Fatal error: Call to undefined method Form::create() in...
create method is to generate form markup from alterfw/php-form-generator library.
So when I tried this
$form = Form::create('path-to-action.php');
$form->add(Form::text('settings')->setLabel('Settings')->setValue('None'));
echo $form->render();
Giving me the error mentioned above. For me it is difficult to understand why even I hven't instantiate another class it is still giving error.
I a also not so much familiar with composer to dig into myself without any guide.
So is there any way so I can use both libraries at the same time?
Tip: Packages without a vendor namespace are a bad practice, as you can see here. I recommend creating an issue for both packages saying they should really add a vendor namespace.
The problem here is that as soon as you use Form in your code, the class isn't already loaded and Composer's autoloader is executed. As it has 2 packages to load the class from, it'll pick the first registered autoload rule. This results in the wrong Form class: Problem!
You can swap the packages position in your composer.json, but this means the other class is no longer usable.
Another solution is to require the class yourself by using the require()/require_once() PHP functions. This is a bad practice and also means you can only use one of the 2 Form classes (requiring the other form class after one is already required results in a "Class with name "Form" already exists" PHP error).
TL;DR: You can only use one of the 2 packages in the same application.
There is really no shortage of form validation libraries. Every single framework should have one component for this.
So I'd recommend selecting your libraries carefully.
We have here the first library "alterfw/php-form-generator", which is 4 years old, being unmaintained since then, until it got forked 4 months ago with adding composer.json. Four years ago, PHP 5.2 was still common, so it is no real surprise that this code has no namespace. It also has no real documentation, because the link in the readme file is dead. The forked repository of this library does not allow creating issues. :( I doubt that the upstream repository will care about anything after 4 years of not maintaining it.
The second library "rlanvin/php-form" seems to be tied to non-public code. You opened a ticket to add namespace to that one class, and effectively got rejected (saying that the maintainer will not add namespaces because it is more convenient for him, but you could edit the file yourself to add it simply does not cut it). Packagist shows that this library has 31 installs. It's not completely right to say that "nobody uses this code", but it is very close.
If your task is form validation and form generation, I'd say that either the Symfony or Zend components will likely perform that task very well. There probably is no need to resort to libraries that "nobody" uses, and that do not apply modern development methods like namespaces (available since PHP 5.3, which was released in 2009).
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.
I know this is highly unlikely but thought I would ask anyway.
I am using DomPdf to render pdfs.
Currently it does not implement namespaces and loads a lot of classes.
I can autoload the library with composer and "classmap": ["include/"].
Is it in any way possible to autoload this library implementing a custom namespace in order to avoid possible class name conflicts?
Or is there a tool to search and replace in a library to add namespaces?
I would prefer not to touch the library and was just wondering if there is some way this could be done with composer's autoloader.
(I don't currently have conflicts but would like to keep my libs from running into future issues by implementing namespaces wherever I can.)
Conflicts would arise because of two classes having the same name, the same (or absent) namespace, but reside in different files (and paths) and contain different code.
Composer autoloading cannot do anything about this.
If you come into this situation, you have to resolve it on the code level first, i.e. you have to rename one of the classes, probably moving it into a namespace and keeping it's name as a quick help. Effectively renaming it means to fix every other line of code that has references to the old class.
Fortunately this will only happen if you try to include new code into your project, so you'd be able to stop using whatever you started importing, and look around for an alternative instead.
I have created a handler class that derives from AbstractProcessingHandler. I've seen that I can put it in src/MyNamespace/MyBundle/Monolog/, but it worries me a bit because this handler is used in several others bundles where I log data. So the other bundles will need MyBundle to work properly, only because of this handler.
I tried to put my handler class in lib/ but it does not seem to work (maybe I have to do something special with Autoload?).
Or should I create a new bundle specifically for this handler?
Edit: I can't really place my custom handler class in vendor/monolog/monolog/src/Monolog/Handler because then I would not be able to add it to my git repository: there is a conflict because this folder is managed by another git repository (created by Composer)
On Monolog's end there is really no restriction on where to put it or how you call it. The key is only that it implements monolog's HandlerInterface or extends from one of the existing handlers.
Now it depends what your handler is, if it's generic stuff that other people could use you could submit it as a pull request to monolog.
If not, you can either create an own composer package for it, or put it in src/Acme/Monolog/FooHandler or something like that, so it stays in your application but is clearly out of a bundle. The downside is that you need to configure it as a service in one of your bundles, so you still have some sort of dependency on a bundle there.
Maybe having it as its own bundle would make sense then. But it's quite a lot of boilerplate for just one class.
If all your bundles are application specific and very unlikely to be extracted out of it, having cross-bundles dependencies is fine though IMO.
The dependency is anyway not very strong since one bundle could contain the handler and configure it. The other bundles can still log to monolog, even if the handler isn't present, they can log. It just won't go to that specific handler. Nothing should break.
As you see, it's just a lot of trade-offs, and it's hard to say which solution is the most fitting without knowing more about your project.
If you want to have your handler class in lib/ you will need to add the lib/ folder to your composer.json autoload section. For example:
"autoload": {
"psr-0": { "": ["src/", "lib/"] }
}
Take a look at the Composer documentation:
Basic Usage
Autoload
I think the common approach here is to use a "Bridge" dir in your Bundle with a clear dependency. If you have other bundles that rely on this, what we've done is create a ServiceBundle which is basically for all shared services across all bundles within the application. This might not work well for you if you have plans of distributing this bundle, but may otherwise.
I played with the zf2-tutorial successfully, but I was totally confused when trying to integrate an external library like "jpgraph". I know I must do this with autoload or servicemanager but it won't work.
The php-files of jpgraph are in the vendor/graph directory. I use a module called Jpgraph, in the controller indexAction I try:
$graph = new Graph($width,$height);
this gives me an error:
Fatal error: Class 'Jpgraph\Controller\Graph' not found in ...
the jpgraph library don't use namespaces.
i also tried this way without success
what's the best way to integrate such things?
I would be glad for every tip or help
Add the library to your composer.json and add the class with Classmap and/or the include path as phpunit does
https://github.com/sebastianbergmann/phpunit/blob/master/composer.json#L48
One option, as Maks3w pointed out, is to use Composer. If you've never heard of or used composer before it's definitely worth a look. I was surprised how easy it was to set up and use 3rd party libraries. It's also very easy to set up your own library to work with composer, and use any source controlled (git or svn) library of your own - works well with GitHub repos - just add a composer.json file.
On the other hand, you do not need to use composer to do what you want, it would make it very easy, but it may be overkill. Zend Framework 2 has a very flexible autoloader system, and although it works well with PSR-0, you can have any class autoloading sytem that you like. Take a look at the different components of Zend\Loader, in particular I think the ClassMapAutoloader will be the one to suit your needs.