If I add a 3rd party bundle, say from Knp bundles for example, should I wrap it first or should I use it directly in my code?
If I decide to wrap it, where do I put the wrapping code? In a separate new bundle? In my application bundle?
To clarify:
I'm not asking about how to add a thirds party bundle to my project.
I'm not asking what a bundle is.
This question is aimed at encapsulating 3rd party code behind wrapper classes. Since the bundle was developed by a 3rd party developer it is a subject for unexpected changes that could break my code.
How do you wrap a 3rd party bundle after adding it to your project?
This is an answer for 3rd party bundles included via composer in Symfony2 in general, it does not refer to a special bundle.
First of all
As long as you are fixing the version of the requested bundle to a stable version (like 1.*) in your composer.json (and as long as the developer follows his own guide lines), you shouldn't have any problems with compatibility breaks of the interfaces, thus wrapping is not necessary.
But I'm assuming that you want to prevent any code breaks by throwing Exceptions in the wrapper code and/or implementing fallbacks, so that everything that uses the wrapper code could still work or at least display appropriate errors.
If you want to wrap
If you want to use the dev-master version of a given 3rd party bundle, major changes might occur. But there shouldn't be a case where you really want to include the dev-master when there are stable versions.
Anyway, there are two ways that I see, that could make sense in the case that you want to include the dev-master or want to wrap it to display errors, log them, catch exceptions etc.:
Build a single service class that uses all instances of the services of the 3rd party bundle
This service class could be in one of your bundles that uses the 3rd party bundle, there's no need for an extra bundle in this approach.
This way you have a single service like acme.thirdparty.client that wraps single method calls of other services. You would need to inject all 3rd party services that you need (or create instances of the desired sub classes) and wrap all desired method calls.
# src/Acme/MyBundle/Resources/config/services.yml
parameters:
acme.thirdparty.wrapper.class: Acme\MyBundle\Service\WrapperClass
services:
acme.thirdparty.wrapper:
class: %acme.thirdparty.wrapper.class%
arguments:
someService: #somevendor.somebundle.someservice
someOtherService: #somevendor.somebundle.someotherservice
And the service class:
<?php
namespace Acme\MyBundle\Service;
use SomeVendor\SomeBundle\SomeService\ConcreteService;
use SomeVendor\SomeBundle\SomeService\OtherConcreteService;
class WrapperClass
{
private $someService;
private $someOtherService;
public function __construct(ConcreteService $someService, OtherConcreteService $someOtherService)
{
$this->someService = $someService;
$this->someOtherService = $someOtherService;
}
/**
* #see SomeVendor\SomeBundle\SomeService\ConcreteService::someMethod
*/
public function someMethod($foo, $bar = null)
{
// Do stuff
return $this->someService->someMethod();
}
/**
* #see SomeVendor\SomeBundle\SomeService\ConcreteOtherService::someOtherMethod
*/
public function someOtherMethod($baz)
{
// Do stuff
return $this->someOtherService->someOtherMethod();
}
}
You could then add some error handling to those method calls (like catching all exceptions and log them etc.) and thus prevent any code outside of the service class to break. But needless to say, this does not prevent any unexpected behaviour of the 3rd party bundle.
or you could:
Create a bundle that has multiple services, each wrapping a single service of the 3rd party bundle
A whole bundle has the advantage of being more flexible on what you exactly want to wrap. You could wrap a whole service or just single repositories and replace the wrapped classes with your own ones. The DI container allows the overriding of injected classes, like the following:
# src/Acme/WrapperBundle/Resources/config/services.yml
parameters:
somevendor.somebundle.someservice.class: Acme\WrapperBundle\Service\WrapperClass
By overriding the class parameter somevendor.somebundle.someservice.class all services that use this class are now instances of Acme\WrapperBundle\Service\WrapperClass. This wrapper class could be either extending the base class:
<?php
namespace Acme\WrapperBundle\Service;
use SomeVendor\SomeBundle\SomeService\ConcreteService;
class WrapperClass extends ConcreteService
{
/**
* #see ConcreteService::someMethod
*/
public function someMethod($foo, $bar = null)
{
// Do stuff here
parent::someMethod($foo, $bar);
// And some more stuff here
}
}
... or could use an instance of the original class to wrap it:
<?php
namespace Acme\WrapperBundle\Service;
use SomeVendor\SomeBundle\SomeService\ConcreteServiceInterface;
use SomeVendor\SomeBundle\SomeService\ConcreteService;
class WrapperClass implements ConcreteServiceInterface
{
private $someService;
/**
* Note that this class should have the same constructor as the service.
* This could be achieved by implementing an interface
*/
public function __construct($foo, $bar)
{
$this->someService = new ConcreteService($foo, $bar);
}
/**
* #see ConcreteService::someMethod
*/
public function someMethod($foo, $bar = null)
{
// Do stuff here
$this->someService->someMethod($foo, $bar);
// And some more stuff here
}
}
Note that implementing an interface for a class that is overriding another one might be mandatory. Also the second one might not be the best idea, since then it's not very clear that you are actually wrapping the ConcreteService and not just replacing it. Also this is ignoring the whole idea of Dependency Injection.
This approach needs a lot more work and means a lot more testing, but if you want more flexibility, this is the way to go.
Perhaps there already are wrapper bundles for your desired 3rd party bundles around (like the SensioBuzzBundle for the Buzz Browser), in this case, you could porbably use those instead of writing everything yourself.
Conclusion
Trusting the developer and including a stable version (like 1.* for bugfixes and new features or 1.0.* for bugfixes only) is the way to go. If there are no stable versions or if you want to include the dev-master, wrapping is an option. If you want to wrap your code, building an extra bundle is the more flexible way, but a single service class could be enough if there's not much code to wrap.
The documentation for this bundle is available in the Resources/doc
directory of the bundle:
Read this it is easy to use.
add your bundle into /vendor/bundles
Add the following namespace entries to the registerNamespaces call in your autoloader:
// app/autoload.php
or Configure the bundle in
app/config/config.yml
Related
I'm testing with PHPSpec, and I've got custom matchers in my spec files that I don't want to have to repeat in every file in which they're used.
I want to be able to extend PHPSpec's behaviour and/or the behaviour of all my tests to use a global set of custom matchers.
The PHPSpec documentation shows how to create custom matchers (inline matchers):
http://phpspec.readthedocs.org/en/latest/cookbook/matchers.html#inline-matcher
I have this inline matcher (as an example) in my ThingImTestingSpec class:
public function getMatchers()
{
return [
'haveSecondLevelKey' => function ($subject, $key) {
foreach ($subject as $first_level_key => $second_level_array)
{
if (is_array($second_level_array))
{
return array_key_exists($key, $second_level_array);
}
}
return FALSE;
}
];
}
This inline matcher example detects whether an array has an array as one of its values, and returns true or false.
As far as I can tell, PHPSpec calls getMatchers() when it constructs ThingImTestingSpec, if a getMatchers() method is present (otherwise PHPSpec ends up calling the empty getMatchers() method on ObjectBehavior.
What I've tried:
Create a CustomMatchers class and namespace it:
namespace SpecUtilities;
class CustomMatchers
{
public static function getMatchers()
{ ... }
}
and add this to my spec file:
use SpecUtilities\CustomMatchers
and in the class itself:
function it_pulls_in_custom_matchers()
{
CustomMatchers::getMatchers();
}
but the return from getMatchers() when the tests are run doesn't get used for anything. PHPSpec only seems to be using the return from getMatchers() when it constructs the test (which makes sense - getMatchers() only returns an array of functions; it doesn't attach those functions to anything else, so PHPSpec isn't using them). I get the error
no haveSecondLevelKey([array:1]) matcher found for [array:14].
i.e. PHPSpec isn't loading the custom matchers.
All spec classes extend ObjectBehavior. I could add my getMatchers() function to PHPSpec's ObjectBehavior class, but I don't want to modify files under /vendor (PHPSpec is being pulled in using Composer). I could copy the vendor file and modify my own CustomObjectBehavior class, and make my spec classes extend that instead, but that will break the usability of PHPSpec's generator methods like phpspec describe SomeNewSpec (I'll have to change the class that new specs extend every time I generate a new spec).
Am I asking too much? Short of modifying ObjectBehavior itself to look for and load an external custom matchers file, and making a pull request for the PHPSpec repo itself, is there a way to load custom matchers without getting into bad practices?
I've used an extension "phpspec-matcher-loader-extension" for this purpose -- it's worked well for me. From the description:
Allows custom phpspec matchers to be registered globally via configuration
There are two ways to get the result you want:
a) Extend ObjectBehaviour and add a new default getMatchers, then extend your new class instead of ObjectBehaviour. You can use a custom template to ensure that describe then generates classes extending the right object (see how PhpSpec itself uses a custom template https://github.com/phpspec/phpspec/tree/master/.phpspec)
b) Write your Matchers as objects implementing PhpSpec\Matcher\MatcherInterface then write an Extension that registers your custom matchers with PhpSpec. This is more complex and requires some understanding of how Matchers are registered.
We're thinking about how to make this easier in future releases, maybe via some configuration settings.
According to Marco's Pivetta thoughts with this, this old question
and my answer to an other question
I was interrogating myself about the better way to use our Services in Zend Framework 2 application.
Actually we can use the ServiceLocatorAwareInterface combined with ServiceLocatorAwareTrait.
With the fact In ZF3 service locator will be removed in controller It may be possible that they will also remove this interface, or advice people not using it, it make sense.
The only way I see how our Services may be constructed is :
Don't use ServiceLocator in your Services, use DependancyInjection.
The problem is :
Some project are just so big that you have either :
15 services's class for one workflow.
A service's class with 15 Dependancies.
Pick your nightmare...
Some example for what you may need in a service :
Get back the formManager (you can't call it in the controller)
You may need to get your ViewRenderer to render template before returning an HTML string to the view through AJAX, and JSON response;
You may need to get back the translator or every service you want provided by ZF2
Get your entity Manager, if you have multiple database, add count here
Get others service like MailService, ExportService, ImportService and so on...
If you have to load specifics services depends on a client (multi-client website in BtoB... add somes services, because you can't load | call an AbstractFactory)
Maybe for some of those points, they're can be solved by a tricks that I don't know.
My Question is :
Is it a good practise to have 15 or more Dependancies for one service
and give up the ServiceLocator, in controllers, but also in services ?
Edit from comments
For illustrate my point, I paste one of my constructor :
public function __construct(
ToolboxService $toolboxService,
EntityService $entityService,
UserService $userService,
ItemService $itemService,
CriteriaService $criteriaService,
Import $import,
Export $export,
PhpRenderer $renderer
) {
$this->toolboxService = $toolboxService;
$this->entityService = $entityService;
$this->userService = $userService;
$this->emOld = $this->toolboxService->getEmOld();
$this->emNew = $this->toolboxService->getEmNew();
$this->serviceLocator = $this->toolboxService->getServiceLocator();
$this->itemService = $itemService;
$this->criteriaService = $criteriaService;
$this->import = $import;
$this->export = $export;
$this->renderer = $renderer;
$this->formManager = $this->toolboxService->getFormManager();
}
As you can see, ToolboxService is an object with multiple dependancies itself. This Service is in my Application folder, and almost everywhere.
I have 2 entity Managers (connection to 2 databases, but maybe soon, i will need a third one...)
You can see that I use the serviceLocator throught a dependancy, so this service doesn't implements ServiceLocatorAwareInterface. If I'm not using it, i'm literraly screwed for my AbstractFactory call with
// Distribute somes orders depends on Clients
$distributionClass = $this->serviceLocator->get(ucfirst($param->type));
if ($distributionClass instanceof DistributeInterface) {
$distributionClass->distribute($orders, $key);
} else {
throw new \RuntimeException("invalid_type_provided", 1);
}
Let's say you would inject the ServiceLocator instance. There is no guarantee that the ServiceLocator actually holds your hard dependencies, thus breaking the DI pattern. When using constructor dependency injection you are sure that all the services that are needed are really available. If not, the constructing of the service will simply fail.
When using a ServiceLocator you will end up in an instantiated service class where hard dependencies might or might not be available through the ServiceLocator. This means you have to write all kind of additional logic (check dependencies, throw exceptions) in case the dependency cannot be resolved from the ServiceLocator instance the moment you ask for it. Writing all this code will probably be much more work then injecting 15 dependencies and on top of that the logic will be cluttered all over your service.
Additionally you would still need to add all the setter and getter methods to be able to get your services from your ServiceLocator and to make your service testable.
IMHO injecting 15 dependencies is less code and easier to maintain then injecting a ServiceLocator instance.
I'm making my own primitive MVC framework with PHP, and I'm wondering where I should load/instantiate corresponding controller dependencies?
In the constructor of each controller (tightly coupled) or inject them (loosely coupled)?
The only part of the latter that I'm not too sure of is for the dependencies to be instantiated on bootstrap level, outside of the MVC paradigm, before being injected. Not every controller uses the exact same dependencies besides the default parent ones. I would have to instantiate them all, which would also create a lot of overhead.
I've seen some existing frameworks do it like $this->load->model('model'); // CodeIgniter in the constructor, but I have no clue on why they're doing it like that.
I would suggest you inject the dependencies, so your controllers are less coupled to your framework. This will make a switch to another framework easier.
About instantiating dependencies: I suggest you use (or implement) a dependency injection container. This container should contain factories that can instantiate services.
In an ideal situation your controllers are services too (meaning they too have factories in the dependency injection container).
This way only the controller you need for a particular request will be instantiated, and therefor only its dependencies are instantiated.
When building you own framework, this means that after the routing phase (when the correct controller is known), the framework should grab that controller from the container. The container itself will make sure all dependencies that are needed will be provided.
Have a look at Pimple for an example of a simple dependency injection container.
PS: That line from CodeIgniter looks a lot like the service locator pattern. This pattern is similar to dependency injection, but does not provide full inversion of control.
Q: Where should i load/instantiate corresponding controller dependencies?
There are multiple ways.
The load and instantiation concepts are basically "before/outside" and "after/inside".
Before and outside means, that you load the file containing a class (which you want to instantiate and pass to the controller), before you load the controller.
But how do you know, what the controller needs, before loading the controller? Uh..
Dependency Description Files
A description file comes into play, describing the wiring between your controller and it's dependencies. In other words, you can see the dependencies of your controller by looking at it's dependency description file. This concept is often used by Dependency Injection tools, which analyze the object and pull the dependencies names out automatically. It's also possible to maintain such a wiring configuration file manually. But it's tedious.
Service Locator
A Service Locator is a instantiation helper for dependencies.
Basically, it contains the same information like a dependency description file, but this time in form of a registry. The link between parts of your application becomes this registry.
Both strategies introduce overhead. It's a trade-off. When you change the perspective and look at things from an application with maybe 500+ classes, then you realize that a dependency injection tool is sometimes worth it.
Manual Injection
via Constructor Injection.
After and inside means, that you load the file containing your controller and then start to care about the dependencies.
At this point the class is not instantiated, yet, but the autoloader might do it's dirty deeds behind the scene. He evaluates the use statements at the top of your controller file. The use statements declare namespaced classes, which the autoloader resolves to actuall files and loads them. You might then start to use these classes as dependencies in your controller. This is probably the easiest way to solve your problem and i strongly suggest looking into the topics autoloading with namespaces and use-statements.
When the class is instantiated, you have the following possiblities:
use might use Setter Injection or Reference Injection to set the dependencies to the object. This requires that your Constructor Dependencies are already solved or your constructor is empty.
It's possible to combine these strategies.
Q: What does this do $this->load->model('model'); // CodeIgniter?
CodeIgniter is a legacy application framework. It was created in times, when namespaced autoloading wasn't available. $this->load is a basic class loading helper. This is the opposite of an "auto"loader, (which surprise, surprise) loads things automatically.
CodeIgniters loader class is used to load various other classes, like libraries or files from the view, helpers, models or user defined stuff. This is again the concept of a registry. Here the registry just knowns where things are in your application layout and resolves them. So $this->load->model('model'); means that the modelfunction must have some piecies of information, about the position of model files in your application.
You provide a model name and the path for the file is constructed by model.
And this is exaclty what it does (except a bit of overhead): https://github.com/EllisLab/CodeIgniter/blob/develop/system/core/Loader.php#L223.
Since I'm a Symfony developer, I can only give you a reference to Symfony.
I think you should do like they are doing in Symfony by thinking about what you need in each
Controller object.
At least, you need :
a Request object
and a Model loader object that gives you every Model you need.
Create a BaseController that implements these few functions and then extend it with custom Controllers.
You can also take a look on Silex : http://silex.sensiolabs.org/ a Micro Framework
Hope it helps.
When do you say "In the constructor" you mean to pass in the conatiner and pull the dependencies from them (in the constructor)?
<?php
class SomeController
{
public function __construct($container)
{
$this->service1 = $contanier->get('service1);
}
//...
}
I advice against that, though simpler and easier you will be coupling your controllers to the container thus using a ServiceLocator instead of truly inversion of control.
If you want your controllers to be easy unit-testable you should use inversion of control:
class SomeController
{
public function __construct($service1)
{
$this->service1 = $service1;
}
//...
}
And you can even create your controller as a service inside the container:
// this uses Pimple notation, I hope you get the point
$container['controller'] = function($c) {
return SomeController($c['service1']);
}
Use proxy services to lazy load them
Also if your controllers needs more than some services and you won't be using all of them you can:
1) Use proxy services in order to lazy load the service only when they are really needed
<?php
class ProxyService
{
/**
* #var Service1Type
*/
private $actualService;
public function __construct()
{
$this->actualService = null;
}
private function initialize()
{
$this->actualService = new Service1(); // This operation may take some time thus we deferred as long as possible
}
private function isInitialized()
{
return $this->actualService === null;
}
public function someActionOnThisService()
{
if (!$this->isInitalized()) {
$this->initalize();
}
$this->actualService->someActionOnThisService();
}
There you have a simple proxy object with lazy loading. You may want to check the fantastic Proxy Manager Library if you want to go that route
2) Split your controller
If your contoller has too many dependencies, you may want to split it.
In fact you may want to read the proposal by Paul M. Jones (lead developer of Aura Framework) about MVC-Refinement, IMHO is a good read even though you may not fully agree with it.
Even if you split your controller in order to reduce the dependencies, lazy loading your dependencies is a good idea (obviously you'll have to check weather if its doable in your context: more work in order to gain more speed).
Maybe you need to define __autoload() function before you try to load the Classes which is not loaded yet. Like:
function __autoload($className) {
require "/path/to/the/class/file/$className.php";
}
My example is very very simple to auto require the file which the class definition is in.
You can also use if-else statement or switch statement in that function to fit your own situations smartly.
The __autoload() function is called when PHP doesn't find the class definition, works for new, class_exists(), call_user_method(), etc, and absolutely for your dependences/parents classes. If there is still no class definition after __autoload() is called, PHP will generate an error.
Or you can use spl_autoload_register() function instead of __autoload() more gracefully.
For more information, you might want to see:
http://php.net/manual/en/function.autoload.php
http://php.net/manual/en/function.spl-autoload-register.php
First of all, sorry for my bad English, I hope you understand what I'm saying.
Here is my problem:
Lets assume i have an MVC application including standard router, controller, model(service) layer and some kind of db connector.
Model layer depends on a db connector, controllers depends on models/services and the top-level "application" class depends on routers and controllers.
My object hierarchy looks like this:
App -> ControllerFactory -> ServiceFactory -> DAO -> DbConnection
Perhaps, written above doesn't look like best application architecture ever, but i want to focus on the other thing:
When i'm trying to instantiate an App class i should pass all dependencies to the class instantiated; class dependencies, in turn, has their own dependencies and so on.
As a result I get all hierarchy stack instantiated at once. But what if i dont need to access the database in some cases; what if some controllers are used for rendering static templates without model interaction?
I mean, what if there are some special cases when class does not require its own dependencies(and in some cases it does)? Should i inject dependencies conditionaly or something?
I'm really stuck at this point and i don't know what to do.
Update: after re-reading carefully your question, here is another advice: yes, every class has different dependencies.
Don't inject every object into every other object. For example, some services might need DAOs, so inject them. But if a service doesn't need a DAO, don't inject any DAO.
The rest of my answer is valid if you have (for example) a service that needs a DAO (and thus a DB connection) not for every method.
What you may be looking for is lazy injection.
It is the act of injecting a dependency not loaded, so that the object is loaded only if/when used.
In conrete terms, that means injecting a proxy object, that would look like and behave exactly like the original object (for example, the db connection).
Several DI container (frameworks) support this so you don't have to create proxies yourself. I'll take as an example PHP-DI (I work on that project FYI).
Here is an example using annotations:
use DI\Annotation\Inject;
class Example {
/**
* #Inject(lazy=true)
* #var My\Class
*/
protected $property;
/**
* #Inject({ "param1" = {"lazy"=true} })
*/
public function method(My\Class $param1) {
}
}
Of course if you don't want to use annotations you can use any other configuration you want (PHP, YAML, …). Here is the same example by configuring the container in pure PHP:
$container->set('Example')
->withProperty('property', 'My\Class', true)
->withMethod('method', array('param1' => array(
'name' => 'My\Class',
'lazy' => true,
)));
See more in the documentation about Lazy Injection.
Note: you may not be using a Container for now (and that's not a problem), but for tackling lazy injection this is a fair amount of work and you might need to start considering using one.
If your dependency construction is complex, simply add a new factory class that should contain all the logic to create a correct object for you.
class AppFactory(){
__construct(all params){
}
build(useDB=true){
// logic to build
if(useDB){
App = new App(new ControllerFactory(new ServiceFactory(new DAO(new DbConnection(params)))))
} else {
App = new App(new ControllerFactory(new ServiceFactory(null))))
}
return App;
}
}
I have a case where I need to reuse common doctrine entities across multiple applications (that reside within the same project). These applications are merely instances of information system used by corresponding institutions.
I've isolated all entities and repositories into separate bundle and that worked like a charm so far. Here's the catch: I have received a requirement that only some of these instances need to support some other features. Modification would include adding new attributed/relations to some of entities.
Here is the brief example:
We have a university which has number of faculty units (instances, that is). Information system was built to support only bachelor studies program but a month ago we received requirement to support specialization and master studies as well. They want to handle all the them thought the same application instance. This applies only to some of these instances.
The question: Is there any way to "override" affected entities while keeping functionality of original ones? Can I override entity configuration (YAML or annotation, not important), at all? I would really like to keep the code base and not to copy all the entities/repositories to another package...
You can override classes metadata on entities loading by catching an event.
EventListener
<?php
namespace Lol\RandomBundle\EventListener;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
class ClassMetadataListener
{
/**
* Run when Doctrine ORM metadata is loaded.
*
* #param LoadClassMetadataEventArgs $eventArgs
*/
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
$classMetadata = $eventArgs->getClassMetadata();
// Override User class to flag MappedSuperclass.
if ('AnotherLol\AnotherRandomBundle\Entity\User' === $classMetadata->name) {
// Do whatever you want...
$classMetadata->isMappedSuperclass = true;
}
}
}
Services configuration
services:
lol.random.listener.class_metadata:
class: Lol\RandomBundle\EventListener\ClassMetadataListener
tags:
- { name: doctrine.event_listener, event: loadClassMetadata }
Sympatch provides tools to override any code part of your Symfony2 project, including entities, without destroying the code base. See https://github.com/DHorchler/SympatchBundle.
I don't know what this means. Looks like it is possible but not documented yet. I don't whether the documentation or the code is in progress.
In this issue, stof suggests it is not possible at all.
I think you should use SCM branches for this.