Validating an entity in EasyAdmin - symfony

How to validate my entity? I want to check if the url property is unique. So I did this:
My Post.php entity:
use Symfony\Component\Validator\Constraints as Assert;
....
#[ORM\Column(length: 255)]
#[Assert\Unique]
private ?string $url = null;
....
This is obviously not enough because my entity is not validated on create/update. So I tried to add a group like:
....
#[Assert\GroupSequence(['post_validation'])]
class Post
....
And call the group in the PostGroupController.php:
public function configureCrud(Crud $crud): Crud
{
return $crud
->setEntityLabelInSingular($this->translator->trans('post.post'))
->setEntityLabelInPlural($this->translator->trans('post.posts'))
->setSearchFields(['title'])
->setFormOptions(['validation_groups' => 'post_validation']);
}
But this doesn't work either. By not working I mean that the record is saved/updated with not unique url. So what is wrong with this EasyAdmin validation or I am doing the things wrong ? P.S. I have the symfony validator installed.

I didn't use the assert, please try this one:
#[ORM\Column(type: 'string', unique: true)]
private $url;

Related

How to access repository methods for an entity in symfony2?

I am stuck with a problem please help me with it. Here is the scenarario:
I have an entity "User" and corresponding repository "UserRepository", inside my entity there are only getter and setter methods. All custom queries I have written to UserRepository. Now inside my UserController I am trying to access repository methods which I am not able to do so.
e.g.
User entity:
class User
{
...
public function getId()
{
return $this->id;
}
public function setId($id)
{
return $this->id=$id;
}
public function setProperty($property)
{
$this->property = $property;
}
public function getProperty()
{
return $this->property;
}
....
}
?>
UserRepository:
class UserRepository extends EntityRepository
{
public function findUsersListingById($id)
{
$queryBuilder = $this->getEntityManager()->createQueryBuilder();
$query = $em->createQuery(
"SELECT U
FROM UserEntityPathGoesHere
WHERE U.id IN (".implode(",", $id).")"
);
$users = $query->getResult();
return $users;
}
public function sayHelloWorld(){
echo ' Hello World';
}
}
?>
UserController
class UserController
{
...
$users=$this->getDoctrine()
->getRepository('MyUserEntityPath')
->findUsersListingById($ids);
//now I have multiple users I want to iterate through each user for associating additional data with each user
foreach($users as $user)
{
$temp = array();
//I am able to access getId method which is defined in User entity
$temp['id'] = $user->getId();
//however I am not able to access method from UserRepository, I tried something like below which gives me error call to undefined function sayHelloWorld
$temp['status'] = $user->sayHelloWorld();
....
}
}
....
How can I access repository methods for an entity? Is it possible ? If not then what are the alternatives for the solution?
Everything is possible however you should not access the entity's repository from the entity itself because of the separation of concerns.
See this Stackoverflow answer for more details.
Basically, the whole idea is that you want to have your application organized the following way.
In short:
Controller > Repository > Entities.
It should not go in the other direction otherwise it creates a mess.
If you want to go a bit further into the separation of concerns you could do the following.
Controller > Service > Repository > Entities
Alternative solutions:
Create a Twig extension that access a service (which access a repository) or a repository.
Create a method in your repository, call the method in your controller, map the data to IDs (keys of array are the IDs), pass the array to the template and then pull the data from the array using the entity IDs
Create a method in your repository, call the method in your controller, inject the data into your entities and access the data through the entity in your template.
There are probably others but you would know better how your application is organized.
If the bundle is Acme/DemoBundle, then one would expect at a minimum
User entity
namespace Acme/DemoBundle/Entity
use Doctrine\ORM\Mapping as ORM;
/**
*
* #ORM\Table(name="user")
* #ORM\Entity(repositoryClass="Acme/DemoBundle/Entity/UserRepository")
*/
class User
{
...
}
User repository
namespace Acme/DemoBundle/Entity
use Doctrine\ORM\Mapping as ORM;
class UserRepository extends EntityRepository
{
...
}
It is also true that with an array of ids, one can also do the following in a controller:
...
$em = $this->getDoctrine()->getManager();
$users = $em->getRepository("AcmeDemoBundle:User")->findAllById($idArray);
...
To iterate thru users in a controller, one can then use a foreach loop as in:
foreach ($users as $user) {
//each user is an array
...
$id = $user['id'];
...
}
or in a template:
{% for user in users %}
...
{{ user.firstName }}
...
{% endfor %}
You need to declare the UserRepository as an EntityRepository for your user entity. In your User entity add this annotation:
/**
* #ORM\Entity(repositoryClass="Acme\StoreBundle\Entity\UserRepository")
*/
See the docs for a more detailed description.
You can use the postLoad event from doctrine and inject everything you want into the entity. The event listener looks like:
<?php
namespace AppBundle\EventListener;
use AppBundle\Entity\MyEntity;
use Doctrine\ORM\Event\LifecycleEventArgs;
/**
* Class MyEntityListener
*/
class MyEntityListener
{
public function postLoad(LifecycleEventArgs $eventArgs)
{
/** #var MyEntity $document */
$document = $eventArgs->getEntity();
if(!($document instanceof MyEntity)){
return;
}
$document->setEntityManager($eventArgs->getEntityManager());
}
}
and service.yml:
services:
app.myentity.listener:
class: AppBundle\EventListener\MyEntityListener
tags:
- { name: doctrine.event_listener, event: postLoad }
Of cource your Entity needs the method setEntityManager and your're ready.

How to call doctrine in an entity class using symfony

Am using symfony framework for my application. And to save records in database I want call the $this->getDoctrine()->getManager(); method in my entity class. But when I did that it gave me the error:
Call to undefined method getDoctrine(),
Can some one tell me what is the right way to do this.
My entity class is like:
namespace Acme\SuperbAppBundle\Entity;
use Symfony\Component\DependencyInjection\Container;
use Doctrine\ORM\Mapping as ORM;
class Users
{
/**
* #var integer
*/
private $id;
/**
* #var string
*/
private $firstName;
/**
* #var string
*/
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set firstName
*
* #param string $firstName
* #return Users
*/
public function setFirstName($firstName)
{
$this->firstName = $firstName;
return $this;
}
/**
* Get firstName
*
* #return string
*/
public function getFirstName()
{
return $this->firstName;
}
function __construct($firstName){
$this->setFirstName($firstName);
}
function save(){
$em = $this->getDoctrine()->getManager();
$em->persist($create);
$em->flush();
}
}
And my controller method is like:
public function test(){
$create = new Users('Rajat');
$create->save();
}
Your save method is attempting to call
$this->getDoctrine();
Whereby $this is the current Class, and any other Class it inherits. As it stands, your current Class, User, is standalone, and does not have a getDoctrine() method. If your Class were to extend the Controller Class, it would have access to that method:
class User extends Controller
I believe this simple fix will work, although it probably doesn't make real sense for it to extend Controller, as it is a User Entity, and unrelated to a Controller. A preferred, more advanced method, would be to inject the Doctrine service into the User class.
Ok, first of all Doctrine Entities :
Handle the entity generation and configuration
Declare the operations on the setters and getters.
If you wana save an object into your entity there it's your User, you have two way to store this user:
One:
You can use entity manager to store a user and the entity will help you to create the right object using the seters and getters:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use PATH\TO\Users;
class ExampleController extends Controller
{
public function examplefunction()
{
$em = $this->getDoctrine()->getManager();
$entity = new Users();
$entity->setFirstName('Rajat');
$em->persist($entity);
$em->flush();
}
}
The other way is to create this entry using QueryBuilder but it's a bad way in your case.
Oh, i forgot please delete the save method in your entity Doctrine manager allready implement it.
Your controller probably doesnt extends Symfony\Bundle\FrameworkBundle\Controller\Controller ...
You should have controller defined like this example:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DefaultController extends Controller
{
}
Entity class does not extends ContainerAware / Controller, so you can't call $this->getDoctrine()->getManager(). I don't think your Entity class should extend to a Controller. Because your entity class will become a controller instance just because you want to access the doctrine manager. That's a not good practice. What you can do is inject doctrine manager to your Entity class through services.
I wrote a blog few weeks ago regarding injecting services container and accessing through constructor. You can inject doctrine entity manager in the same way you inject services container. You can take a look at that if you like :- http://anjanasilva.com/blog/injecting-services-in-symfony-2/
Here's a nice question regarding injecting doctrine manager. Make sure you read the answer as well. :- Symfony 2 EntityManager injection in service
And another nice tutorial on injecting custom repository manager instead of injecting the whole entity manager. Which I believe even a good solution. :- http://php-and-symfony.matthiasnoback.nl/2014/05/inject-a-repository-instead-of-an-entity-manager/
Hope this helps to increase your understanding about Symfony 2.
Cheers!

Get entityManager inside an Entity

I'd like to use, something like:
$em = $this->getEntityManager();
Inside a Entity.
I understand I should do this as a service but for some testing purposes, I want to access it from an Entity.
Is it possible to achieve that?
I've tried to:
$em = $this->getEntityManager();
$profile_avatar = $em->getRepository('bundle:Perfils')->findOneByUser($this-getId());
But isn't working.
Fatal error: Call to undefined method
Proxies\webBundleEntityUserProxy::getEntityManager() in
/opt/lampp/htdocs/web/src/Pct/bundle/Entity/User.php on line
449
Why am I trying to do it this way?
I've 3 kinds of users: Facebook, Twitter and MyOwnWebsite users. Each of them have differents avatar which links facebook's profile, twitter's or otherwise, if its myownwebsite user, I retrieve the avatar from a URL in a database. For now, I don't want to create a service, because I'm just trying to make it working, to test it, not to create a final deployment. So this is why I'm trying to call Entity manager from an Entity. I don't want, by now, to modify configuration files, just this entity.
As pointed out (again) by a commenter, an entity manager inside an entity is a code smell. For the OP's specific situation where he wished to acquire the entity manager, with the least bother, a simple setter injection would be most reliable (contrary to my original example injecting via constructor).
For anyone else ending up here looking for a superior solution to the same problem, there are 2 ways to achieve this:
Implementing the ObjectManagerAware interface as suggested by https://stackoverflow.com/a/24766285/1349295
use Doctrine\Common\Persistence\ObjectManagerAware;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Entity implements ObjectManagerAware
{
public function injectObjectManager(
ObjectManager $objectManager,
ClassMetadata $classMetadata
) {
$this->em = $objectManager;
}
}
Or, using the #postLoad/#postPersist life cycle callbacks and acquiring the entity manager using the LifecycleEventArgs argument as suggested by https://stackoverflow.com/a/23793897/1349295
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\HasLifecycleCallbacks()
*/
class Entity
{
/**
* #ORM\PostLoad
* #ORM\PostPersist
*/
public function fetchEntityManager(LifecycleEventArgs $args)
{
$this->setEntityManager($args->getEntityManager());
}
}
Original answer
Using an EntityManager from within an Entity is VERY BAD PRACTICE. Doing so defeats the purpose of decoupling query and persist operations from the entity itself.
But, if you really, really, really need an entity manager in an entity and cannot do otherwise then inject it into the entity.
class Entity
{
private $em;
public function __contruct($em)
{
$this->em = $em;
}
}
Then invoke as new Entity($em).
Best way is to use Life Cycle: #ORM\HasLifecycleCallbacks
And you can use the appropriate Event as you want to get result:
#postLoad
#postPersist
...
Calling the Entity Manager from inside an Entity is a bad practice! You should keep your entities as simple as possible.
For what purpose do you need to call the Entity Manager from an Entity?
What I think you should do is, instead of using the Entity Manager inside your entity, is to create a custom repository for your entity.
In your entity ORM file, add an entry as follows (or in your entity class annotations if not using YML):
App\Bundle\Profils:
# Replace the above as appropiate
type: entity
table: (your table)
....
repositoryClass: App\Bundle\CustomRepos\ProfilsRepository
# Replace the above as appropiate.
# I always put my custom repos in a common folder,
# such as CustomRepos
Now, create a new PHP class that has the namespace above:
//Your ProfilsRepository.php
<?php
namespace App\Bundle\CustomRepos;
use Doctrine\ORM\EntityRepository;
class ProfilsRepository extends EntityRepository
{
/**
* Will return the user url avatar given the user ID
* #param integer $userID The user id.
#return string The avatar url
*/
public function getUserProfile($userId)
{
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder();
$qb->select... (your logic to retrieve the profil object);
$query = $qb->getQuery();
$result = $query->getResult();
return $result;
}
}
Finally, in your Controller:
// Your controller
<?php
namespace <class namespace>;
...
use App\Bundle\CustomRepos\ProfilsRepository;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
...
class YourClassNameController extends Controller
{
public function yourAction()
{
$userId = <get the user ID>;
// Pass the name of your entity manager to the
// getManager function if you have more than one and
// didn't define any default
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('Profils');
$avatar = $repo->getUserProfile($userId);
...
}
}
You need to set the services.yml with:
services:
your_service_name:
class: AppBundle\Controller\ServiceController
arguments: [ #doctrine.orm.entity_manager ]
You need to set also the Controller with the following constructor:
public function __construct(\Doctrine\ORM\EntityManager $em)
{
$this->em = $em;
}
and use $this->em in the controller
(for example $connection = $this->em->getConnection();)

Get many-to-many entities in a form properly

I'm new with symfony, I looked around but I didn't find the right answer to my problem.
I have two entities linked with a many-to-many relation. Entity User -> Entity FollowedUser.
One User should be able to follow several FollowedUser and one FollowedUser should has several Users who follow him.
My problem is that when I try to list all FollowedUser for one User, say my CurrentUser, I get all FollowedUser not only those associated to my CurrentUser.
Here is my code.
User Entity (src/MyBundle/Entity/User.php) :
namespace MyBundle\Entity;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="My_user")
*/
class User extends BaseUser
// ...
/**
* #var FollowedUser[] $followedUsers
*
* #ORM\ManyToMany(targetEntity="MyBundle\Entity\FollowedUser")
*/
private $followedUsers;
// ...
public function getFollowedUsers()
{
return $this->followedUsers;
}
}
UserType:
namespace MyBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use MyBundle\Entity\FollowedUserRepository;
class UserType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('followedUsers'); // This shows me the whole table
//,'entity' , array('class' => 'MyBundle\Entity\FollowedUser',
// 'multiple' => true,
// 'query_builder' => function(FollowedUserRepository $followedUserRepo) use ($options) {
// $followedUsers = $options['data']->getFollowedUsers();
// $choices = array();
// foreach ( $followedUsers as $followedUser){
// $choices[] = $followedUser->getId();
// }
// $qb = $followedUserRepo->createQueryBuilder('u');
// $qb->select('u')
// ->where( $qb->expr()->in('u.id',$choices));
// return $qb;
// }
// ));
}
public function getName()
{
return 'followedUser';
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'MyBundle\Entity\User',
);
}
}
NB: The lines I commented is the only way I found to do what I want. But it does not feel the right way to do it.
In my Controller:
$currentUser = $this->container->get('security.context')->getToken()->getUser();
$followedUsers = $currentUser->getFollowedUsers(); // That works properly
$form = $this->createForm(new UserType(),$currentUser);
EDIT :
Actually my problem was that I forgot some annotation in my ManyToMany declaration. Here is the default annotation which should be used for an unidirectionnal ManyToMany relation:
/**
* #ManyToMany(targetEntity="Group")
* #JoinTable(name="users_groups",
* joinColumns={#JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
Solution was found in the doctrine documentation here : doctrine2 unidirectionnal ManyToMany.
If specified, this is used to query the subset of options (and their
order) that should be used for the field. The value of this option can
either be a QueryBuilder object or a Closure. If using a Closure, it
should take a single argument, which is the EntityRepository of the
entity.
Without specifying query_builder Symfony 2 option you'll get all FollowedUser, as you said. The meaning of:
$builder->add('followedUsers');
Is something like:
Add a field whose property is followedUsers of the User class.
Guess it's type (entity type).
query_builder option not specified? Then fetch all users.
Select (depending of expanded and multiple options) those (options) users actually following the user from the model, leaving all other (options) users unselected.
So, question for you is: why you want to display only the users following the user in the form model? It's a no sense... the actual user of the application will never be able to add new following users.

Symfony2 - FOSUserBundle - FindUserBy<field_in_custom_UserBundle>

I´ve created my own user Bundle, extending FOSUserBundle.
In my UserBundle, I have a memberID field, with its setters and getters.
I can already find users by memberID using EntityManager, and then I could find the user through UserManager matching the username/email/... obtained with that EntityManager query, but...
Is there a way to findUserByMemberID using UserManager?
Thank you.
Thank you for your replies. It seems it´s easier than all this stuff.
OwnUserBundle:
/**
* #ORM\Column(type="string")
*
*/
protected $memberID;
public function getMemberID()
{
return $this->memberID;
}
public function setMemberID($memberID)
{
$this->memberID = $memberID;
}
You can query FOSUserBundle:
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->findUserBy(array('memberID' => '123'));
Then, using method findUserBy(array(*OwnUserBundle_field* => *search_parameter_value*)) you´ll get the user/s instance.
Every query that is "not standard" one has to be written into a repository class
You have also to relate this class with one that represent you data model.
Suppose that your entity is called User, you have to do something like this
/**
* VendorName\UserBundle\Entity\User
*
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="VendorName\UserBundle\Repository\UserRepository")
*/
class User implements AdvancedUserInterface
{
[...]
This says that every "custom" query for that entity will be fit into that repository class.
Now you have to create the repository
class UserRepository extends EntityRepository implements UserProviderInterface
{
public function findUserByMemberID($id)
{
/* your logic here */
}
[...]
and you can use that in the following way
$userRepo = $this->em->getRepository('VendorUserBundle:User');
$userRepo->findUserByMemberID();
You could extend the UserManager from the FOSUserBundle in your bundle and write your own method. And you could follow these instructions http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes

Resources