Problem with auto-updating column create_at - symfony

After $this->em->flush(); updated columns create_at and update_at but need only update_at. I tried to fix trait-file with set\get but its not give result.

if $this->em->flush(); creates the entity, it will update both field otherwise it should only update updated_at field.

You can use this bundle StofDoctrineExtensionsBundle.
And activate the extensions what you want.
in yaml config you can activate timestampable.
stof_doctrine_extensions:
default_locale: en_US
orm:
default:
timestampable: true
and you can use TimestampableEntity in your entity like this.
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\TokenRepository")
* #ORM\Table(name="tokens")
*/
class Token
{
use TimestampableEntity;
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
}
so it will update and create your entities dates. :)

Related

Symfony Accessing to parent entity inside entity class

In Symfony 5, I've created 2 entities related with a ManyToOne relation : Project is the parent, Serie is the child.
Project entity :
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\SerieRepository")
*/
class Serie
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=100)
*/
private $name;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Project", inversedBy="series")
* #ORM\JoinColumn(nullable=false)
*/
private $project;
[...]
}
Serie entity :
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\ProjectRepository")
*/
class Project
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=100)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Serie", mappedBy="Project", orphanRemoval=true)
*/
private $series;
[...]
}
I didn't write down here, but you also have all the getter and setter for each class.
I need to access to the Project entity in the Serie entity. For example : accessing to the name property of Project entity by adding a getProjectName method in Serie class.
public function getProjectName()
{
return $this->project->getName();
}
But this is not working as the Project entity is not loaded (only the id). How can I get this value, without adding a repository in the entity class or passing any argument to the getProjectName method ? (maybe a Doctrine annotation...).
In doctrine entities in relations are lazy-loaded, that means, when you have not accessed anything on $this->project (or the referenced project), it will just be of type Project^ (notice the ^) and it will have an attribute called __initialized__ (or similar) with the value false (check by dump($this->project);). This means, that the entity is NOT loaded, yet.
Lazy-loading means, it will be loaded if it's actually needed (thus reducing database accesses), and before that, a proxy object will take the place of the entity. It'll register all calls done to it, load the entity if necessary and forward all calls to it.
So, to load a lazy-loaded entity, you just call one of its methods. So $this->project->getName() should already work nicely. (verify by calling dump($this->project); afterwards).
If it doesn't, something else is missing/wrong/dysfunctional.
Ok, thank you Jakumi. You are right, on that way, it's working fine.
To complete your explanation, if you want to get the child elements, like :
$series = $project->getSeries();
You will have an empty table (a foreach loop won't get any item). This is because $series is a Doctrine Collection. You need to use :
$series = $project->getSeries()->getValues();
to have a fully completed array.
I spend 2 hours on the topic, I hope this will help somebody else.

FOS Bundle User - multiple roles

I'm exploring the possibilities of FOS Bundle User.
Thanks to Knpuniversity (https://knpuniversity.com/screencast/fosuserbundle/roles-canonical-fields) I discovered this good bundle to manage users.
In my case I also need multiple roles BUUUUUUT I don't want to save it with an array of roles in a field from user table. My intention is to use more tables with a relation 'n' to 'm' where 1 user have 'n' roles and 1 role can be used by 'n' users also.
So instead of having one table to manage users and roles, I will need one table for users, one table for roles and a last one to make the relationship n-m between them. I need that because I will use this structure for others functionalities and saving the roles as an array... will create more problems than solve... in my case.
What you propose to achieve that?
Perhaps another bundle?
Perhaps a simple solution to adapt the bundle to my requirements?
What do you think I could do?
With the FOSUserBundle indeed you can manage all kind of roles through the groups class that this bundle creates.
In the normal flow from symfony these groups they doesn't exist by default. Its an extra feature that provides this bundle, but it helps you to manage better the roles for the users.
This is what I am doing and works pretty well for me:
I have a User,Role and a Group entities
User Entity
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
Group Entity
use FOS\UserBundle\Model\Group as BaseGroup;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_group")
*/
class Group extends BaseGroup
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
}
all this is from FOS docs
Now the roles by default comes as array but symfony provides a Symfony\Component\Security\Core\Role\Role class to extend from it.
so your role class should look like this:
Role Entity
use Symfony\Component\Security\Core\Role\Role as BaseRol;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_role")
*/
class Role extends BaseRol
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
To do the magic you just need to add the mapping information as follow.
To support groups in users entities
/**
* #ORM\ManyToMany(targetEntity="path/to/my/groupEntity")
* #ORM\JoinTable(name="join_table_name",
* joinColumns={#ORM\JoinColumn(name="join_column_name_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="join_column_name_id", referencedColumnName="id")}
* )
*/
protected $groups;
To support roles in both Group and User entity
/**
* #ORM\ManyToMany(targetEntity="path/to/my/roleEntity")
* #ORM\JoinTable(name="join_table_name",
* joinColumns={#ORM\JoinColumn(name="join_column_name_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="join_column_name_id", referencedColumnName="id")}
* )
*/
protected $roles;
After that update your database and you are ready to go.
Finally what I did is use the functionality from the FOSUserBunlde using roles and groups where each role is used as permissions to execute controller and the groups to manage easily all the roles from a user.
I would create a new UserManager class extending the FosUserManager class overriding the role related methods. But not sure about if it's worthy or not. Also you will have to create a middle plain object that extends from the FosUserBundle User model and then use it to create yor user Entity. In this middle object you will have to change the way Roles are stored.
Seriously I'm not sure of this is better than starting your own user management from scratch.

Doctrine Entity Repository how to add 'andWhere' to all 'find*' functions?

For legacy reasons I have table that is used for many purposes. Only subset of rows is relevant to Entity I'm writing. Criteria is simple, just check 'project' field for specific value.
Instead of reimplementing find, findAll, findByName, findByID, findBy.... Just notify doctrine to append single condition to them all. Is that possible without reimplementing each and every find* ?
Or maybe it can be done on lover level still?
UPDATE:
Reworked question, to specify what kind of solution would be acceptable.
An available easy-to-use solution is to create a Repository with your custom find function.
Then, if all your entities has a specific Repository, make them (Repository) extending from yours (which contains the custom find method), otherwise (you doesn't have a Repository per entity), assign the repository to all your entities with the repositoryClass option of the #ORM\Entity annotation like :
#ORM\Entity(repositoryClass="YourMainRepository")
Otherwise, if you doesn't want put any repository in your entities, override the whole default repository and customise the find method.
I already used the last option because of a specific need, also I invite you to see the following question :
Abstract repository and #Entity annotation inheritance
Look at the solution wich contains a gist of all required steps for override the default doctrine repository.
See Custom Repository classes
Entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Phrase
*
* #ORM\Table(name="User")
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
*/
class User
{
/**
* #var int
*
* #ORM\Column(name="id", type="bigint")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
.............................................................
.............................................................
.............................................................
Your Repository:
namespace AppBundle\Repository;
use Doctrine\ORM\EntityRepository;
class UserRepository extends EntityRepository
{
/** For example **/
public function getByName($name)
{
$qb = $this->createQueryBuilder('u')
->where('u.name = :name')->setParameter('name', $name)
->andWhere('u.lastname LIKE :name')->setParameter('lastname', '%'.$name.'%');
$query = $qb->getQuery();
return $query->getResult();
}
}
In Your Controller:
/**
* #Route("/", name="index")
*/
public function indexAction(Request $request)
{
$userRepository = $this->getDoctrine()->getRepository('AppBundle:User');
$userName = $userRepository->getByName($name);
..................................................................................
..................................................................................

Symfony - Doctrine not generating entity

i have a quite primitve problem:
I created an Entity in my Symfony App:
src/AppBundle/Model/Article/Article.php:
<?php
namespace AppBundle\Model\Article;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="articles")
*/
class Article {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length="255", nullable=false)
*/
private $name;
}
When i type in console:
php app/console doctrine:generate:entities AppBundle
it prints:
Bundle "AppBundle" does not contain any mapped entities.
And when i type:
php app/console doctrine:generate:entities AppBundle/Model/Article/Article
it prints:
Class "AppBundle\Model\Article\Article" is not a valid entity or mapped super class.
Anybody has some idea how to solve this?
I already followed some solutions on stackoverflow like changing or turning off cache/clearing cache/ etc.. but none works.
Thanks and Greetings!
Probably Doctrine doesn't know about these mappings.
Have you created this bundle with a generator?
Check your config.yml in app/config, you should have an entry under following keys structure:
doctrine:
orm:
mappings:
AppBundle: ~
Edit:
Ok, you use custom structure.
Default namespace should look like that:
AppBundle\Entity
So full class name should be AppBundle\Entity\Article
If you want to stick with custom mappings, check configuration docs.
You should add all your Entities in the Entity Folder, remember Entity and Model are different concepts. You can create others folders like Model, Handlers, Managers. Another important thing is not to confuse Data Base with Object-oriented programming.
You need to make sure that you do not use Doctrine\Common\Annotations\SimpleAnnotationReader class. Instead Doctrine\Common\Annotations\AnnotationReader should be used.
Simple reader doesn't support #ORM\Annotation, only #Annotation.

type of users SonataUserBundle + FOSUserBundle + SonataAdminBundle

I'm trying to create 3 users in my project:
Cliente : Who will access front-end and have fields 'name', 'CPF', 'adress'.
Vendedor : Who will register Offers in the site and have fields 'phone', 'CNPJ'
Admin : Who will administer all Clientes, Vendedores, Offers, etc...
So.. I installed 3 bundles for that: SonataUserBundle + FosUserBundle + SonataAdminBundle
I followed the entire tutorial of each one. But I don't know how can I create each type of this users.
I am using ApplicationSonataUserBundle which generate entities User and Group.
Here is my code:
namespace Sete\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Application\Sonata\UserBundle\Entity\User as BaseUser;
/**
* Cliente
*
* #ORM\Table(name="cliente")
* #ORM\Entity
*
*/
class Cliente extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
...another fields...
}
and Vendedor:
namespace Sete\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Application\Sonata\UserBundle\Entity\User as BaseUser;
/**
* Vendedor
*
* #ORM\Table(name="vendedor")
* #ORM\Entity
*/
class Vendedor extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
...another fields...
}
AppKernel.php
...
new Sonata\UserBundle\SonataUserBundle('FOSUserBundle'),
new Sonata\EasyExtendsBundle\SonataEasyExtendsBundle(),
new Application\Sonata\UserBundle\ApplicationSonataUserBundle()
And config.yml
...
fos_user:
db_driver: orm # can be orm or odm
firewall_name: main
user_class: Application\Sonata\UserBundle\Entity\User
group:
group_class: Application\Sonata\UserBundle\Entity\Group
sonata_user:
manager_type: orm # can be orm or mongodb
...
This way my entities Cliente and Vendedor have no association with groups. I try to add $groups relationship, but not work. So, when I try to admin this entities I got error:
An exception occurred while executing 'SELECT count(DISTINCT c0_.id)
AS sclr0 FROM cliente c0_ LEFT JOIN fos_user_user_group f3_ ON f2_.id
= f3_.user_id LEFT JOIN fos_user_group f1_ ON f1_.id = f3_.group_id':
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'f2_.id' in 'on
clause'
Is that the best pratice to create types of users? Or, Instead of extends ApplicationUserBundle:User, create Cliente and Vendedor entities (without extends ApplicationUserBundle:User), and then create relationship with User (puting fields $cliente and $vendedor inside User entity and making a relationship) ?
Sorry about the english.
I trying to do this all week. Follow many tutorials but not got the answer.
Thx all.
One way to go about having multiple user types is to use Doctrine inheritance mapping.
However, I would recommend using single user type together with role security handler. You should install SonataUserBundle with Easy Extends (installation instructions), so that you can leave SonataUserBundle unmodified. You should add all needed fields to the App\UserBundle\Entity\User and create three user Groups: Clientes, Vendedors and Admins. In your main config.yml, add two missing roles (there already is ROLE_ADMIN):
ROLE_SUPER_ADMIN: [<...>, ROLE_CLIENT, ROLE_VENDOR]
Assign those three user Groups appropriate permissions that you created.
Now, in User, make custom fieds nullable and in you UserAdmin show only the fieds user type can see using security rigths. Example:
if ($this->isGranted('ROLE_CLIENT')) {
$formMapper->add('cpf');
}

Resources