Symfony4 extends controller with route annotation - php

I'm building a webapp with Symfony and since now I had to repeat a specific pattern for each new controller I built.
For example I have this AdminController :
/**
* #Route("/pro/{uniqid}")
* #ParamConverter("company", options={"mapping":{"uniqid" = "uniqid"}})
* #Security("is_granted(constant('App\\Security\\Voter\\CompanyVoter::VIEW'), company)")
* #package App\Controller
*/
class AdminController extends Controller
{
/**
* #Route("/admin/users/", name="users")
* #return \Symfony\Component\HttpFoundation\Response
*/
public function users(Company $company){}
}
So, each controller must redefine #Route, #ParamConverter and #Security that is extremely redundant.
I tried to create a LoggedController that define every annotation, then make Controller extends that LoggedController, but that does not work.
Is there a solution or should I continue to copy/paste these Annotation each time I create a new Controller that needs to implement it ?
EDIT :
I add the declaration of Company entity :
/**
* #ORM\Entity(repositoryClass="App\Repository\CompanyRepository")
*/
class Company
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;

Long story short, you can but it will be a lot easier to duplicate your annotations in every controller.
But if you wan't to do this anyway, here are some solutions.
Routing
This is the easy one. You can define a global prefix in the config/routes/annotations.yaml file.
If you're using the default config, you can try something like this:
# Default controllers
controllers:
resource: ../../src/Controller/
type: annotation
# Company controllers
company_controllers:
resource: ../../src/Controller/Company/
type: annotation
prefix: /pro/{uniqid}
All your routes will now start with /pro/{uniqid} and you can remove the #Route annotation from your controller.
ParamConverter
You can create your own ParamConverter. Everytime you'll use a Company type in an action method, it'll be converted to the matching entity using the uniqid attribute.
Something like this:
// src/ParamConverter/CompanyConverter.php
<?php
namespace App\ParamConverter;
use App\Entity\Company;
use Doctrine\ORM\EntityManagerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
use Symfony\Component\HttpFoundation\Request;
class CompanyConverter implements ParamConverterInterface
{
const CONVERTER_ATTRIBUTE = 'uniqid';
/**
* #var EntityManagerInterface
*/
private $entityManager;
/**
* CompanyConverter constructor.
*
* #param EntityManagerInterface $entityManager
*/
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
/**
* #inheritdoc
*/
public function apply(Request $request, ParamConverter $configuration)
{
$uniqid = $request->attributes->get(self::CONVERTER_ATTRIBUTE);
$company = $this->entityManager->getRepository(Company::class)->findOneBy(['uniqid' => $uniqid]);
$request->attributes->set($configuration->getName(), $company);
}
/**
* #inheritdoc
*/
function supports(ParamConverter $configuration)
{
return $configuration->getClass() === Company::class;
}
}
With this, you can remove the #ParamConverter annotation from your controller.
Security
You can't use the access_control section of the security.yaml file since custom functions are not yet supported.
Otherwise, something like this could have been nice:
security:
...
access_control:
-
path: ^/pro
allow_if: "is_granted(constant('App\\Security\\Voter\\CompanyVoter::VIEW'), company)"
(Note: It was fixed in Symfony 4.1 but i don't know yet how it will work).
Instead, you can use a subscriber listening on the kernel.request kernel event:
<?php
namespace App\Subscriber;
use App\Entity\Company;
use App\Security\CompanyVoter;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
class SecurityListener implements EventSubscriberInterface
{
/**
* #var AuthorizationCheckerInterface
*/
private $authorizationChecker;
/**
* #var EntityManagerInterface
*/
private $entityManager;
/**
* #param AuthorizationCheckerInterface $authorizationChecker
* #param EntityManagerInterface $entityManagerInterface
*/
public function __construct(AuthorizationCheckerInterface $authorizationChecker, EntityManagerInterface $entityManager)
{
$this->authorizationChecker = $authorizationChecker;
$this->entityManager = $entityManager;
}
/**
* #param GetResponseEvent $event
*/
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
if (!$uniqid = $request->attributes->get('uniqid')) {
return;
}
$company = $this->entityManager->getRepository(Company::class)->findOneBy(['titre' => $uniqid]);
if (!$this->authorizationChecker->isGranted(CompanyVoter::VIEW, $company)) {
throw new AccessDeniedHttpException();
}
}
/**
* #return array
*/
public static function getSubscribedEvents()
{
return array(
KernelEvents::REQUEST => 'onKernelRequest',
);
}
}

Related

Logging from inside a repository in Symfony

I'm tracing a weird error in a Symfony 2 app and I'd like to know if there's a way to print log messages from a Repository PHP file. For example:
class OrderEntityRepository extends EntityRepository
{
/**
*
* #param mixed $filter
* #return type
*/
public function findByCriteria($filter) {
[...]
/* I'D LIKE TO LOG SOME VARIABLES FROM HERE */
}
}
I've tried using error_log() but nothing happens.
Is this possible? Thanks in advance,
It's possible but it's usually not a good practice. The good thing to do is to send back the Repository result to your Controller or Service and you log from them an error or something else.
But if you still want to do it, Repository are like services (when you implements ServiceEntityRepository see this slide for more information). If you want to log something specific inside you have to inject the LoggerInterface into your Repository configuration (like you do with service).
In your service.yml (or xml) if you don't use autowire:
Your\Repository:
arguments: ['#logger']
In your repository class:
/**
* #var LoggerInterface
*/
protected $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
On symfony 3.8 I have
class BlahRepository extends ServiceEntityRepository
{
/* #var ContainerInterface $container */
private $container;
/* #var LoggerInterface $logger */
private $logger;
public function __construct(RegistryInterface $registry, ContainerInterface $container, LoggerInterface $logger)
{
parent::__construct($registry, Blah::class);
$this->container = $container;
$this->logger = $logger;
}
}
and I am able to use $this->logger->info("text")
I think the trick may be extending ServiceEntityRepository
In order to use dependency injection for Doctrine entity repositories, you can create a custom RepositoryFactory.
Tested on Symfony 3.4.
<?php
namespace AppBundle\Doctrine;
use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
use Doctrine\ORM\Repository\RepositoryFactory as RepositoryFactoryInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
class RepositoryFactory implements RepositoryFactoryInterface, LoggerAwareInterface
{
/** #var DefaultRepositoryFactory */
protected $defaultRepositoryFactory;
/** #var LoggerInterface */
private $logger;
/**
* #required (for autowiring)
* #param LoggerInterface $logger (Monolog will be the default one)
*/
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
/**
* #see Configuration::getRepositoryFactory()
*/
public function __construct()
{
$this->defaultRepositoryFactory = new DefaultRepositoryFactory();
}
/**
* Gets the repository for an entity class.
*
* #param EntityManagerInterface $entityManager
* #param string $entityName The name of the entity.
* #return ObjectRepository
*/
public function getRepository(EntityManagerInterface $entityManager, $entityName): ObjectRepository
{
$repository = $this->defaultRepositoryFactory->getRepository($entityManager, $entityName);
if ($repository instanceof LoggerAwareInterface && $this->logger !== null) {
$repository->setLogger($this->logger);
}
return $repository;
}
}
Declare it in Doctrine configuration.
# app/config.yml
doctrine:
# ...
orm:
repository_factory: AppBundle\Doctrine\RepositoryFactory
And finally, make your repository class implement LoggerAwareInterface.
class OrderEntityRepository extends EntityRepository implements LoggerAwareInterface
{
/** #var LoggerInterface */
private $logger;
/**
* #param LoggerInterface $logger
*/
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
/**
* #param mixed $filter
* #return type
*/
public function findByCriteria($filter) {
//[...]
$this->logger->alert('message');
}
}
You can also make a LoggerAwareTrait trait to spare yourself some code duplication.

How to create custom endpoint in API Platform and add it to the documentation?

I want to create not mapped with entity endpoint like /api/v1/me that returns information (User object) about currently authenticated user and add it to my documentation. In the plans I also want to add endpoints like /api/v1/account/recover and /api/v1/account/verify-email.
I have an action:
namespace AppBundle\Action\Me;
use AppBundle\Entity\User;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class MeView
{
/**
* #var TokenStorageInterface
*/
private $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
/**
* #Security("is_authenticated()")
*
* #Route(
* name="me_view",
* path="/me",
* methods={"GET"}
* )
*
* #return User
*/
public function __invoke()
{
return $this->tokenStorage->getToken()->getUser();
}
}
But when I try to access it, it returns an exception:
The controller must return a response (Object(AppBundle\Entity\User) given). (500 Internal Server Error)
Same action, but mapped with entity, works well:
namespace AppBundle\Action\City;
use AppBundle\Entity\City;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\Routing\Annotation\Route;
class CityView
{
/**
* #Security("is_authenticated()")
*
* #Route(
* name="city_view",
* path="/cities/{id}",
* methods={"GET"},
* defaults={"_api_resource_class"=City::class, "_api_item_operation_name"="view"}
* )
*
* #param City $city
* #return City
*/
public function __invoke(City $city)
{
return $city;
}
}
What should I do to make my custom action work and how to add it to auto-generated Swagger documentation?
Controller:
class MyUserController extends Controller
{
public function fn_me()
{
return $this->getUser();
}
}
Entity:
* #ApiResource(
* collectionOperations={
* "get","post",
* "collName_api_me"={"route_name"="api_me"}
* }
* )
*/
class User implements UserInterface, \Serializable
routes.yaml
api_me:
path: '/api/me'
methods: ['GET']
defaults:
_controller: '\App\Controller\MyUserController::fn_me'
_api_resource_class: 'App\Entity\User'
_api_collection_operation_name: 'collName_api_me'

How to override bundled Doctrine repository in Symfony

I have an independent Symfony bundle (installed with Composer) with entities and repositories to share between my applications that connect same database.
Entities are attached to every applications using configuration (yml shown):
doctrine:
orm:
mappings:
acme:
type: annotation
dir: %kernel.root_dir%/../vendor/acme/entities/src/Entities
prefix: Acme\Entities
alias: Acme
Well, it was the easiest way to include external entities in application, but looks a bit ugly.
Whenever I get repository from entity manager:
$entityManager->getRepository('Acme:User');
I get either preconfigured repository (in entity configuration) or default Doctrine\ORM\EntityRepository.
Now I want to override bundled (or default) repository class for a single entity. Is there any chance to do it with some configuration/extension/etc?
I think, the best looking way is something like:
doctrine:
orm:
....:
Acme\Entities\User:
repositoryClass: My\Super\Repository
Or with tags:
my.super.repository:
class: My\Super\Repository
tags:
- { name: doctrine.custom.repository, entity: Acme\Entities\User }
You can use LoadClassMetadata event:
class LoadClassMetadataSubscriber implements EventSubscriber
{
/**
* #inheritdoc
*/
public function getSubscribedEvents()
{
return [
Events::loadClassMetadata
];
}
/**
* #param LoadClassMetadataEventArgs $eventArgs
*/
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
/**
* #var \Doctrine\ORM\Mapping\ClassMetadata $classMetadata
*/
$classMetadata = $eventArgs->getClassMetadata();
if ($classMetadata->getName() !== 'Acme\Entities\User') {
return;
}
$classMetadata->customRepositoryClassName = 'My\Super\Repository';
}
}
Doctrine Events
Entities are attached to every applications using configuration (yml shown):
Well, it was the easiest way to include external entities in application, but looks a bit ugly.
You can enable auto_mapping
Works for Doctrine versions <2.5
In addition to Artur Vesker answer I've found another way: override global repository_factory.
config.yml:
doctrine:
orm:
repository_factory: new.doctrine.repository_factory
services.yml:
new.doctrine.repository_factory:
class: My\Super\RepositoryFactory
Repository Factory:
namespace My\Super;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
class RepositoryFactory extends DefaultRepositoryFactory
{
/**
* #inheritdoc
*/
protected function createRepository(EntityManagerInterface $entityManager, $entityName)
{
if ($entityName === Acme\Entities\User::class) {
$metadata = $entityManager->getClassMetadata($entityName);
return new ApplicationRepository($entityManager, $metadata);
}
return parent::createRepository($entityManager, $entityName);
}
}
No doubt implementing LoadClassMetadataSubscriber is a better way.
With current symfony 5.3 and doctrine 2.9.5
In your configuration define the service and doctrine.orm.repository_factory:
doctrine:
orm:
#Replace repository factory
repository_factory: 'MyBundle\Factory\RepositoryFactory'
services:
MyBundle\Factory\RepositoryFactory:
arguments: [ '#router', '#translator', '%kernel.secret%' ]
Add you MyBundle/Factory/RepositoryFactory.php file:
<?php declare(strict_types=1);
namespace MyBundle\Factory;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Repository\RepositoryFactory as RepositoryFactoryInterface;
use Doctrine\Persistence\ObjectRepository;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* This factory is used to create default repository objects for entities at runtime.
*/
final class RepositoryFactory implements RepositoryFactoryInterface {
/**
* The list of EntityRepository instances
*
* #var ObjectRepository[]
*/
private $repositoryList = [];
/**
* The kernel secret
*
* #var string
*/
private $secret;
/**
* The RouterInterface instance
*
* #var RouterInterface
*/
private $router;
/**
* The TranslatorInterface instance
*
* #var TranslatorInterface
*/
private $translator;
/**
* Initializes a new RepositoryFactory instance
*
* #param RouterInterface $router The router instance
* #param TranslatorInterface $translator The TranslatorInterface instance
* #param string $secret The kernel secret
*/
public function __construct(RouterInterface $router, TranslatorInterface $translator, string $secret) {
//Set router
$this->router = $router;
//Set secret
$this->secret = $secret;
//Set translator
$this->translator = $translator;
}
/**
* {#inheritdoc}
*/
public function getRepository(EntityManagerInterface $entityManager, $entityName): ObjectRepository {
//Set repository hash
$repositoryHash = $entityManager->getClassMetadata($entityName)->getName() . spl_object_hash($entityManager);
//With entity repository instance
if (isset($this->repositoryList[$repositoryHash])) {
//Return existing entity repository instance
return $this->repositoryList[$repositoryHash];
}
//Store and return created entity repository instance
return $this->repositoryList[$repositoryHash] = $this->createRepository($entityManager, $entityName);
}
/**
* Create a new repository instance for an entity class
*
* #param EntityManagerInterface $entityManager The EntityManager instance.
* #param string $entityName The name of the entity.
*/
private function createRepository(EntityManagerInterface $entityManager, string $entityName): ObjectRepository {
//Get class metadata
$metadata = $entityManager->getClassMetadata($entityName);
//Get repository class
$repositoryClass = $metadata->customRepositoryClassName ?: $entityManager->getConfiguration()->getDefaultRepositoryClassName();
//Return repository class instance
//XXX: router, translator and secret arguments will be ignored by default
return new $repositoryClass($entityManager, $metadata, $this->router, $this->translator, $this->secret);
}
}
Then define your MyBundle/Repository/EntityRepository.php:
<?php declare(strict_types=1);
namespace MyBundle\Repository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository as BaseEntityRepository;
use Doctrine\ORM\Mapping\ClassMetadata;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* EntityRepository
*
* {#inheritdoc}
*/
class EntityRepository extends BaseEntityRepository {
/**
* The RouterInterface instance
*
* #var RouterInterface
*/
protected RouterInterface $router;
/**
* The table keys array
*
* #var array
*/
protected array $tableKeys;
/**
* The table values array
*
* #var array
*/
protected array $tableValues;
/**
* The TranslatorInterface instance
*
* #var TranslatorInterface
*/
protected TranslatorInterface $translator;
/**
* The kernel secret
*
* #var string
*/
protected string $secret;
/**
* Initializes a new LocationRepository instance
*
* #param EntityManagerInterface $manager The EntityManagerInterface instance
* #param ClassMetadata $class The ClassMetadata instance
* #param RouterInterface $router The router instance
* #param TranslatorInterface $translator The TranslatorInterface instance
* #param string $secret The kernel secret
*/
public function __construct(EntityManagerInterface $manager, ClassMetadata $class, RouterInterface $router, TranslatorInterface $translator, string $secret) {
//Call parent constructor
parent::__construct($manager, $class);
//Set secret
$this->secret = $secret;
//Set router
$this->router = $router;
//Set slugger
$this->slugger = $slugger;
//Set translator
$this->translator = $translator;
//Get quote strategy
$qs = $manager->getConfiguration()->getQuoteStrategy();
$dp = $manager->getConnection()->getDatabasePlatform();
//Set quoted table names
//XXX: remember to place longer prefix before shorter to avoid strange replacings
$tables = [
'MyBundle:UserGroup' => $qs->getJoinTableName($manager->getClassMetadata('MyBundle:User')->getAssociationMapping('groups'), $manager->getClassMetadata('MyBundle:User'), $dp),
'MyBundle:Group' => $qs->getTableName($manager->getClassMetadata('MyBundle:Group'), $dp),
'MyBundle:User' => $qs->getTableName($manager->getClassMetadata('MyBundle:User'), $dp),
//XXX: Set limit used to workaround mariadb subselect optimization
':limit' => PHP_INT_MAX,
"\t" => '',
"\n" => ' '
];
//Set quoted table name keys
$this->tableKeys = array_keys($tables);
//Set quoted table name values
$this->tableValues = array_values($tables);
}
}
Then simply extend it in MyBundle/Repository/UserRepository.php:
<?php declare(strict_types=1);
namespace MyBundle\Repository;
/**
* UserRepository
*/
class UserRepository extends EntityRepository {
}

FpOpenIdBundle implement interface error

I am working on an authentication with FpOpenIdBundle but i get this error
Catchable Fatal Error: Argument 1 passed to Fp\OpenIdBundle\Model\UserIdentity::setUser() must implement interface Symfony\Component\Security\Core\User\UserInterface, instance of Doctrine\ODM\MongoDB\DocumentRepository given, called in C:\xampp\htdocs\project\src\AppBundle\Security\User\OpenIdUserManager.php on line 64 and defined
I followed the doc (https://github.com/formapro/FpOpenIdBundle/blob/master/Resources/doc/configure_user_manager.md)
I have made a manager
namespace AppBundle\Security\User;
use AppBundle\Document\User;
use AppBundle\Document\OpenIdIdentity;
use Doctrine\ODM\MongoDB\DocumentManager;
use Fp\OpenIdBundle\Model\UserManager;
use Fp\OpenIdBundle\Model\IdentityManagerInterface;
class OpenIdUserManager extends UserManager
{
/**
* #var DocumentManager
*/
private $documentManager;
/**
* OpenIdUserManager constructor.
*
* #param IdentityManagerInterface $identityManager
* #param DocumentManager $documentManager
*/
public function __construct(IdentityManagerInterface $identityManager, DocumentManager $documentManager)
{
parent::__construct($identityManager);
$this->documentManager = $documentManager;
}
/**
* #param string $identity
* #param array $attributes
*
* #return \Doctrine\ODM\MongoDB\DocumentRepository
*/
public function createUserFromIdentity($identity, array $attributes = array())
{
$user = $this->documentManager->getRepository('AppBundle:User');
$openIdIdentity = new OpenIdIdentity();
$openIdIdentity->setIdentity($identity);
$openIdIdentity->setAttributes($attributes);
$openIdIdentity->setUser($user);
$this->documentManager->persist($openIdIdentity);
$this->documentManager->flush();
return $user;
}
}
The error is returned because of this line
$openIdIdentity->setUser($user);
I use this manager as the service like this
services:
fp_openid.manager:
class: AppBundle\Security\User\OpenIdUserManager
arguments: [ '#fp_openid.identity_manager', '#doctrine.odm.mongodb.document_manager' ]
Who's called by my security.yml
security:
firewalls:
main:
fp_openid:
create_user_if_not_exists: true
provider: openid_user_manager
providers:
openid_user_manager:
id: fp_openid.manager
main:
entity:
{ class: AppBundle:User, property: personaName }
I finally made a MongoDB document as they said
namespace AppBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Symfony\Component\Security\Core\User\UserInterface;
use Fp\OpenIdBundle\Document\UserIdentity as BaseUserIdentity;
/**
* #MongoDB\Document(collection="openid_identities")
*/
class OpenIdIdentity extends BaseUserIdentity
{
/**
* #MongoDB\Id(strategy="auto")
*/
protected $id;
/**
* {#inheritdoc}
* #MongoDB\String
*/
protected $identity;
/**
* {#inheritdoc}
* #MongoDB\Hash
*/
protected $attributes;
/**
* #var UserInterface
*
* #MongoDB\ReferenceOne(targetDocument="AppBundle\Document\User", simple=true)
*/
protected $user;
public function __construct()
{
parent::__construct();
}
}
Everythings is working well except this problem, i don't understand why this is not working whereas i do the same as the doc said. I must implement UserInterface instead of instance of DocumentRepository but they use their user document instead.
Does some already use this bundle and had this issue ?
Thanks for helping
Please carefully read the doc again, in the doc it's:
$user = $this->entityManager->getRepository('AcmeDemoBundle:User')->findOneBy(array(
'email' => $attributes['contact/email']
));

Did you forget a "use" statement for another namespace on Service?

if a access the index login page I get this error:
ClassNotFoundException in appDevDebugProjectContainer.php line 1729:
Attempted to load class "LoginListener" from namespace "Chris\UserBundle".
Did you forget a "use" statement for another namespace?
I wonder what the error comes from. I never implemented a syfmfony2 service.
Here are my sources:
my config.yml
login_listener:
class: 'Chris\UserBundle\LoginListener'
arguments: ['#security.context', '#doctrine']
tags:
- { name: 'kernel.event_listener', event: 'security.interactive_login' }
my Chris/UserBundle/Controller/LoginListener.php
<?php
/**
* Created by PhpStorm.
* User: christian
* Date: 22.07.15
* Time: 11:38
*/
namespace Chris\UserBundle\Controller;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Core\SecurityContext;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Doctrine\Bundle\DoctrineBundle\Registry as Doctrine; // for Symfony 2.1.0+
// use Symfony\Bundle\DoctrineBundle\Registry as Doctrine; // for Symfony 2.0.x
/**
* Custom login listener.
*/
/**
* #Route("blub", name="blub")
*/
class LoginListener
{
/** #var \Symfony\Component\Security\Core\SecurityContext */
private $securityContext;
/** #var \Doctrine\ORM\EntityManager */
private $em;
/**
* Constructor
*
* #param SecurityContext $securityContext
* #param Doctrine $doctrine
*/
public function __construct(SecurityContext $securityContext, Doctrine $doctrine)
{
$this->securityContext = $securityContext;
$this->em = $doctrine->getEntityManager();
}
/**
* Do the magic.
*
* #param InteractiveLoginEvent $event
*/
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
if ($this->securityContext->isGranted('IS_AUTHENTICATED_FULLY')) {
$userId = 1217;
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('UserBundle:User')->find($userId);
$user->setLetzterLogin(new \DateTime("now"));
$em->flush();
}
if ($this->securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
// user has logged in using remember_me cookie
}
// do some other magic here
$user = $event->getAuthenticationToken()->getUser();
// ...
}
}
my UserBundle.php
<?php
/**
* Created by PhpStorm.
* User: christianschade
* Date: 24.01.15
* Time: 15:10
*/
namespace Chris\UserBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class UserBundle extends Bundle {
}
Thanks for your help!
your service definition report the wrong namespace, missing the Controller path, try using the following configuration:
login_listener:
class: 'Chris\UserBundle\Controller\LoginListener'
arguments: ['#security.context', '#doctrine']
tags:
- { name: 'kernel.event_listener', event: 'security.interactive_login' }
Of course, i don't think this class is a real controller

Categories