Symfony console application: dependency injection [duplicate] - php

This question already has an answer here:
How to use DependencyInjection from symfony in stand alone application with commands?
(1 answer)
Closed last year.
A Symfony novice here. After reading some of the Symfony documentation and some answers here at SO, I am now almost completely confused.
I am trying to use the console application component and create a small db-aware console application.
Many people state that in order to use Symfony's DI features it would be enough to inherit my command class not from Symfony\Component\Console\Command\Command but from ContainerAwareCommand.
However when I try this I get a Method Not Found error on an application::getKernel() call.
I have a feeling that DI features are in fact not available in a console application based on the console component. Is there another kind of Symfony console application, for example, based on the full-blown framework?
I very much like the simple framework provided by the console component Symfony\Component\Console\Application. But the question is then - what to do for dependency injection and DBAL? All examples that I find seem to refer to the full Symfony framework and get me just all the more stuck.

Just a quick update on my progress if anybody stumbles upon the same problems.
I incorporated into my project the PHP-DI dependency injection framework, which seems to be working fairly well with no configuration (so far) - it figures out quite a lot by reflection, actually.
The same way, Doctrine\DBAL is included as a standalone library (I opted against the O/RM part of it, as it is really a tiny project and I'm on a much firmer ground with SQL than anything else) and the connection is simply returned by a connection provider which is injected wherever needed by the DI.
One thing I couldn't figure out is how to have the command classes instantiated by the DI library without my help, so I actually had to inject the container itself into my overridden application class and override the getDefaultCommands() where I then pull the instances out of the container manually. Not ideal but will have to do for now.

If your command extends ContainerAwareCommand
...
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
...
class MyCommand extends ContainerAwareCommand
{
The DI container is available with the getContainer() method. (like in a standard controller), ex:
$this->validator = $this->getContainer()->get('validator');

I don't know if your question is still relevant, but I have an answer as I stumbled across the same problem here.
You just have to create the kernel yourself and give it to the \Symfony\Bundle\FrameworkBundle\Console\Application that extends the basic \Symfony\Component\Console\Application.
<?php
// CronRun.php
require __DIR__.'/../../../../vendor/autoload.php';
require_once __DIR__.'/../../../../app/AppKernel.php';
$kernel = new AppKernel('prod', false);
$kernel->loadClassCache();
$application = new \Symfony\Bundle\FrameworkBundle\Console\Application($kernel);
$application->add(new \KingdomHall\TaskBundle\Command\CronCommand());
$input = new \Symfony\Component\Console\Input\StringInput('k:c:r');
$application->run($input);

You could use a solution I just pushed it to packagist.org. Includes full working symfony/dependency-injection. You're welcome to give it a shot. use composer to create your own project composer create-project coral-media/crune project_dir or just clone the repository.
https://packagist.org/packages/coral-media/crune
You only need to install DBAL dependencies (I don't suggest ORM if you don't really need it). Configure connection parameters in .env and just define a service to handle connection. That service can be injected in your Commands using public setMyService($myService) method with #required annotation. Also you could create a Connection class and bind is as parameter in your command constructor.The crune boilerplate also supports autowire and autoconfiguring features.

Related

Extending of Symfony container

is it possible overwrite/extend Symfony\Component\DependencyInjection\Container::get() method? I want automatic creating service, when it is not contain in container, but class of service exists.
For example:
Name of service is My.MyBundle.Model.FooRepository
Service with this name doesnt exists, but when i call:
$container->get('My.MyBundle.Model.FooRepository');
check class_exists for \My\MyBundle\Model\FooRepository and when its exists, add to container and return it. Dependencies of this new services will be resolve by kutny/autowiring-bundle.
This feature can be extended only for some namespaces or interfaces and in production enviroment can be cached, but for developing will be great helper.
Any idea?
This is not directly answering your question but maybe it's answering your need: if you want to have "auto-wiring" inside your Symfony project, you can use PHP-DI inside Symfony. PHP-DI is an alternative container that can do auto-wiring (which Symfony does not).
Have a look at the Symfony 2 integration documentation to see if it can fit your bill.

Dependency injection in a symfony console command? Not full Symfony application

I've seen this How can i inject dependencies to Symfony Console commands? but that answer doesn't really give enough information and is already explained here http://symfony.com/doc/current/cookbook/console/console_command.html
The problem is a containerAwareCommand doesn't work with the setup here http://symfony.com/doc/current/components/console/introduction.html
In order to use containerAwareCommand from what I can tell, I need my application to use
Symfony\Bundle\FrameworkBundle\Console\Application
instead of
Symfony\Component\Console\Application
But using the frameworkBundle Application class requires an instance of KernelInterface and won't allow me to pass in a name and version to my application.
Here is what I have that won't work with containerAwareCommands
#!/usr/bin/env php
<?php
require __DIR__.'/../src/vendor/autoload.php';
$app = new Symfony\Component\Console\Application('spud', '0.0.1');
$app->add(new Isimmons\Spudster\Console\Commands\SayHelloCommand);
$app->run();
The command it's self runs but I get an error when trying to use getContainer
Call to undefined method Symfony\Component\Console\Application::getKernel()
On a related topic which will probably come up next, The documentation for registering a class in the container shows using a app/config/config.php file. But I don't have an app directory since this is not a full symfony application. My base directory in which all of the app except for the file above is located, is src/lib. If I can figure out the first part above, will symfony be able to find the config file at src/lib/config/config.php?
You can use Consolefull application.
Consolefull is a simple library to work with Symfony Console Component and Symfony Dependency Injection Component

Can we use Symfony\Bundle\FrameworkBundle\Test\WebTestCase for symfony 2 console commands testing?

Using Symfony\Bundle\FrameworkBundle\Test\WebTestCase, we get easy access to container, entity manager etc. We can use it for functional testing by automatic manual HTTP requests.
Can we use it to test Symfony2 console commands as well so that we can have easy access to container and all services?
I want to test my costum Symfony2 console commands which uses many services which in turn uses doctrine entity manager to access data.
PHPunit documentation suggest to extend the test class with PHPUnit_Extensions_Database_TestCase,
Can we extend WebTestCase instead of test instead to test console commands ?
I have already refereed
How to test Doctrine Repositories Cookbook
How to test code that interacts with the Database Cookbook
The Console Component Docs
WebTestCase is meant for functional testing your web applications. Nothing will stop you from using it to test commands, but it doesn't feel right (hence your question).
Testing commands
Remember, that command tests (as well as controller tests) shouldn't be complex, just like the code you're putting in there shouldn't be complex either.
Treat your commands as controllers, make them slim and put your business logic where it belongs - to the model.
Accessing the container
Having said that, you can implement your own KernelAwareTestCase (or ContainerAwareTestCase) yourself. Here's a base class I'm using occasionally: jakzal / KernelAwareTest.php Gist
Also, note that next to Symfony\Component\Console\Application there's a Symfony\Bundle\FrameworkBundle\Console\Application which can actually work with the Symfony kernel.
Final note
Remember, that the most extensive testing should be done on a unit level.

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

How do I use Symfony's Doctrine model classes outside of Symfony?

Is there a way to use Doctrine using the model classes I've already setup for my Symfony applications without having to call Symfony with all that overhead?
This is more to satisfy a curiosity than anything else. For all the scripts I've used, I've just been able to instantiate Symfony (which typically turns out nice since I have all of the features that I'm used to working with on this particular project. But there has to be a way to load Doctrine and use the Symfony model classes without Symfony... Right?
Doctrine isn't dependet on symfony. Doctrine is a "framework" on its own. It has it's own autoloading and can therefore work with it's classes like a regular PHP app. You can integrate Doctrine with other frameworks if you want (like CodeIgniter or Zend). So you have every freedom you need without the need to do some tedious migration of your models/data/... from one system to another.
I've come to the conclusion there really isn't a way to use the model classes from Symfony elsewhere. With a little work, you can port over the classes to a new Doctrine model (even if you use the generator, since the main model class just extends the base which extends sfDoctrineRecord (from the API docs, you can see which functions will need to be removed).
Otherwise, there isn't a practical way of doing that.
Anytime I need to access the Symfony model, I'm making a task or plugin since I do typically need part of Symfony's functionality.
As far as Symfony2 goes, just looking at the documentation makes me want to run screaming. It's not mature in any form or fashion (but, then again, neither is Symfony "legacy"). So, I'm not sure if the process would be any easier there.

Categories