Container is non-object error in Symfony data fixtures - php

I'm trying to access to the service api.service.feedback in fixture class below but for some reason container returns error below on if statement in load() method:
ERROR: PHP Fatal error: Call to a member function has() on a non-object
Note: If anyone wants to know, the service api.service.feedback itself is accessible in all the controllers and has no problem with it.
<?php
namespace .........;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class LoadOrderFixtures extends AbstractFixture implements FixtureInterface, ContainerAwareInterface
{
/**
* #var ContainerInterface
*/
private $container;
/**
* {#inheritDoc}
*/
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
/**
* {#inheritDoc}
*/
public function load(ObjectManager $manager)
{
if ($this->container->has('api.service.feedback')) {
exit('EXISTS');
}
}
......
}

You are just implementing the ContainerAwareInterface. If you want the container, you have to inject it:
services:
bundle.service_name:
class: ...
calls:
- [ setContainer, [ #service_container ] ]

You can extend directly ContainerAware:
class LoadArticlesData extends ContainerAware implements FixtureInterface, OrderedFixtureInterface {
public function load(ObjectManager $manager)
{
$dummy = $this->container->getParameter('dynamic.dummy');
...
}
}

Related

Can't get the IriConverter from the container because it's not public

I trying to load the api_platform.iri_converter but get an error:
The \"api_platform.iri_converter\" 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.
This is the code:
declare(strict_types=1);
namespace App\Security\Authorization\Voter;
use Symfony\Component\DependencyInjection\ContainerInterface;
abstract class BaseVoter extends Voter
{
public ContainerInterface $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
}
declare(strict_types=1);
namespace App\Security\Authorization\Voter;
class VenueVoter extends BaseVoter
{
protected function voteOnAttribute(): bool
{
/** #var User $tokenUser */
$tokenUser = $token->getUser();
if (self::VENUE_CREATE === $attribute) {
$iri = $this->container->get('api_platform.iri_converter')->getItemFromIri($valueWithIri);
}
}
}
Do not inject the Container.
Instead, inject the IriConverter directly.
use ApiPlatform\Core\Bridge\Symfony\Routing\IriConverterInterface;
abstract class BaseVoter extends Voter
{
public IriConverterInterface $iriConverter;
public function __construct(IriConverterInterface $iriConverter)
{
$this->iriConverter = $iriConverter;
}
}

Symfony 4 access parameters inside of repository

I have a repository class called EmailRepository
class EmailRepository extends EntityRepository implements ContainerAwareInterface { ... }
I need to get a parameter injected into this repository class but I dont know how...
This is what I currently have inside of the repository, which is being called from my controller:
Controller:
$em->getRepository(Email::class)->getEmailApi();
Repository
class EmailRepository extends EntityRepository implements ContainerAwareInterface {
protected $container;
public function setContainer(ContainerInterface $container = null) {
$this->container = $container;
}
/**
* #param $array
*/
public function getEmailApi($array)
{
echo $this->container->getParameter('email_api');
}
}
I always get this error:
Call to a member function getParameter() on null
The parameter is not null, it does have a value. I know it's telling me that $this->container is null. How do I fix this?
If I run this inside of my controller, it works fine and returns Google
echo $this->getParameter('email_api');
Inject container not a good idea. Try this
services.yaml
App\Repository\EmailRepository:
arguments:
$emailApi: '%env(EMAIL_API)%'
Repository
class EmailRepository
{
protected $emailApi;
public function __construct(string $emailApi)
{
$this->emailApi = $emailApi;
}
/**
* #param $array
*/
public function getEmailApi($array)
{
return $this->emailApi;
}
}
Or via setter injection
services.yaml
App\Repository\EmailRepository:
calls:
- method: setEmailApi
arguments:
$emailApi: '%env(EMAIL_API)%'
Repository
class EmailRepository extends EntityRepository implements ContainerAwareInterface
{
protected $emailApi;
public function setEmailApi(string $emailApi)
{
$this->emailApi = $emailApi;
}
/**
* #param $array
*/
public function getEmailApi($array)
{
return $this->emailApi;
}
}
Your original code is not going to work because there is nothing calling EmailRepository::setContainer. Furthermore, using ContainerAware and injecting the full container is discouraged.
Fortunately, the Doctrine bundle has a new base repository class that the entity manager can use to pull the repository from container and allow you to inject additional dependencies as needed. Something like:
namespace App\Repository;
use App\Entity\Email;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Symfony\Bridge\Doctrine\RegistryInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
class EmailRepository extends ServiceEntityRepository // Different class to extend from
{
private $emailApi;
public function __construct(RegistryInterface $registry, ParameterBagInterface $parameterBag)
{
parent::__construct($registry, Email::class);
$this->emailApi = $parameterBag->get('email_api');
}
So in this case we inject all the parameters and then store the ones we need.
Even injecting the parameter bag is a bit frowned upon. Better to inject individual parameters though this takes just a bit more configuration as we need to use services.yaml to explicitly inject the needed parameters:
public function __construct(RegistryInterface $registry, string $emailApi)
{
parent::__construct($registry, Email::class);
$this->emailApi = $emailApi;
}
#services.yaml
App\Repository\EmailRepository:
$emailApi: 'email_api_value'

Doctrine PHP DataFixture : "Compile Error: Cannot redeclare class"

I created a PHP class to generate some fixtures :
namespace DashboardBundle\DataFixtures\ORM;
use DashboardBundle\Entity\Property;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class LoadPropertyData extends AbstractFixture implements FixtureInterface, ContainerAwareInterface, OrderedFixtureInterface
{
/** #var ContainerInterface */
private $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
public function load(ObjectManager $manager)
{
$properties = $this->container->get('dashboard.properties_generator');
foreach ($properties as $key => $propertyConfig) {
$property = new Property();
$property->setName($key);
$property->setType($propertyConfig);
$this->addReference('property-' . $key, $property);
$manager->persist($property);
}
$manager->flush();
}
public function getOrder()
{
return 1;
}
}
But I get this error :
➜ dashboard git:(guillaume) ✗ bin/console -v fixtures:load
/* ... some stuff ... */
[Symfony\Component\Debug\Exception\FatalErrorException]
Compile Error: Cannot redeclare class DashboardBundle\DataFixtures\ORM\LoadPropertyData
The namespace seems and the class name seems correct. There is no other file in the DashboardBundle\DataFixtures\ORM directory.
I tried to restart the servers (PHP-FPM and Nginx), I tried to clear the Symfony cache, but there is no effect.
In brief, I have no idea why Symfony throws this exception.
Any idea ? Thanks !

Repositories Not be Instantiated

I'm trying to find out why I'm receiving this error. I'm following along. However the only difference is that at the time of the recording it was done with Laravel 4.25 and I am now using Laravel 5.0.
Repositories and Inheritance
BindingResolutionException in Container.php line 785:
Target [App\Repositories\User\UserRepository] is not instantiable.
<?php
namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Repositories\User\UserRepository;
use Illuminate\Http\Request;
class UsersController extends Controller {
private $userRepository;
public function __construct(UserRepository $userRepository) {
$this->userRepository = $userRepository;
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index() {
$users = $this->userRepository->getAll();
return $users;
}
}
<?php
namespace App\Repositories\User;
use App\Repositories\EloquentRepository;
class EloquentUserRepository extends EloquentRepository implements UserRepository
{
private $model;
function __construct(User $model) {
$this->model = $model;
}
}
<?php
namespace App\Repositories\User;
interface UserRepository {
public function getAll();
}
<?php
namespace App\Repositories;
abstract class EloquentRepository {
public function getAll() {
return $this->model->all();
}
public function getById() {
return $this->model->findOrFail($id);
}
}
You are type hinting an interface, and not the class itself. This error is occurring because Laravel cannot bind an interface because the binding must be instantiable. Abstract classes or interfaces are not valid unless Laravel knows the concrete (instantiable) class to substitute in for the abstract class / interface.
You will need to bind the EloquentUserRepository to the interface:
App::bind('UserRepository', 'EloquentUserRepository');

Symfony2 Extending Controller getParameter()

I Want to extend Symfony2 Controller to my project that is using API but I am having error of a non object use getParameter() function look at my code:
namespace Moda\CategoryBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class ApiController extends Controller
{
/**
* #var String
*/
protected $_host;
/**
* #var String
*/
protected $_user;
/**
* #var String
*/
protected $_password;
public function __construct()
{
$this->_host = $this->container->getParameter('api_host');
$this->_user = $this->container->getParameter('api_user');
$this->_password = $this->container->getParameter('api_password');
}
}
And next Controller
namespace Moda\CategoryBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class CategoryController extends ApiController
{
/**
* #Route("/category", name="_category")
* #Template()
*/
public function indexAction()
{
return array('name' => 'test');
}
}
And the end, I got this Fatal Error:
FatalErrorException: Error: Call to a member function getParameter()
on a non-object in (..)
I try to use $this->setContainer() but it doesn't work. Do you have any idea how can I slove this problem?
If your controller is not defined as service, The constructor execution of the controller is not persisted.
You have two options to solve your situation:
Define the controller as a service and inject the parameters you need using dependency injection.
Add an init method in the controller, or on a parent abstract controller, and call the init method, before the action you need to have these parameters available;
You cant use container in Controller __construct at reason that when constructor called where is none container set yeat.
You can simply define some simple methods in controller like
class ApiController extends Controller
{
protected function getApiHost()
{
return $this->container->getParameter('api_host');
}
}
I wonder if something crazy like this would work? Instead of overriding the constructor, override the setContainer method? I haven't tried it...just thinking out loud.
namespace Moda\CategoryBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\DependencyInjection\ContainerInterface;
class ApiController extends Controller
{
/**
* #var String
*/
protected $_host;
/**
* #var String
*/
protected $_user;
/**
* #var String
*/
protected $_password;
public function setContainer(ContainerInterface $container = null)
{
parent::setContainer($container);
$this->_host = $this->container->getParameter('api_host');
$this->_user = $this->container->getParameter('api_user');
$this->_password = $this->container->getParameter('api_password');
}
}

Categories