I'm trying to pre-populate a database with some User objects, but when I call $user->setPassword('some-password'); and then save the user object, the string 'some-password' is stored directly in the database, instead of the hashed+salted password.
My DataFixture class:
// Acme/SecurityBundle/DataFixtures/ORM/LoadUserData.php
<?php
namespace Acme\SecurityBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Acme\SecurityBundle\Entity\User;
class LoadUserData implements FixtureInterface
{
public function load(ObjectManager $manager)
{
$userAdmin = new User();
$userAdmin->setUsername('System');
$userAdmin->setEmail('system#example.com');
$userAdmin->setPassword('test');
$manager->persist($userAdmin);
$manager->flush();
}
}
And the relevant database output:
id username email salt password
1 System system#example.com 3f92m2tqa2kg8cookg84s4sow80880g test
Since you are using FOSUserBundle, you can use UserManager to do this. I would use this code (assuming you have $this->container set):
public function load(ObjectManager $manager)
{
$userManager = $this->container->get('fos_user.user_manager');
$userAdmin = $userManager->createUser();
$userAdmin->setUsername('System');
$userAdmin->setEmail('system#example.com');
$userAdmin->setPlainPassword('test');
$userAdmin->setEnabled(true);
$userManager->updateUser($userAdmin, true);
}
Call setPlainPassword instead.
<?php
namespace Acme\SecurityBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Acme\SecurityBundle\Entity\User;
class LoadUserData implements FixtureInterface, ContainerAwareInterface
{
private $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
public function load(ObjectManager $manager)
{
$userAdmin = new User();
$userAdmin->setUsername('System');
$userAdmin->setEmail('system#example.com');
$userAdmin->setPlainPassword('test');
$userAdmin->setRoles(array('ROLE_SUPER_ADMIN'));
$manager->persist($userAdmin);
$manager->flush();
}
}
Four lines of code and you are done. It will handle everything for you:
$userManager = $this->container->get('fos_user.user_manager');
$user->setPlainPassword($password);
$userManager->updatePassword($user);
This worked for me
public function load(ObjectManager $manager){
$userAdmin = new User();
$userAdmin->setUsername('admin');
$userAdmin->setPlainPassword('admin');
$userAdmin->setEmail('admin#gmail.com');
$userAdmin->setEnabled(true);
$manager->persist($userAdmin);
$manager->flush();
}
Note the difference when setting the password. Querying the database you find
id username username_canonical email email_canonical enabled salt password
2 admin admin admin#gmail.com admin#gmail.com 1 4gm0bx6jzocgksw0wws8kck04kg40o8 m2ZyJM2+oBIzt/NZdnOX4nFvjV/SWTU1qJqe6dWZ0UwLF5gB8N...
$userAdmin->setUsername('System');
$userAdmin->setEmail('system#example.com');
$userAdmin->setPlainPassword('test');
$userAdmin->setEnabled(true);
setPlainPassword works for me.
/**
* 添加用户
* #param $param
* #return int
*/
public function doAdd($param)
{
$entity = new User();
$em = $this->getEntityManager();
$entity->setUsername($param['username'])
->setPlainPassword($param['password'])
->setEmail($param['email'])
->setEnabled(true)
->setRealName($param['realName']);
$em->persist($entity);
$em->flush();
return $entity->getId();
}
Above worked for me, so I got some conclusion:
1. must use the setPlainPassword
2. must setEnabled(true)
Here a sample class to create an admin user via ORM Fixtures:
<?php
namespace Acme\SecurityBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Acme\SecurityBundle\Entity\User;
class LoadFOSAdminUser extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
{
private $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
public function load(ObjectManager $manager)
{
$userManager = $this->container->get('fos_user.user_manager');
$userAdmin = $userManager->createUser();
$userAdmin->setUsername('admin');
$userAdmin->setEmail('admin#example.com');
$userAdmin->setPlainPassword('admin');
$userAdmin->setEnabled(true);
$userAdmin->setRoles(array('ROLE_ADMIN'));
$userManager->updateUser($userAdmin, true);
}
public function getOrder()
{
return 1;
}
}
Related
please tell me how to get entity manager on laminas framework
Controller:
public function signupAction()
{
$user = new Users();
$user->setUsername('Test');
$user->setEmail('test#mail.ru');
$user->setNumber('+79168415532');
// this one i have persist() and flush()
}
To elaborate on #Aleksey Blossom's answer you need to create a factory from which to inject the entity manager.
use Laminas\ServiceManager\Factory\FactoryInterface;
use Interop\Container\ContainerInterface;
use Doctrine\ORM\EntityManager;
use YourModule\Controller\CategoryController;
class CategoryControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null)
{
$entityManger = $container->get(EntityManager::class);
return new CategoryController($entityManger);
}
}
and in your controller
use Laminas\Mvc\Controller\AbstractActionController;
use Doctrine\ORM\EntityManager;
class CategoryController extends AbstractActionController
{
private EntityManager $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function signupAction()
{
$user = new Users();
$user->setUsername('Test');
$user->setEmail('test#mail.ru');
$user->setNumber('+79168415532');
$this->entityManager->persist($user);
$this->entityManager->flush();
}
}
As a side note I would also consider placing your business logic into models.
Create Factory
class CategoryControllerFactory implements FactoryInterface
{
public function __invoke(\Interop\Container\ContainerInterface $container, $requestedName, ?array $options = null)
{
$entityManger = $container->get(\Doctrine\ORM\EntityManager::class);
return new CategoryController($entityManger);
}
}
I want to add a new UserTeam(which get a team, a user and a role) each time a User create a Team. I created an event subscriber TeamFirstUserAdminSubscriber.php but it doesn't work and I have no error message.
here is my database model:
and here is the file TeamFirstUserAdminSubscriber.php
<?php
namespace App\Events;
use ApiPlatform\Core\EventListener\EventPriorities;
use App\Entity\Team;
use App\Entity\UserTeam;
use App\Repository\RoleUserTeamRepository;
use App\Repository\TeamRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Security;
class TeamFirstUserAdminSubscriber implements EventSubscriberInterface
{
private $security;
private $repository;
private $repositoryT;
private $manager;
public function __construct(Security $security, RoleUserTeamRepository $repository, TeamRepository $repositoryT, EntityManagerInterface $manager)
{
$this->security = $security;
$this->repository = $repository;
$this->repositoryT = $repositoryT;
$this->manager = $manager;
}
public static function getSubscribedEvents()
{
return[
KernelEvents::VIEW => ['setInstanceUserTeam', EventPriorities::POST_WRITE],
];
}
public function setInstanceUserTeam(ViewEvent $event)
{
$team = $event->getControllerResult();
$method = $event->getRequest()->getMethod();
if($team instanceof Team && $method === 'POST')
{
//get the user connected
$user = $this->security->getUser();
//get the last team created
$lastTeam = $this->repositoryT->findLastTeamCreated();
//get the admin role (NOT the symfony one)
$admin = $this->repository->findOneByRoleAdmin('Admin');
//should create a new UserTeam instance with the User, the Team and the RoleUserTeam wanted
$userTeam = new UserTeam();
$userTeam->setUser($user);
$userTeam->setTeam($lastTeam);
$userTeam->setRoleUserTeam($admin);
$manager = $this->manager;
$manager->persist($userTeam);
$manager->flush();
}
}
The new UserTeam is not created in the databse when I try it out with postman, but the Team is well created.
I think I am missing something but I don't know what.
Could anyone help me ?
I can't see your full code(controller, forms etc), but you can achieve this without an event listener. As you already know, what team to be assigned for a user, why don't you assign that on the entity when creating the user object. For example if you using form in the controller
public function addAdminUser(Request $request, RoleUserTeamRepository $repository, TeamRepository $repositoryT, EntityManagerInterface $manager)
{
$user = new User();
$form = $this->createForm(UserForm::class, $user);
$form->handleRequest($form);
if ($form->isSubmitted && $form->isValid()) {
//get the last team created
$lastTeam = $this->repositoryT->findLastTeamCreated();
//get the admin role (NOT the symfony one)
$admin = $this->repository->findOneByRoleAdmin('Admin');
//should create a new UserTeam instance with the User, the Team and the
RoleUserTeam wanted
$userTeam = new UserTeam();
$userTeam->setUser($user);
$userTeam->setTeam($lastTeam);
$userTeam->setRoleUserTeam($admin);
$user->setUserTeam($userTeam);
//persist the user
$manager->persist($user);
$manager->flush();
}
}
If you want to use events I would suggest use Doctrine events. You can use prePersist event on user entity to achieve same result. Doctrine Events
I solved my problem, I needed a cascade persist in my entities. Here, if it can hepl some people :
I had this in the Team entity
public function __construct()
{
$this->id = Team::class;
$this->userTeams = new ArrayCollection();
$this->categories = new ArrayCollection();
}
public function userTeam()
{
$newUserTeam = new UserTeam();
$newUserTeam->setTeam($this);
$this->userTeams->add($newUserTeam);
}
UserTeam entity, I had to add cascade={"persist"} in the relation ManyToOne:
class UserTeam
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity=Team::class, inversedBy="userTeams", cascade={"persist"})
* #ORM\JoinColumn(nullable=false)
* #Groups({"users_read", "userTeam_read"})
*/
private $team;
And the TeamByUserSubscriber that I modified :
<?php
namespace App\Events;
use ApiPlatform\Core\EventListener\EventPriorities;
use App\Entity\Team;
use App\Entity\UserTeam;
use App\Repository\RoleUserTeamRepository;
use App\Repository\TeamRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Security;
class TeamByUserSubscriber implements EventSubscriberInterface
{
private $security;
private $repository;
private $entityManager;
public function __construct(Security $security, RoleUserTeamRepository $repository, EntityManagerInterface $entityManager)
{
$this->security = $security;
$this->repository = $repository;
$this->entityManager = $entityManager;
}
public static function getSubscribedEvents()
{
return[
KernelEvents::VIEW => ['setUserForTeam', EventPriorities::PRE_VALIDATE],
];
}
public function setUserForTeam(ViewEvent $event)
{
$team = $event->getControllerResult();
$method = $event->getRequest()->getMethod();
if($team instanceof Team && $method === 'POST')
{
//get the connected User
$user = $this->security->getUser();
//put the current User to the team we are creating (as the creator of the team)
$team->setUser($user);
//get the Admin role from the RoleUserTeam entity
$admin = $this->repository->findOneByRoleAdmin('Admin');
//create a new instance of UserTeam with the connected User, the Team we are creating and the role
$userTeam = new UserTeam();
$userTeam->setUser($user);
$userTeam->setTeam($team);
$userTeam->setRoleUserTeam($admin);
$manager = $this->entityManager;
$manager->persist($userTeam);
$manager->flush();
}
}
I have tried to create DataFixtures, I think that my code is correct because if I tried on another project it's worked. So I don't understand why just in that my actual project , the Object Manager isn't working and my IDE is underlying Object Manager.
My error:
Declaration must be compatible with FixtureInterface->load(manager: \Doctrine\Persistence\ObjectManager)
My code:
<?php
namespace App\DataFixtures;
use App\Entity\User;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
class UserFixtures extends Fixture
{
public function __construct(UserPasswordEncoderInterface $passwordEncoder)
{
$this->passwordEncoder =$passwordEncoder;
}
public function load(ObjectManager $manager)
{
foreach ($this->getUserData() as [$email,$password,$lastname,$firstname,$company,$language,$enabled,$pictures])
{
$user = new User();
$user->setEmail($email);
$user->setPassword($this->passwordEncoder->encodePassword($user,$password));
$user->setLastname($lastname);
$user->setFirstname($firstname);
$user->setCompany($company);
$user->setLanguage($language);
$user->setEnabled($enabled);
$user->setPictures($pictures);
}
$manager->flush();
}
private function getUserData() : array {
return [
['test#gmail.com','test','paul','marc','WKCompany','BE',1,'https://media.istockphoto.com/photos/businessman-silhouette-as-avatar-or-default-profile-picture-picture-id476085198?k=6&m=476085198&s=612x612&w=0&h=5cDQxXHFzgyz8qYeBQu2gCZq1_TN0z40e_8ayzne0X0=']
];
}
}
it looks simple type error. I only changed ObjectManager namespace.
use App\Entity\User;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
class UserFixtures extends Fixture
{
public function __construct(UserPasswordEncoderInterface $passwordEncoder)
{
$this->passwordEncoder =$passwordEncoder;
}
public function load(ObjectManager $manager)
{
foreach ($this->getUserData() as [$email,$password,$lastname,$firstname,$company,$language,$enabled,$pictures])
{
$user = new User();
$user->setEmail($email);
$user->setPassword($this->passwordEncoder->encodePassword($user,$password));
$user->setLastname($lastname);
$user->setFirstname($firstname);
$user->setCompany($company);
$user->setLanguage($language);
$user->setEnabled($enabled);
$user->setPictures($pictures);
}
$manager->flush();
}
private function getUserData() : array {
return [
['test#gmail.com','test','paul','marc','WKCompany','BE',1,'https://media.istockphoto.com/photos/businessman-silhouette-as-avatar-or-default-profile-picture-picture-id476085198?k=6&m=476085198&s=612x612&w=0&h=5cDQxXHFzgyz8qYeBQu2gCZq1_TN0z40e_8ayzne0X0=']
];
}
}
trying to make an subscriber for Entity actions (CRUD) and cannot figure it out.
I know there is a way, where I can make listener and send him 3 different events, but that's not what I want to reach, I dont even think is good solution.
Event Subscriber
<?php
namespace App\EventListener;
use App\Entity\Log;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Events;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
/**
* Part of program created by David Jungman
* #author David Jungman <davidjungman.web#gmail.com>
*/
class EntitySubscriber implements EventSubscriberInterface
{
/**
* #var EntityManagerInterface
*/
private $em;
/**
* #var TokenStorageInterface
*/
private $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage, EntityManagerInterface $em)
{
$this->em = $em;
$this->tokenStorage = $tokenStorage;
}
public static function getSubscribedEvents()
{
return array(
Events::postPersist,
Events::postUpdate,
Events::postRemove,
);
}
public function postUpdate(LifecycleEventArgs $args)
{
$this->logEvent($args, "remove");
}
public function postRemove(LifecycleEventArgs $args)
{
$this->logEvent($args, "remove");
}
public function postPersist(LifecycleEventArgs $args)
{
$this->logEvent($args, "create");
}
private function logEvent(LifecycleEventArgs $args, string $method)
{
$entity = $args->getEntity();
if($entity->getShortName() != "Log")
{
$user = $this->tokenStorage->getToken()->getUser();
$log = new Log();
$log
->setUser($user)
->setAffectedTable($entity->getShortName())
->setAffectedItem($entity->getId())
->setAction($method)
->setCreatedAt();
$this->em->persist($log);
$this->em->flush();
}
}
}
and my Service.yaml part
App\EventListener\EntitySubscriber:
tags:
- { name: doctrine.event_subscriber, connection: default }
I have tried:
I've looked into these 2 official tutorials:
-https://symfony.com/doc/current/event_dispatcher.html
-https://symfony.com/doc/current/doctrine/event_listeners_subscribers.html
but neither helped.. when I use shown part of config, my computer freeze.
When I try to debug it, I can see these methods active
( php bin/console debug:event-dispatcher )
but they are listening on "event" event
Doctrine has it's own events handler/subscriber system. However, with the class Symfony\Component\EventDispatcher\EventSubscriberInterface; that you are implementing, that is from the Symfony event system.
<?php
use Doctrine\ORM\Events;
use Doctrine\Common\EventSubscriber; // **the Doctrine Event subscriber interface**
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
class MyEventSubscriber implements EventSubscriber
{
public function getSubscribedEvents()
{
return array(
Events::postUpdate,
);
}
public function postUpdate(LifecycleEventArgs $args)
{
$entity = $args->getObject();
$entityManager = $args->getObjectManager();
// perhaps you only want to act on some "Product" entity
if ($entity instanceof Product) {
// do something with the Product
}
}
}
I'm trying to create an image fixture for SonataMediaBundle. The media is saved in the database and shown in the admin interface, but the image is missing. There is no difference between the records created by fixture and admin interface.
Here is my Fixture in AppBundle\DataFixtures\ORM\LoadMediaBundleMediaData
<?php
namespace AppBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\HttpFoundation\File\File;
use Application\Sonata\ClassificationBundle\Entity\Context;
use Application\Sonata\ClassificationBundle\Entity\Category;
class LoadMediaBundleMediaData extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
{
/**
* #var ContainerInterface
*/
private $container;
/**
* {#inheritDoc}
*/
public function load(ObjectManager $manager)
{
$context = new Context();
$context->setId('default');
$context->setName('default');
$context->setEnabled(true);
$manager->persist($context);
$manager->flush();
$category = new Category();
$category->setName('Default');
$category->setContext($context);
$category->setEnabled(true);
$manager->persist($category);
$manager->flush();
$media1File = new File(__DIR__ . '/../Assets/Images/image.jpg');
$mediaManager = $this->container->get('sonata.media.manager.media');
$media1 = $mediaManager->create();
$media1->setEnabled(true);
$media1->setBinaryContent($media1File);
$media1->setName('brunnkogel.jpg');
$media1->setContext('default');
$media1->setProviderName('sonata.media.provider.image');
$media1->setProviderStatus(1);
$mediaManager->save($media1);
$manager->persist($media1);
$manager->flush();
}
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
/**
* {#inheritDoc}
*/
public function getOrder()
{
return 40;
}
}
If I create a media in the admin interface it works and the image is saved at web/uploads/media/default/0001/01/c4412442f8f146db6acaec10751fb54e4c80e8c5.jpeg. Also the thumbnails are in this directory. If I create the media by fixtures, the files in web/uploads/media are missing.
I'm using Symfony 2.8 and SonataMediaBundle 3.0.
How can I solve this issue?