I am a beginner on Symfony.
I am trying to create a class to use my database (mysql). But I can not succeed. Can you help me ?
Here is my current class:
<?php
namespace App\Database;
use Doctrine;
use Doctrine\DBAL\Connection;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class DatabaseApi extends AbstractController
{
/**
* #var Connection
*/
protected $database = null;
protected static $instance = null;
/**
* DatabaseApi constructor.
*/
protected function __construct()
{
$database = $this->container->get('database');
$this->database = $database;
}
public static function getInstance()
{
self::$instance = new self();
return self::$instance;
}
private function __clone()
{
}
/**
* #param $authentication_key
* #return mixed
* #throws Doctrine\DBAL\DBALException
*/
public function select_authentication_key($authentication_key)
{
$auth_key_query = $this->database->prepare('CALL Verify_authentication_key(:authentication_key)');
$auth_key_query->bindValue('authentication_key', $authentication_key);
$auth_key_query->execute();
$results = $auth_key_query->fetchAll(\PDO::FETCH_ASSOC);
return $results[0];
}
}
I tried to create it with everything I could find on the Internet. Unfortunately, I get an error "Call to a member function get() on null".
There is my services.yaml file :
parameters:
database_connection: default
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
public: false # Allows optimizing the container by removing unused services; this also means
# fetching services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
database:
alias: doctrine.dbal.%database_connection%_connection
And is is how I try to call the fonction :
$database = DatabaseApi::getInstance();
$result = null;
try{
$result = $database->select_authentication_key("1111-1111-1111-1111");
}catch (Exception $e){
print($e);
}
print_r($result);
Related
While updating from Symfony 3.4 to 4.1, when I php bin/console, I got the following error.
I want to take parameters in a url reference way.
What is the cause?
https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service
Error code
Unused binding "$projectDir" in service "common.parameterService".
config/services.yaml
parameters:
parameter_name: XXX
services:
_defaults:
autowire: false
autoconfigure: false
public: false
bind:
$projectDir: '%kernel.project_dir%'
common.parameterService:
class: AppBundle\Model\Service\ParameterService
arguments: [ "#service_container" ]
AppBundle/Model/Service/ParameterService.php
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use AppBundle\Model\Service\BaseService;
/**
*
*/
class ParameterService extends BaseService
{
private $params;
public function __construct(ParameterBagInterface $params)
{
$this->params = $params;
}
/**
*
* #param string
* #return mixed
*/
public function getParameter()
{
return $this->params->get('parameter_name');
}
It means you have declared this:
bind:
$projectDir: '%kernel.project_dir%'
but have not injected the $projectDir in the ParameterService nor in any other services in that file.
You can delete these two lines:
bind:
$projectDir: '%kernel.project_dir%'
I'm trying to create a config for an extension which will give me 1 service with all dependencies injected but so far I was unable to do it. My steps were this to follow those steps in this web page https://symfony.com/doc/current/bundles/extension.html but I still get an error that I don't have service
Cannot autowire service "App\Command\ParserConfigAutoCreationCommand": argument "$nominatimGeocode" of method "__construct()" references class "XYZ\Service\NominatimGeocode" but no such service exists.
my services.yml file:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
bind:
Geocoder\Provider\Provider $nominatimProvider: '#bazinga_geocoder.provider.nominatim'
Geocoder\Provider\Provider $googleProvider: '#bazinga_geocoder.provider.google'
XYZ\Service\NominatimGeocode:
arguments: [ '#bazinga_geocoder.provider.nominatim' ]
and my GeoCodeExtension.php file:
<?php
declare(strict_types=1);
namespace XYZ\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
/**
* This is the class that loads and manages your bundle configuration.
*
* To learn more see {#link http://symfony.com/doc/current/cookbook/bundles/extension.html}
*/
class GeoCodeExtension extends Extension
{
/**
* {#inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
// $configuration = new Configuration();
// $config = $this->processConfiguration($configuration, $configs);
$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
}
}
do I need to add additional files or something?
EDIT:
class NominatimGeocode
{
/**
* #var \Geocoder\Provider\Provider
*/
private $nominatimProvider;
private $checkPostCode = false;
/**
* Geo Nominatim constructor.
*
* #param \Geocoder\Provider\Provider $nominatimProvider
*/
public function __construct(Provider $nominatimProvider)
{
$this->nominatimProvider = $nominatimProvider;
}
.
.
.
so I'm injecting it with right param name.
Your class should inject the Geocoder\Provider\Provider $nominatimProvider dependency if you want type binding to work.
Mind the variable's name must match the one in the bind section too.
Your is totally different:
XYZ\Service\NominatimGeocode $nominatimGeocode
Given a class Publisher like this:
<?php
namespace App\Util\Publisher;
use Symfony\Component\Mercure\Update;
use Symfony\Component\Messenger\MessageBusInterface;
class Publisher
{
protected $topic = null;
protected $bus;
/**
* Publisher constructor.
* #param MessageBusInterface $bus
*/
public function __construct(MessageBusInterface $bus)
{
$this->topic = getenv('TOPIC_MAIN_URL');
$this->bus = $bus;
}
...
}
I would like to autowire it in my controllers like this:
/**
* #Route("/_exp/_exp", name="exp")
*/
public function expAction(Publisher $publisher)
{
...
}
and I added this to my services.yaml:
Symfony\Component\Messenger\MessageBusInterface: ~
App\Util\Publisher\Publisher:
autowire: true
arguments: ['#Symfony\Component\Messenger\MessageBusInterface']
But I get an error:
Cannot instantiate interface Symfony\Component\Messenger\MessageBusInterface
Is that related to the MessageBusInterface or am I doing something wrong with the autowiring. I followed The Symfony docs for autowiring and they seem to be the same?
Thank you!
I believe MessageBusInterface service is already declared by Symfony Messenger component.
Try to remove Symfony\Component\Messenger\MessageBusInterface: ~ from your services.yaml, otherwise you are overriding the default definition.
A note for clarification: MessageBusInterface service does not really exists, it in an alias over the "default bus" service. You can declare other buses, cf documentation
I have Symfony 4 project.
And here is the service. It is marked as public and it is in separate cooperation.yml which is connected to project:
services:
App\Matcher\CooperationSiteConfigMatcher:
public: true
Here is class itself
<?php
namespace App\Matcher;
use App\Factory\CooperationOptionsFactory;
use App\Options\Cooperation\CooperationOptions;
use App\Resolver\SiteResolver;
use App\Factory\Exception\MissingCooperationOptionsException;
use Assert\AssertionFailedException;
class CooperationSiteConfigMatcher
{
const TYPE_PARTNERSHIP = 'partnership';
const TYPE_FRANCHISE = 'franchise';
/**
* #var CooperationOptionsFactory
*/
private $optionsFactory;
/**
* #var SiteResolver
*/
private $siteResolver;
/**
* CooperationSiteConfigMatcher constructor.
* #param CooperationOptionsFactory $optionsFactory
* #param SiteResolver $siteResolver
*/
public function __construct(CooperationOptionsFactory $optionsFactory, SiteResolver $siteResolver)
{
$this->optionsFactory = $optionsFactory;
$this->siteResolver = $siteResolver;
}
/**
* #param $group
* #return CooperationOptions
* #throws AssertionFailedException
* #throws MissingCooperationOptionsException
*/
public function matchOptionsByGroupAndSite($group)
{
$domainAliasKey = $this->siteResolver->resolve();
return $this->optionsFactory->createForSite($group, $domainAliasKey);
}
}
Global service.yml base configuration:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
public: false # Allows optimizing the container by removing unused services; this also means
# fetching services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
App\:
resource: '%kernel.root_dir%/*'
exclude: '%kernel.root_dir%/{Entity,Migrations,Tests,Kernel.php,Form/EventListener,Request}'
But I receive an error:
The "App\Matcher\CooperationSiteConfigMatcher" service or alias has
been removed or inlined when the container was compiled. You should
either make it public or stop using the container directly and use
dependency injection instead.
The problem disappears when I move this service to global services.yml.
My custom services.yml is loaded via CooperationExtension class:
class CooperationExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$config = $this->processConfiguration(new CooperationConfiguration(), $configs);
$loader = new YamlFileLoader(
$container,
new FileLocator(__DIR__ . '/../Resources/config/services')
);
$loader->load('cooperation.yaml');
$this->generateCooperationServices($config, $container);
}
public function getAlias()
{
return 'cooperation';
}
public function getXsdValidationBasePath()
{
return false;
}
public function getNamespace()
{
return "cooperation/schema";
}
}
Extension registered in Kernel.php configureContainer method:
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void
{
$cooperationExtension = new CooperationExtension();
$container->registerExtension($cooperationExtension);
$container->loadFromExtension($cooperationExtension->getAlias());
$container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php'));
// Feel free to remove the "container.autowiring.strict_mode" parameter
// if you are using symfony/dependency-injection 4.0+ as it's the default behavior
$container->setParameter('container.autowiring.strict_mode', true);
$container->setParameter('container.dumper.inline_class_loader', true);
$confDir = $this->getProjectDir().'/config';
$loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{packages}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob');
}
Symfony sees cooperation.yml. I checked it when removed some other services from it and exception appeared.
But somehow it do not merge it correctly with global services.yml and I don't see this service as public when load it from cooperation.yml
How to use entity as service in doctrine (Using Symfony 2.1).
Example usage:
<?php
namespace MyNamespace;
class MyEntity
{
protected $container = NULL;
public function __construct($container)
{
$this->container = $container;
}
/**
* #ORM\PrePersist
*/
public function()
{
// Must call to container and get any parameters
// for defaults sets entity parameters
$this->container->get('service.name');
}
}
As a result, I need to get access to the entire container.
EDIT: THIS IS NOT THE PREFERRED WAY, it's the only way to get service container inside an entity, it's not a good practice, it should be avoided, but this just answers the question.
In case you still want the container and/or repository you can extend a base abastractEntity like this:
<?php
namespace Acme\CoreBundle\Entity;
/**
* Abstract Entity
*/
abstract class AbstractEntity
{
/**
* Return the actual entity repository
*
* #return entity repository or null
*/
protected function getRepository()
{
global $kernel;
if ('AppCache' == get_class($kernel)) {
$kernel = $kernel->getKernel();
}
$annotationReader = $kernel->getContainer()->get('annotation_reader');
$object = new \ReflectionObject($this);
if ($configuration = $annotationReader->getClassAnnotation($object, 'Doctrine\ORM\Mapping\Entity')) {
if (!is_null($configuration->repositoryClass)) {
$repository = $kernel->getContainer()->get('doctrine.orm.entity_manager')->getRepository(get_class($this));
return $repository;
}
}
return null;
}
}
An entity is a data model and should only hold data (and not have any dependencies on services). If you want to modify your model in case of a certain event (PrePersist in your case) you should look into making a Doctrine listener for that. You can inject the container when defining the listener:
services:
my.listener:
class: Acme\SearchBundle\Listener\YourListener
arguments: [#your_service_dependency_or_the_container_here]
tags:
- { name: doctrine.event_listener, event: prePersist }