I have the following code and I just need to test my controller and it takes a request as parameter. But keep getting
Warning: Deprecated JSON test listener used
and
PayrollperiodControllerTest::testPayrollWeekCreateAction
Error: Call to undefined method PayrollperiodControllerTest::bootKernel()
class PayrollperiodControllerTest extends PHPUnit_Framework_TestCase {
/**
* #var \Doctrine\ORM\EntityManager
*/
private $em;
/**
* {#inheritDoc}
*/
public function setUp()
{
self::bootKernel();
$this->em = static::$kernel->getContainer()
->get('doctrine')
->getManager();
}
public function testPayrollWeekCreateAction(Request $request) {
$request = Request::create('http://localhost:8000/web/app_dev.php/payrollperiod/new', 'GET');
$result=$this->em->handle($request);
$this->assertTrue($result->isSuccessful);
}
/**
* {#inheritDoc}
*/
public function tearDown() {
parent::tearDown();
$this->em->close();
$this->em = null; //avoid memory Leaks
}
}
How can I fix these errors?
You should extend the KernelTestCase instead of PHPUnit_Framework_TestCase, so try this:
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
...
class PayrollperiodControllerTest extends KernelTestCase {
instead of this:
class PayrollperiodControllerTest extends PHPUnit_Framework_TestCase {
Hope this help
Related
Infos : I'm new to Symfony and Sonata
My objective : Encrypte the password only for the database side. I would be able to display this password in clear. All this for the field password in the entity Service.
What did i'm trying ? : I tryed to create a Doctrine Listener which use bcrypt encryption
security:
encoders:
App\Entity\Service: bcrypt
here is the HashPasswordLisetener.php in my App\Doctrine (in the $formMapper of my configureFormField function in App\Admin\ServiceAdmin.php i have a row like this ->add('password'))
<?php
namespace App\Doctrine;
use App\Entity\Service;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
class HashPasswordListener implements EventSubscriber
{
private $passwordEncoder;
public function __construct(UserPasswordEncoderInterface $passwordEncoder)
{
$this->passwordEncoder = $passwordEncoder;
}
public function prePersist(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
if (!$entity instanceof Service) {
return;
}
$this->encodePassword($entity);
}
public function preUpdate(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
if (!$entity instanceof Service) {
return;
}
$this->encodePassword($entity);
$em = $args->getEntityManager();
$meta = $em->getClassMetadata(get_class($entity));
$em->getUnitOfWork()->recomputeSingleEntityChangeSet($meta, $entity);
}
public function getSubscribedEvents()
{
return ['prePersist', 'preUpdate'];
}
/**
* #param Service $entity
*/
private function encodePassword(Service $entity)
{
if (!$entity->getPlainPassword()) {
return;
}
$encoded = $this->passwordEncoder->encodePassword(
$entity,
$entity->getPlainPassword()
);
$entity->setPassword($encoded);
}
}
here is the Service entity in the App\Entity
<?php
namespace App\Entity;
use App\Admin\AbstractAdmin;
use App\Repository\ServiceRepository;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* #ORM\Entity(repositoryClass=ServiceRepository::class)
*/
class Service implements UserInterface
{
use TimestampableEntity;
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\Column(type="string", length=255)
*/
private $password;
/**
* #ORM\Column(type="text", nullable=true, length=255)
*/
private $comment;
/**
* #ORM\Column(type="string", length=255)
*/
private $identifier;
private $plainPassword;
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getPassword(): ?string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
public function getComment(): ?string
{
return $this->comment;
}
public function setComment(?string $comment): self
{
$this->comment = $comment;
return $this;
}
public function getIdentifier(): ?string
{
return $this->identifier;
}
public function setIdentifier(string $identifier): self
{
$this->identifier = $identifier;
return $this;
}
/**
* #return mixed
*/
public function getPlainPassword()
{
return $this->plainPassword;
}
/**
* #param mixed $plainPassword
*/
public function setPlainPassword($plainPassword): void
{
$this->plainPassword = $plainPassword;
$this->password = null;
}
public function getRoles()
{
return array('ROLE_USER');
}
public function getSalt()
{
}
public function eraseCredentials()
{
$this->plainPassword = null;
}
public function getUsername()
{
return $this->identifier;
}
}
Also my sonata_admin.yaml :
app.doctrine.hash_password_listener:
class: App\Doctrine\HashPasswordListener
autowire : true
tags:
- { name: doctrine.event_subscriber, connection: 'default' }
The result it give me :
My Probleme :
I understand the function encodePassword is waiting for a UserInterface in 1st arg (instead of my entity) and the password to encrypt in 2nd arg but i don't understand who use this UserInterface ? Where i'm suppose to call it ? to get it ? to send it ?
I think i give lot of details but if i forgot something feel free to notice me ^^
Thanks the time you spend at least reading.
I had a probleme but i was coding an Hashing type of code but i was looking for an encrypting methode. but here is how i deal for having a working hashing :
Step 1 : implementing UserInterface in my Service entity
Step 2 : Replace UserPasswordEncoder for UserPasswordEncoderInterface in the Listener
Step 2.5 : Added all function needed for the UserInterface like eraseCredidential getSalt().. see : this for more details
Step 3 : Adding a getUsername which return this->identifier
Step 4 : using plainPasswords in form field instead of password
Step 5 : added a provider :
app_user:
entity:
class: 'App\Entity\Service'
property: 'identifier'
Step 6 : Using TextType::class for plainPassword form field type + fixing the use with :
Symfony\Component\Form\Extension\Core\Type\TextType
Step 7 : Working
(Special thanks to #msg who helped me a lot)
Because I have many controllers, after the user is logged in, I want to transfer some user settings to Twig. But I don't want to make it in each controller:
Eg:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DefaultController extends Controller
{
public function indexAction()
{
$user = $this->getUser();
$settings = $user->getSettings();
// ...
}
}
Is there a possibility to make it at a higher level from the call of the DefaultController?
Solution 1
Use app.user variable in Twig which is globally accessible:
{{ app.user.username }}
More info: https://symfony.com/doc/current/templates.html#the-app-global-variable
Solution 2
Write custom Twig function:
// src/Twig/UserExtension.php
namespace App\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
use Symfony\Component\Security\Core\Security;
class UserExtension extends AbstractExtension
{
Security $security
public function __construct(Security $security)
{
// Avoid calling getUser() in the constructor: auth may not
// be complete yet. Instead, store the entire Security object.
$this->security = $security;
}
public function getFunctions()
{
return [
new TwigFunction('get_user_settings', [$this, 'getUserSettings']),
];
}
public function getUserSettings()
{
$user = $this->security->getUser();
return $user->getSettings();
}
}
Usage in Twig:
{{ get_user_settings().setting1 }}
More info: https://symfony.com/doc/current/templating/twig_extension.html
How to inject current logged user: https://symfony.com/doc/current/security.html#b-fetching-the-user-from-a-service
Ok, maybe I don't describe it clearly. This is the solution I have searched for:
<?php
namespace AppBundle\Subscriber;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\User\UserInterface;
class ControllerSubscriber implements EventSubscriberInterface
{
/**
* #var TokenStorageInterface
*/
private $tokenStorage;
/**
* #var EntityManagerInterface
*/
private $em;
/**
* ControllerSubscriber constructor.
*
* #param TokenStorageInterface $tokenStorage
* #param EntityManagerInterface $em
*/
public function __construct(TokenStorageInterface $tokenStorage, EntityManagerInterface $em)
{
$this->tokenStorage = $tokenStorage;
$this->em = $em;
}
/**
* #param FilterControllerEvent $event
*/
public function onKernelController(FilterControllerEvent $event)
{
if (!$event->isMasterRequest()) {
return;
}
if (!$token = $this->tokenStorage->getToken()) {
return;
}
if (!$user = $token->getUser()) {
return;
}
// if no user
if (!$user instanceof UserInterface) {
return;
} else {
// .... do something
}
}
/**
* #return array
*/
public static function getSubscribedEvents()
{
return array(
// must be registered before (i.e. with a higher priority than) the default Locale listener
KernelEvents::CONTROLLER => array(array('onKernelController', 1)),
);
}
}
services.yml
app.controller.subscriber:
class: AppBundle\Subscriber\ControllerSubscriber
arguments: ["#security.token_storage","#doctrine.orm.default_entity_manager"]
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
In a symfony 4 project, many services/controllers need log.
Trying to use the advantage of traits & autowire options given by symfony, I created a loggerTrait that will be passed to the different services.
namespace App\Helper;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
trait LoggerTrait
{
/** #var LoggerInterface */
private $logger;
/** #var array */
private $context = [];
/**
* #return LoggerInterface
*/
public function getLogger(): LoggerInterface
{
return $this->logger;
}
/**
* #required
*
* #param LoggerInterface|null $logger
*/
public function setLogger(?LoggerInterface $logger): void
{
$this->logger = $logger;
}
public function logDebug(string $message, array $context = []): void
{
$this->log(LogLevel::DEBUG, $message, $context);
}
...
}
(inspired by symfonycasts.com)
A service will be using this trait
namespace App\Service;
use App\Helper\LoggerTrait;
class BaseService
{
use LoggerTrait;
/** #var string */
private $name;
public function __construct(string $serviceName)
{
$this->name = $serviceName;
}
public function logName()
{
$this->logInfo('Name of the service', ['name' => $this->name]);
}
}
It works perfectly but I couldn't succeed to test it.
I tried to extend KernelTestCase in my test to mock an loggerInterface but I receive Symfony\Component\DependencyInjection\Exception\InvalidArgumentException: The "Psr\Log\LoggerInterface" service is private, you cannot replace it which make perfect sens.
Here my test:
namespace App\Tests\Service;
use App\Service\BaseService;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
class BaseServiceTest extends KernelTestCase
{
private function loggerMock()
{
return $this->createMock(LoggerInterface::class);
}
protected function setUp()
{
self::bootKernel();
}
/**
* #test
* #covers ::logName
*/
public function itShouldLogName()
{
// returns the real and unchanged service container
$container = self::$kernel->getContainer();
// gets the special container that allows fetching private services
$container = self::$container;
$loggerMock = $this->loggerMock();
$loggerMock->expect(self::once())
->method('log')
->with('info', 'Name of the service', ['name' => 'service_test']);
$this->logger = $container->set(LoggerInterface::class, $loggerMock);
$baseService = new BaseService('service_test');
var_dump($baseService->getLogger());
}
}
Is there a solution to test such a logger inside the service ?
You can override the service to be public (only for the test environment) in your config_test.yml as follows:
services:
Psr\Log\LoggerInterface:
public: true
This is commonly done for testing private services.
I use Objectmanger for use Doctrine .. I create instance of objectManager and I create service but I have this bug:
Catchable Fatal Error: Argument 1 passed to Tag\TagBundle\Form\Types\TagsType::__construct() must be an instance of Doctrine\Common\Persistance\ObjectManager, instance of Doctrine\ORM\EntityManager given, called in /var/www/html/TagProject/var/cache/dev/appDevDebugProjectContainer.php on line 2412 and defined
code TagsType:
<?php
namespace Tag\TagBundle\Form\Types;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Tag\TagBundle\Form\DataTransformer\TagsTransformer;
use Symfony\Bridge\Doctrine\Form\DataTransformer\CollectionToArrayTransformer;
use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\Common\Persistance\ObjectManager;
class TagsType extends AbstractType {
/**
* #var ObjectManager
*/
private $manager;
public function __construct(ObjectManager $manager){
$this->manager = $manager;
}
public function buildForm(FormBuilderInterface $builder, array $options){
$builder
->addModelTransformer(new CollectionToArrayTransformer(),true)
->addModelTransformer(new TagsTransformer($this->manager),true);
}
public function getParent(){
return TextType::class;
}
}
code TagsTransformer:
<?php
namespace Tag\TagBundle\Form\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
use Tag\TagBundle\Entity\Tag;
use Doctrine\Common\Persistance\ObjectManager;
class TagsTransformer implements DataTransformerInterface {
/**
* #var ObjectManager
*/
private $manager;
public function __construct(ObjectManager $manager){
$this->manager = $manager;
}
public function transform($value) {
dump($value);
return implode(',',$value);
}
public function reverseTransform($string)
{
$names = explode(',',$string);
$tags = $this->manager->getRepository('TagBundle:Tag')->findBy(['name' => $names]);
$newNames = array_diff($names, $tags);
foreach($names as $name){
$tag = new tag();
$tag->setName($name);
$tags[] = $tag;
}
return $tags;
}
}
code services.yml:
services:
tag.form.types.tages:
class: Tag\TagBundle\Form\Types\TagsType
arguments: ["#doctrine.orm.entity_manager"]
tags:
- { name: form.type }
# tag.example:
# class: Tag\TagBundle\Example
# arguments: ["#service_id", "plain_value", "%parameter%"]
You're injecting an instance of EntityManager so you should use the corresponding interface Doctrine\ORM\EntityManagerInterface for typehinting.
use Doctrine\ORM\EntityManagerInterface;
class TagsTransformer implements DataTransformerInterface
{
/**
* #var EntityManagerInterface
*/
private $manager;
public function __construct(EntityManagerInterface $manager)
{
$this->manager = $manager;
}
I have a problem in redirect path according to role in FOSuserBndle.The problem is in :
FatalErrorException: Error: Call to a member function generate() on a
non-object in.....
This is the event listener
namespace Register\UserBundle\EventListener;
///////////////////////////////
//////////////////////////////
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Router;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\SecurityContext;
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.
*/
class LoginListener
{
protected $router;
/** #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('ROLE_PATIENT')) {
$response = new RedirectResponse($this->router->generate('demands'));
//this->redirect($this->generateUrl('home'));
}
if ($this->securityContext->isGranted('ROLE_THERAPIST')) {
// user has logged in using remember_me cookie
print_r("FFFFFFFFFFFFFTHERAPIST");
die;
}
// do some other magic here
$user = $event->getAuthenticationToken()->getUser();
$type = $user->getType()->getId();
print_r( $type);
die;
// ...
}
}
It seems that the router is not injected in your listener/service.
Listener class :
...
use Symfony\Component\Routing\Router;
class LoginListener
{
protected $container;
protected $em;
protected $router;
public function __construct(ContainerInterface $container, EntityManager $em, Router $router)
{
$this->container = $container;
$this->em = $em;
$this->router = $router;
}
...
}
Service declaration :
my_bundle.my_listener:
class: %my_bundle.my_listener.class%
arguments: [ #service_container, #doctrine.orm.entity_manager, #router ]