Symfony2 , Container Service - symfony

Hello i have an error on EventSubscriber for form in sonata admin
namespace OneA\AdvertBundle\Form\EventListener;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\DependencyInjection\ContainerAware;
class CategoryFieldsSubscriber extends ContainerAware implements EventSubscriberInterface
{
private $factory;
public function __construct(FormFactoryInterface $factory)
{
$this->factory = $factory;
}
public static function getSubscribedEvents()
{
return array(FormEvents::PRE_SET_DATA => 'preSetData');
}
public function preSetData(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
//$form->add('advert_fields', 'text');
$advert_type = $form->get('advert_type')->getData();
$this->getFields($form, $advert_type);
}
public function getFields($form, $advert_type)
{
$form->add('advert_fields', 'text', array(
'label' => 'dfjg',
));
$this->container->get('one_a_advert.admin_motors_field')->getFieldsForm($form);
}
}
When i call the container i have this error
FatalErrorException: Error: Call to a member function get() on a non-object in
To the container->get(

You need to send in your constructor required container like this:
services:
kernel.listener.your_listener:
class: OneA\AdvertBundle\Form\EventListener\CategoryFieldsSubscriber
arguments: [#factory, #service_container]
and use this like
private $container;
private $factory;
public function __construct(FormFactoryInterface $factory, $container)
{
$this->container = $container;
$this->factory = $factory;
}

Related

Symfony 6 Persisting Objects to the Database

Here is the error message when displaying: "An exception occurred while executing a query: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'done' cannot be null"
I don't understand why this error occurs when everything seems very normal.
Here's my DefaultController.php file:
<?php
namespace App\Controller;
use App\Entity\Todo;
use App\Form\TodoType;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class DefaultController extends AbstractController {
#[Route('/', name:'index')]
public function index(Request $request, ManagerRegistry $mr) {
$todo = new Todo();
$todoForm = $this->createForm(TodoType::class, $todo);
$todoForm->handleRequest($request);
// dd($todoForm);
if($todoForm->isSubmitted() && $todoForm->isValid() ){
$todo->setCreatedAt(new \DateTime());
$entityManager = $mr->getManager();
$entityManager->persist($todo);
$entityManager->flush();
}
return $this->render('./page1.html.twig',
['form'=>$todoForm->createView()]
);
}
}
Here is the code of my entity class todo:
<?php
namespace App\Entity;
use App\Repository\TodoRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: TodoRepository::class)]
class Todo
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $id;
#[ORM\Column(type: 'string', length: 255)]
private $content;
#[ORM\Column(type: 'boolean', options:["default" => false])]
private $done;
#[ORM\Column(type: 'datetime' , options:["default" => "CURRENT_TIMESTAMP"])]
private $createdAt;
public function getId(): ?int
{
return $this->id;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
public function getDone(): ?bool
{
return $this->done;
}
public function setDone(bool $done): self
{
$this->done = $done;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
}
Here is my TodoType form:
<?php
namespace App\Form;
use App\Entity\Todo;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class TodoType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('content')
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Todo::class,
]);
}
}
I tried another method by injecting the EntityManagerInterface service in my controller, unfortunately. I get the same error message. Need help please.
I think instead of initialising your property withing the ORM you can do it underneath
#[ORM\Column(type: 'boolean')]
private $done = false;
Or you could do it as soon as you submit the form, by any means when you submit the form it sets the done value to false. However this method isn't practical.
if($todoForm->isSubmitted() && $todoForm->isValid() ){
$todo->setCreatedAt(new \DateTime());
$todo->setDone(0); // Sets the value to false as soon as the form is submitted
$entityManager = $mr->getManager();
$entityManager->persist($todo);
$entityManager->flush();

HWIOAuthBundle add token attribute after success auth

I use HWIOAuthBundle for Symfony.
HWI\Bundle\OAuthBundle\Security\Core\Authentication\Provider\OAuthProvider.php has function "authenticate" where create and return OAuthToken.
public function authenticate(TokenInterface $token){
...
$token = new OAuthToken($oldToken->getRawToken(), $user->getRoles());
$token->setResourceOwnerName($resourceOwner->getName());
$token->setUser($user);
$token->setAuthenticated(true);
$token->setRefreshToken($oldToken->getRefreshToken());
$token->setCreatedAt($oldToken->getCreatedAt());
return $token;
}
I need set some attribute to this OAuthToken like :
$token->setAttribute('name' => 'value');
How can i do this ?
I use service with only one function "loadUserByOAuthUserResponse" which return user object :
class PartnerEntityUserProvider implements OAuthAwareUserProviderInterface{
...
public function loadUserByOAuthUserResponse(UserResponseInterface $response){
...
return $user;
}
...
}
Edited
I found solution with using service on security.interactive_login event :
config/services.yaml
services:
App\EventListener\InteractiveLoginListener:
tags:
- { name: kernel.event_listener, event: security.interactive_login }
src/EventListener/InteractiveLoginListener.php
<?php
namespace App\EventListener;
use App\Entity\Perimetre;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
class InteractiveLoginListener
{
private $security;
private $entityManager;
public function __construct(Security $security, EntityManagerInterface $entityManager)
{
$this->security = $security;
$this->entityManager = $entityManager;
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
$this->security->getToken()->setAttribute('perimetre', $this->entityManager->getRepository(Perimetre::class)->findOneBy(['id' => $this->security->getToken()->getUser()->getFiliale()->getPerimetre()->getId()]));
}
}

Symfony login success redirect to change password screen

Admin generate user then user first time login i want to redirect user to change password.
I have google but there are no any post found that make this fix.
Below i have attached service.yml and loginsuccessListener file code.
service.yml
services:
fos_user.security.interactive_login_listener:
class: OnlineCare\MarketingWebBundle\EventListener\LastLoginListener
tags:
- { name: kernel.event_subscriber, event: kernel.request, method: onKernelRequest }
arguments: ['#fos_user.user_manager','#router','#service_container']
LastLoginListiner.php
namespace OnlineCare\MarketingWebBundle\EventListener;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\UserEvent;
use FOS\UserBundle\Model\UserManagerInterface;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class LastLoginListener implements EventSubscriberInterface
{
protected $userManager;
private $router;
private $container;
public function __construct(UserManagerInterface $userManager, UrlGeneratorInterface $router, ContainerInterface $container)
{
$this->userManager = $userManager;
$this->router = $router;
$this->container = $container;
}
public static function getSubscribedEvents()
{
return array(
FOSUserEvents::SECURITY_IMPLICIT_LOGIN => 'onImplicitLogin',
SecurityEvents::INTERACTIVE_LOGIN => 'onSecurityInteractiveLogin',
);
}
public function onImplicitLogin(UserEvent $event)
{
$user = $event->getUser();
$user->setLastLogin(new \DateTime());
$this->userManager->updateUser($user);
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
$user = $event->getAuthenticationToken()->getUser();
if(empty($user->getLastLogin())){
$url = $this->router->generate('fos_user_change_password');
**return $event->setResponse(new RedirectResponse($url));**
} elseif ($user instanceof UserInterface) {
$user->setLastLogin(new \DateTime());
$this->userManager->updateUser($user);
}
}
}

How to pass arguments to Datatransformer when using a custom field type

I need to transform a user name to a user entity, and I'm using this transformation in many form,every form need some specific test to the returned user entity.
In the registration form a user can enter a referral code (user name) or leave this empty, the referral code must have the role ROLE_PARTNER.
In the dashboard a partner can append some user to his account: in this case the user name can't be empty, the user must have the role ROLE_CLIENT and the partner can't enter his own user name this is my data transformer class
class UserToNameTransformer implements DataTransformerInterface
{
private $om;
private $role;
private $acceptEmpty;
private $logged;
public function __construct(ObjectManager $om,$role,$acceptEmpty,$logged)
{
$this->om = $om;
$this->role=$role;
$this->acceptEmpty=$acceptEmpty;
$this->logged=$logged;
}
public function transform($user)
{
if (null === $user) {
return "";
}
return $user->getUsername();
}
public function reverseTransform($username)
{
if (!$username) {
if ($this->acceptEmpty)
return null;
else
throw new TransformationFailedException(sprintf(
'user name can\'t be empty!'
));
}
$user = $this->om
->getRepository('FMFmBundle:User')
->findOneBy(array('username' => $username))
;
if (null === $user) {
throw new TransformationFailedException(sprintf(
'user with user name "%s" not found!',
$username
));
}
else if (!$user->hasRole($this->role)){
throw new TransformationFailedException(sprintf(
'user name "%s" is not valid',
$username
));
}
else if($this->logged==true){
$activeUser=$this->get('security.context')->getToken()->getUser();
if($user===$activeUser)
throw new TransformationFailedException(sprintf(
'you can\'t enter you user name'
));
}
else
return $user;
}
}
Form type
this form work fine because I'm not using the custom field
class ActivatePartnerType extends AbstractType
{
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('user','text', array(
'invalid_message' => 'That is not a valid username',
'label' => 'Partner Username :',
))
->add('next','submit')
;
$builder->get('user')
->addModelTransformer(new UserToNameTransformer($this->entityManager,'ROLE_PARTNER',false,true));
}
public function getName()
{
return 'fm_fmbundle_activate_partner';
}
}
The custom field type
class UserSelectorType extends AbstractType
{
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$transformer = new UserToNameTransformer($this->entityManager,**{others parametres}**);
$builder->addModelTransformer($transformer);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'invalid_message' => 'The selected user does not exist'
));
}
public function getParent()
{
return 'text';
}
public function getName()
{
return 'user_selector';
}
}
the custom field service
FmarketUserSelector:
class: FM\FmBundle\Form\UserSelectorType
arguments: ["#doctrine.orm.entity_manager"]
tags:
- { name: form.type, alias: user_selector }
the form type
class ActivatePartnerType extends AbstractType
{
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('user','user_selector')
->add('next','submit')
;
}
public function getName()
{
return 'fm_fmbundle_activate_partner';
}
}
Look at this pages:
Introduction to Parameters
Service Container
In your case, it would look like this:
FmarketUserSelector:
class: FM\FmBundle\Form\UserSelectorType
arguments: ["#doctrine.orm.entity_manager", "ROLE_PARTNER", false, true]
tags:
- { name: form.type, alias: user_selector }
but looks like, you're passing dynamic values to your form type, that's why this doesn't suit your needs I think..
In your case you can call your form type as a regular class call, like this:
...
$builder
->add('user', new UserSelectorType(ARG1, ARG2, ...))
->add('next','submit')
;
...
may be this answer can also help you a bit..
Here, is how I use the $options array
class UserSelectorType extends AbstractType
{
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$transformer = new UserToNameTransformer($this->entityManager,$options['role'],$options['accept_empty'],$options['logged']);
$builder->addModelTransformer($transformer);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'invalid_message' => 'The selected user does not exist',
'role'=>'ROLE_PARTNER',
'accept_empty'=>true,
'logged'=>false
));
}
public function getParent()
{
return 'text';
}
public function getName()
{
return 'user_selector';
}
}
In the form type
$builder->add('referral','user_selector',array(
'role'=>'ROLE_PARTNER',
'accept_empty'=>false,
'logged'=>false
));

How pass 'templating' component for service as argument?

I have a method in 'DynamicList' service that should return a select filled with dynamic data, but i'm getting "circular reference":
YML:
parameters:
my.dynamic_list.class: My\DynamicListBundle\Service\DynamicList
services:
my.dynamic_list:
class: %my.dynamic_list.class%
arguments: ['#doctrine.orm.default_entity_manager','#templating']
Class:
<?php
namespace My\DynamicListBundle\Service;
use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
class DynamicList
{
private $em;
private $templating;
public function __construct(
EntityManager $em,
EngineInterface $templating
) {
$this->em = $em;
$this->templating = $templating;
}
public function getSelect($slug)
{
$dynamic_list = $this->em
->getRepository('MyDynamicListBundle:DynamicList')
->findOneBy(array(
"slug" => $slug
));
return $this->templating->render('MyComponentsCoreBundle::Templates/DynamicList/combo.html.twig', array(
'dl' => $dynamic_list
));
}
}
I guess i don't need to put here the twig content: the problema occurs before.
Last, the error i'm getting:
Circular reference detected for service "my.dynamic_list", path: "my.dynamic_list -> templating -> twig". (500 Internal Server Error - ServiceCircularReferenceException)
What's the proper way to get templating component working in my service?
Well, I found a workaround but I don't if is the best way:
<?php
namespace My\DynamicListBundle\Service;
use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
class DynamicList
{
private $em;
private $templating;
public function __construct(
EntityManager $em
) {
$this->em = $em;
}
public function init(
EngineInterface $templating
) {
$this->templating = $templating;
}
public function getSelect($slug)
{
$dynamic_list = $this->em
->getRepository('MyDynamicListBundle:DynamicList')
->findOneBy(array(
"slug" => $slug
));
return $this->templating->render('MyComponentsCoreBundle::Templates/DynamicList/combo.html.twig', array(
'dl' => $dynamic_list
));
}
}
So, in controller, I call 'init()' to pass 'templating':
$dl_service = $this->get('my.dynamic_list');
$dl_service->init($this->container->get('templating'));

Resources