I use Doctrine and try to use [DependencyInjection Component][1] without Symfony (outside of a Symfony application).
I have [bootstrap.php for doctrine][2]:
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
require_once "vendor/autoload.php";
$isDevMode = false;
$paths = ["src/Project/Infrastructure/Persistence/Doctrine/Mapping/"];
$config = Setup::createXMLMetadataConfiguration($paths, $isDevMode);
$dbParams = array(
'driver' => 'pdo_mysql',
'user' => 'root',
'password' => 'root',
'dbname' => 'project',
);
$entityManager = EntityManager::create($dbParams, $config);
And I have a file to configure the container:
$containerBuilder = new ContainerBuilder();
$loader = new XmlFileLoader($containerBuilder, new FileLocator(__DIR__));
$loader->load(dirname(__DIR__) . '/config/services.xml');
And I want to get EntityManager from container such as:
$entityManager = $containerBuilder->get('doctrine.orm.entity_manager')->getManager();
But what should I do here I don't understand:
//config/services.xml
<services>
<defaults autowire="true" autoconfigure="true"/>
<service id="Doctrine\ORM\EntityManagerInterface" alias="doctrine.orm.entity_manager" public="false" />
</services>
How I can register EntityManager as a service? (I don't use Symfony just DI component)
[1]: https://symfony.com/doc/current/components/dependency_injection.html
[2]: https://www.doctrine-project.org/projects/doctrine-orm/en/2.8/reference/configuration.html#obtaining-an-entitymanager
This is basically a 'how do I use the DI component without reading the documentation' sort of question. But it is kind of interesting so here are some hints.
You need to configure a Doctrine configuration service and then inject it into the entity manager service. Both services use a static factory method so something like:
parameters:
isDevMode: true
services:
doctrine.orm.config:
public: false
class: 'Doctrine\ORM\Configuration'
factory:
- 'Doctrine\ORM\Tools\Setup'
- 'createYAMLMetadataConfiguration'
arguments:
- ['src/Entity']
- '%isDevMode%'
doctrine.orm.entity_manager:
public: true
class: 'Doctrine\ORM\EntityManager'
factory:
- 'Doctrine\ORM\EntityManager'
- 'create'
arguments:
-
driver: 'pdo_mysql'
user: db_user
password: db_password
dbname: db_name
- '#doctrine.orm.config'
I used yaml here because it's easier for me to understand. You of course can convert to xml. You never want to check in your database credentials but I'll leave that for the student to figure out. This is the sort of thing that the Doctrine bundle deals with and is why you should probably use the framework.
The test application looks like:
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
require_once 'vendor/autoload.php';
$container = new ContainerBuilder();
$loader = new YamlFileLoader($container, new FileLocator(__DIR__));
$loader->load('config/services.yaml');
$container->compile();
$em = $container->get('doctrine.orm.entity_manager');
echo get_class($em) . "\n";
I tested it and it all works.
Enjoy.
Related
i have this code to run schema update command from controller i got help from symfony document
i have this code:
namespace AdminBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class DefaultController extends Controller
{
/**
* #Route("/admin")
*/
public function indexAction(KernelInterface $kernel)
{
$application = new Application($kernal);
$input = new ArrayInput(array(
'command' => 'doctrine:schema:update'
));
$output = new NullOutput();
$application->run($input, $output);
return new Response("");
}
}
it's not work for me i get this error after open this url (http://127.0.0.1:8000/admin):
Controller "AdminBundle\Controller\DefaultController::indexAction()" requires that you provide a value for the "$kernel" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or because there is a non optional argument after this one.
how can i do?
Instead of injecting the KernelInterface $kernel directly into your action (I guess, you're not using it as a declared service), call your container directly for asking the kernel:
public function indexAction()
{
$kernel = $this->get('kernel');
$application = new Application($kernel); // btw: you have an typo in here ($kernal vs $kernel)
$input = new ArrayInput(array(
'command' => 'doctrine:schema:update'
));
$output = new NullOutput();
$application->run($input, $output);
// tip: use "204 No Content" to indicate "It's successful, and empty"
return new Response("", 204);
}
While Michael's answer works, it is not the preferred method in Symfony 3.3, which had several changes to dependency injection. Your code will actually work just fine with some changes to your services configuration.
As the documentation states, the Dependency Injection Container changed in Symfony 3.3, and by default your controllers are registered as services:
# app/config/services.yml
services:
# ...
# controllers are imported separately to make sure they're public
# and have a tag that allows actions to type-hint services
AppBundle\Controller\:
resource: '../../src/AppBundle/Controller'
public: true
tags: ['controller.service_arguments']
This allows you to autowire the kernel through arguments in your controller action method, like you tried. The reason yours isn't working is because your AdminBundle is likely not set up the way your AppBundle is by default in app/config/services.yml. To truly solve the issue in the way that Symfony 3.3 wants, you should add AdminBundle to your services configuration like so:
# app/config/services.yml
services:
# add this below your AppBundle\Controller definition
AdminBundle\Controller\:
resource: '../../src/AdminBundle/Controller'
public: true
tags: ['controller.service_arguments']
With that, you no longer have to call $this->get('kernel');, and your original code will work as you have it, with KernelInterface as a parameter to your action method.
Furthermore, you can extend the new AbstractController instead of the regular Controller, and then calls to $this->get() will not work anymore, which is the way Symfony is going.
So again while Michael's answer will work just fine, I would advise you to implement the answer I've given simply because Symfony 3.3 prefers that method going forward.
I'm using symfony 2.3 version and I want to configure two different from_email in fos_user configuration how is it possible and where to set my configuration.
I want to send welcome email after registration normal user using normaluser#gmail.com and send addition user welcome email using additionaluser#gmail.com
Plz suggest any solution.
You can do it by Using A Custom Mailer.
Create a custom service
Example:
<?php
namespace AppBundle\Mailer;
// implement all the needed methods
class CustomMailer implements MailerInterface
{
public function sendConfirmationEmailMessage(UserInterface $user)
{
$template = $this->parameters['confirmation.template'];
$url = $this->router->generate('fos_user_registration_confirm', array('token' => $user->getConfirmationToken()), UrlGeneratorInterface::ABSOLUTE_URL);
$rendered = $this->templating->render($template, array(
'user' => $user,
'confirmationUrl' => $url,
));
// implement the logic that decides which from_email to use
// change the from_email accordingly
$this->sendEmailMessage($rendered, $this->parameters['from_email']['confirmation'], (string) $user->getEmail());
}
}
and update the fos_user configuration to use your custom mailer
fos_user:
# ...
service:
mailer: app.custom_fos_user_mailer
Reference links:
http://symfony.com/doc/current/bundles/FOSUserBundle/emails.html#using-a-custom-mailer
https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Mailer/Mailer.php
am creating own framework based on Sf2 commponents and i try to create router service.
I i need that service for generateUrl() method
protected function generateUrl($route, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH)
{
return $this->get('router')->generate($route, $parameters, $referenceType);
}
I try this
$container = new ContainerBuilder();
$container->setDefinition('router_loader', new Definition('Symfony\Component\Config\Loader\LoaderInterface'));
$container->setDefinition('router', new Definition('Symfony\Component\Routing\Router', array()));
And when i execute in my methodAction
$this->generateUrl('home');
he return me:
Catchable fatal error: Argument 1 passed to
Symfony\Component\Routing\Router::__construct() must be an instance of
Symfony\Component\Config\Loader\LoaderInterface, none given in
D:\xampp\htdocs\my_fw\vendor\symfony\routing\Router.php on line 95
looking on router constructor i see. I need that interface
public function __construct(LoaderInterface $loader, $resource, array $options = array(), RequestContext $context = null, LoggerInterface $logger = null)
how to avoid that implementation in service?
**New update:** routing.php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
// Routing
$routes = new RouteCollection();
// Home
$routes->add('home', new Route('/', array(
'_controller' => 'MyCompany\\Controller\\HomeController::indexAction',
)));
You are having this error because you are configuring the router service with no service definition the service definition should have your service arguments which is the source of your error because the container try to create the router with no arguments check this
For better use you can configure the router service in the service.yml/.xml file
Edit: The documentation page for the Routing component has detailed setup instructions
Try injecting the router_loader service as an argument into the router service. For this case you have to use the Symfony\Component\DependencyInjection\Reference class.
Routes have to be configured with a config file when using the all in one Router class. You have to use a FileLocator and a real Loader class, like the YamlFileLoader, you can't just use the interface (services generally can't be interfaces in Symfony).
The service container setup for the router service should look like this:
use Symfony\Component\DependencyInjection\Reference;
// Loads config files from the current directory, change this to
// your liking, or add more than one path
$container->setDefinition('router_config_locator', new Definition(
'Symfony\Component\Config\FileLocator', [[__DIR__]]
));
$container->setDefinition('router_loader', new Definition(
'Symfony\Component\DependencyInjection\Loader\YamlFileLoader', [
new Reference('router_config_locator'),
]
));
$container->setDefinition('router',
new Definition('Symfony\Component\Routing\Router', array(
'loader' => new Reference('router_loader'),
// Definition of routes in Yaml form
'resource' => 'routes.yml',
))
);
The routes.yml file contains your route definitions:
home:
path: /home
defaults: {_controller: "MyController:index"}
Also have a look at this documentation page about setting up the routing component, which also talks about setting up the routing without the all in one class and config file.
im trying to make a simple custom repository in order to understand how elastic search repository works. the documentation is pretty straight forward but i still dont understand how it works, im getting this error ´The service definition "fos_elastica.manager" does not exist.´. so far i think my problem is in the controller since i dont understand how to intialize them, also i would like to know if im in the right way in my configuration of the custom repository and the simple query i made.
im getting this error with this configuration whenever i try to make a search,
The service definition "fos_elastica.manager" does not exist.
this is my configuration so far:
//app/config.yml
fos_elastica:
clients:
default: { host: localhost, port: 9200 }
indexes:
sava:
client: default
types:
blog:
mappings:
id:
type: integer
body : ~
title : ~
tags: ~
persistence:
identifier: id
driver: orm
model: sava\BlogBundle\Entity\TblPost
finder: ~
provider: ~
listener: ~
repository: sava\BlogBundle\SearchRepository\TblPostRepository
this is my controller action:
namespace sava\BlogBundle\Controller;
//custom querys
use FOS\ElasticaBundle\Manager\RepositoryManager;
use FOS\ElasticaBundle\Repository;
//
use Symfony\Component\DependencyInjection\ContainerBuilder;
class TblPostController extends Controller
{
public function getPostAction(Request $request)
{
$container = new ContainerBuilder();
$repositoryManager = $container->get('fos_elastica.manager');
$repository = $repositoryManager->getRepository('BlogBundle:TblPost');
$items2 = $repository->matchExact($categoria,$searchQuery );
return $this->render('savaBlogBundle:TblPost:index.html.twig', array(
'results' => $items2, 'entities' => $items2
));
}
this is my post repository:
<?php
namespace sava\BlogBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use FOS\ElasticaBundle\Repository;
class TblPostRepository extends FOS\ElasticaBundle\Repository
{
public function matchExact($campo, $searchQuery) {
//$finder = $this->get('fos_elastica.finder.sava.blog');
$query = new Query();
if($searchQuery=='')
{
$innerQuery = new Query\MatchAll();
}
else{
$innerQuery = new Query\Match();
$innerQuery->setField( $campo , array('query' => $searchQuery));
}
$query->setQuery($innerQuery);
$query->setSize(1000000);
$query->setExplain(true);
return $this->find($query);
}
}
and since im using yml this is my tblpost.orm, i did generate my entities.
whenever i do the get postaction it throws me that it cant find the container, and i dont see an example in how to properly intiaze it, also is this is how you make a custom query?
EDIT 1:
so i changed this:
$container = new ContainerBuilder();
$repositoryManager = $container->get('fos_elastica.manager');
to this:
$elastica = $this->container->get('fos_elastica.manager');// single entry point, no fancy services
$SearchRepository = $elastica->getRepository('savaBlogBundle:TblPostRepository');// single type
and im getting this error:
No search finder configured for sava\BlogBundle\Entity\TblPostRepository
I've just had the same issue, the soultion is that instead of savaBlogBundle:TblPostRepository you should use your entity, for example:
$SearchRepository = $elastica->getRepository('savaBlogBundle:TblPost`)
According your fatal error in title of the issue enter link description here
The main problem why did you get that mistake is that, you assigned the same TblPostRepository in (doctrine config for entity) and in fos_elastica.
Disclaimer: I'm slowly starting to get into Symfony and still have some problems understanding how the architecture works.
Currently I set up different Bundles (Services, right?) that should deliver different output for different routes. So far I got around adding a simple Twig template that loads stylesheets and scripts via Assetics and Twig-blocks. Now I added another Bundle that queries data via Buzz from a remote location, which worked fine as a standalone script, but I don't get around printing output in a Twig template.
The architecture of the original script is like the following (names made more generic):
Vendors - abstract class that serves as base for all remote request Bundles.
ServiceABC - abstract class that extends Vendors and defines Error handling and output preparation for the ABC service.
ClientXYZ - final class that extends Service_ABC, defines output parsing and normalization of the returned data.
This Bundle got a services.yml file:
# ~/MyApp/Bundle/ServiceABCBundle/Resources/config/services.yml
parameters:
service_abc_manager.class: MyApp\Bundle\ServiceABCBundle\Models\Service_ABC
location_manager.class: MyApp\Bundle\ServiceABCBundle\Models\Clients\ClientLocation
monitor_manager.class: MyApp\Bundle\ServiceABCBundle\Models\Clients\ClientMonitor
services:
service_abc_manager:
abstract: true
location_manager:
class: %location_manager.class%
parent: service_abc_manager
monitor_manager:
class: %monitor_manager.class%
parent: service_abc_manager
Names changed for easier reference - Typos by accident possible.
Now my problem/question is, that I don't really get behind the Symfony2 concept of how to get the output into the template.
namespace MyApp\Bundle\ServiceABCBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use MyApp\Bundle\ServiceABCBundle\Models\Clients\ClientLocation;
class DefaultController extends Controller
{
public function indexAction()
{
$services = array();
$services[] = $this->container->has('service_abc_manager');
$services[] = $this->container->has('location_manager');
$services[] = $this->container->has('client_location');
$services[] = $this->container->has('ClientLocation');
var_dump( $services );
$client = new ClientLocation();
var_dump( $client );
$response = $this->render(
'Service_ABC:Default:index.html.twig'
);
# $response->setCharset( 'utf-8' );
# $response->headers->set( 'Content-Type', 'text/html' );
return $response;
}
}
The output of the first array() named $services is always false and the $client = new ClientLocation(); throws an Exception that the class name wasn't found.
How can I access those Services/Bundle(parts)/Classes? And how would I render the output to a template?
Update
After I added the complete tree definition to Configuration()->getConfigTreeBuilder(), I'm able to see the definitions in the CLI:
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root( 'myapp_service_abc' );
$rootNode
->children()
->scalarNode('service_abc_manager')->end()
->scalarNode('location_manager')->end()
->scalarNode('monitor_manager')->end()
->end()
;
return $treeBuilder;
}
}
The CLI command php app/console config:dump-reference myapp_service_abc now gives me the following output:
myapp_service_abc:
service_abc_manager: ~
location_manager: ~
monitor_manager: ~
I can as well see that the config data was loaded, when I var_dump( $loader ); inside MyAppServiceABCExtension right after $loader->load( 'services.yml' ); was called.
The output is the following:
object(Symfony\Component\DependencyInjection\Loader\YamlFileLoader)
protected 'container' =>
object(Symfony\Component\DependencyInjection\ContainerBuilder)
private 'definitions' =>
array
'service_abc_manager' =>
object(Symfony\Component\DependencyInjection\Definition)
'location_manager' =>
object(Symfony\Component\DependencyInjection\DefinitionDecorator)
private 'parent' => string 'service_abc_manager'
// etc.
The problem itself remains: There's still a FALSE return value inside DefaultController()->indexAction() when I var_dump( $this->container->has( 'service_abc_manager' );. I as well tried var_dump( $this->container->has( 'location_manager' ); and var_dump( $this->container->has( 'myapp.service_abc_manager' ); with the same result.
You should not call your services from the twig file, but from the controller.
The role of the controller is to :
validate your forms if there were a form posted
call your services to get some stuffs to display in a view
initialize forms if there is a form to display
return a Response that typically contains a rendered twig view
Do not call your services using something like $client = new ClientLocation();, but call it using the service container. This will allow you to take the whole power of the dependancy injection offered by Symfony2.
Your controller will look like :
<?php
namespace MyApp\Bundle\ServiceABCBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DefaultController extends Controller
{
public function indexAction()
{
$locationService = $this->container->get('location_manager');
$someStuffs = $locationService->someMethod();
$response = $this->render(
'ServiceABCBundle:Default:index.html.twig', array('stuffs' => $someStuffs)
);
return $response;
}
}
From your twig file, you'll be able to use the stuffs variable :
{{ stuffs }} if your variable is a terminal ( a string, a number... )
{{ stuffs.attribute }} if your variable is an object or an array
About your services file, I am a bit confused, because your architecture does not look to be the standard Symfony2's one :
# ~/MyApp/Bundle/ServiceABCBundle/Resources/config/services.yml
Why your services.yml file isn't in the src/MyApp/SomethingBundle/Resources/config/ directory?
If you didn't already read it, I suggest you to have a look to the Symfony2 : The Big Picture documentation, which is the best way to start with Symfony2.