Doctrine2, create one entity from another? - orm

I'm using Doctine2\ORM and i have en entity for user , and the role.
When user is registering, i need to create role record with user id and return its id to user, then create the user record, how can i organize my annotation for such work?

You can add a default role to your user during __construct, then mark the association as cascade={"persist"}.
The constructor would look like:
public function __construct()
{
$this->role = new RoleLink();
}
I also don't think that a role needs to keep a reference to the user itself, but if need that, keep in mind that in Doctrine 2 ORM you handle associations by assigning related objects to the association property itself (not identifiers!)

Firstly, I don't think you want to create your role entry when a user is registering. I think it's wise to define these upfront (along with their respective access rights).
Once you've taken care of that I guess the obvious relation you're after would be ManyToOne on the User with a persistence cascade set.
/**
* #Table(name="role")
*/
class Role
{
// possibly define your roles accesses as another realtion or hard code?
}
/**
* #Table(name="user")
*/
class User
{
// id + any other definitions
/**
* #var Entities\Role $role
* #ManyToOne(targetEntity="Role", cascade={"persist"})
*/
private $role;
}

Related

RBAC with Ory Keto and ownership of objects

I'm trying to achieve the following points with Ory Keto:
UserA has ownership of ProductA -> Ownership gives one CRUD rights.
UserB has the role Admin -> Admin gives one CRUD rights on everything.
UserA has a role KYCVerified or is part of a group named KYCVerified -> This gives the user additional permissions.
Point 1 describes the concept of ownership, which is described as one of the shortcomings of RBAC (source) with the current state of Ory Keto:
There is no concept of ownership: Dan is the author of article "Hello
World" and is thus allowed to update it.
Point 2 describes a role that basically passes the ownership check, since this role can do everything. This should be possible in the current state, but not in combination with point 1.
Point 3 describes basically the same thing as point 2, but this is more specific to my use case.
I've read this article on the Ory website and this article. However, I'm still unable to wrap my head around this concept. I've made the following example of how I see the concept of ownership with Ory Keto:
# Tenant TenantA needs to be a owner of product ProductA in order to view it
products:ProductA#view#(tenants:TenantA#owner)
# Tenant A is a owner of ProductA
tenants:ProductA#owner#TenantA
But this will result in a lot of rules and I'm not even sure if this is the way to go.
As of this moment you are right. You have to create a bunch of tuples manually. The full set of tuples should be something like:
products:ProductA#owner#UserA
products:ProductA#crud#(products:ProductA#owner)
roles:admin#member#UserB
products:ProductA#curd#(roles:admin#member)
products:ProductA#additional_permissions#(roles:KYCVerified#member)
roles:KYCVerified#member#UserA
With https://github.com/ory/keto/pull/877 you will be able to define global rewrites. It would looks similar to:
import { Context, Namespace } from #ory/keto-config
/**
* "User" is a namespace with no additional rewrite rules defined.
*/
class User implements Namespace {}
/**
* "Role"s only have members.
*/
class Role implements Namespace {
related: {
members: User[]
}
}
/**
* "Product" is a namespace representing a product. It has some rewrites.
*/
class Product implements Namespace {
// Relations are defined and type-annotated.
related: {
/**
* "owners" are the users that are the owners of the product.
*/
owners: User[]
/**
* "admins" are the roles that are administrators of this product (potentially only one).
*/
admins: Role[]
/**
* "special_roles" are the roles a user has to be member of to gain "additional_permissions"
*/
special_roles: Role[]
}
permits = {
// this is probably three/four rewrites (create, read, update, delete) with similar rules
crud: (ctx: Context): boolean =>
this.related.owners.includes(ctx.subject) ||
this.related.admins.some((admin) => admin.related.members.includes(ctx.subject)),
// for the additional_permissions one has to have curd and be member of a special role
additional_permissions: (ctx: Context): boolean =>
this.permits.crud(ctx) &&
this.related.special_roles.some((role) => role.related.members.includes(ctx.subject))
}
}
With that you have to create these tuples:
products:ProductA#owners#UserA
roles:admin#members#UserB
roles:KYCVerified#members#UserA
products:ProductA#admins#(roles:admin)
products:ProductA#additional_permissions#(roles:KYCVerified)
Please note that it is not possible (and not planned right now) to define a single admin group that would have access to everything. You always have to have some kind of relation between the object and subject to query/rewrite it. That is the reason for having the admins and special_roles relations.

Why Doctrine 2 not have basic validate method that validate if all values fit entities attributes?

I am new with doctrine 2.
Why Doctrine 2 not have basic validate method that validate if all values fit entities attributes?
My question target to understand more how doctrine 2 works and why without say that something wrong in doctine 2. (Mostly because i am new i miss some understanding about doctrine 2 way of design)
Example:
<?php
// entities/User.php
/**
* #Entity #Table(name="users")
**/
class User
{
/**
* #Id #GeneratedValue #Column(type="integer")
* #var int
**/
protected $id;
/**
* #Column(type="string")
* #var string
**/
protected $name;
}
code example of use of build in validate(not need connect to db, only validate #Column(type="integer") ) basic function that not exist in doctrine 2:
$user=new User();
$user->setId('trtr');
$user->setName("goodname");
if($user->validate()){
echo 'ok';
}
else{
echo $user->validateError();
}
//output: id of User should be integer and not string
Thanks
Doctrine ORM assumes that entities you're persisting are in a valid state. That's the only job of the persistence layer, and adding validation to it would just be wrong. If you have entities with invalid data in them, you already have an invalid object graph that should not be saved.
So please keep in mind that if you ever had some API like
$someEntity->isValid();
Then something is probably wrong, since the entity should always be valid, and any dependencies of it should be set at construction time and handled in setters/getters so that the object never reaches an inconsistent state.
The main reason is separation of concerns. Since entities are fairly dumb objects that don't know much about the rest of the world, their ability to do validations is limited to begin with.
For instance, there's no way that your typical entity could validate that a particular property is unique.
That said, if you just want to do basic validations, just do them in the setters.
<?php
class MyEntity {
// ...
/**
* #ORM\Column(length="32")
*/
protected $myProperty;
public function setMyProperty($prop){
if (! is_string($prop))
throw new \InvalidArgumentException('MyEntity::setMyProperty() expects a string!';
if (strlen($prop) > 32)
throw new \LengthException('Argument passed to MyEntity::setMyProperty() is too long!');
$this->myProperty = $prop;
}
}
This approach can be used to enforce data types, lengths, etc. Anything beyond that is better handled somewhere other than inside your entity.
It's not good idea to mix entity and validation, but it make sense to have this rules in entity as annotation and validation logic in separated aspect validator class.
Check how it's done in Spring framework -
http://www.abtosoftware.com/blog/form-validation-using-aspect-oriented-programming-aop-in-spring-framework
and how to implement it with doctrine2 and go -
http://go.aopphp.com/blog/2013/07/21/implementing-logging-aspect-with-doctrine-annotations/

Adding more info to Laravel's auth user

I am new to Laravel and I am trying to add some more information to the user variable I am getting back from Auth::user()
To be more detailed, I have a Many-to-Many relationship to a "Privileges" table. As the name suggests, that table holds specific privileges a user can have. In the pivot table, I just hold the the user_id and privilege_id. I have the necessary models set up and everything works fine if I do this in my before filter:
$user = Auth::user();
$user->priviledges()->get();
Now, I would really like to avoid querying every single time I want to find the privileges and would like to have Laravel's Auth class include the privilege information, so that when I do
$user = Auth::user();
I can do a
$user->privileges;
to get an array of all privileges the user has.
Any suggestions for the best approach?
The link to the answer above is not working. However, I found another solution here which worked for me as follows:
First I created a model called EmailPref.php in my own case;
app/model/EmailPref.php
class EmailPref extends Eloquent {
protected $table = 'email_pref';
public function user()
{
return $this->belongsTo('User');
}
}
and then I created a relationship (in my own case) in the User model like so;
app/model/User.php
public function emailPref()
{
return $this->hasOne('EmailPref');
}
I subsequently referenced it anywhere required within my application like so:
Auth::user()->emailPref;
Hence, I was able to add more information to the Auth user.
I'm no Laravel pro, but i think this will solve your problem: http://forums.laravel.io/viewtopic.php?id=1652

How to map many to many relationship with composite key in symfony2 Doctrine ORM

I have this scenario
I have four classes
User
profiles
Activity
Workbook
user can have many profiles based on per year. Every year diff profile
User profile will have many to many with Activities
so there will be profile_activities table with profile_id and activity_id
Now User will do 1 workbook per activity per profile
so i am confused how to map in database
I mean for profile table , i can have
class profile
#many to many
protected $activities
many to one
protected $user
But in class workbook how to define foreign key which belongs to activity and profile relationship table
For every activity child has to complete workbook. How should i define that
#[one to one [PK of activity_profile table]
protected $workbook
Symfony provides you different methods for do this operation.
One of those methods is annotation. With annotation you can write directly into php classes this relationships and more (like db column's type, specify if an attribute is mandatory and so on ...)
So, let's took this example (because i dind't understand the relationships of your entities)
Consider two entities: User and Groups.
One user can belong to n Groups and a Groups can have m Users. This mean that we have to "break up" m-n cardinality into an m-1-n relationship.
In symfony (with doctrine; i don't know if with mongodb and similar is the same) you haven't to create this "intermediate table" as a php class. All you have to do is, with annotation into php classes involves, specify what tables are related and in what way.
Let's see how!
/**
* Acme\UserBundle\Entity\User
*
* #ORM\Table(name="users")
* #ORM\Entity()
*/
class User implements AdvancedUserInterface
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
[...]
/**
* #ORM\ManyToMany(targetEntity="Groups", inversedBy="users")
*
*/
private $groups;
[...]
}
As you can see, this is a part of a php class mapped into db table with doctrine (ORM).
This class han an attribute $groups that tells (take a look to annotations) that is a many-to-many relationship between this class and another class (identified by targetEntity) and inversedBy tells what attribute (db column; attribute if you talk about class) is involved into the relationship (external key).
/**
* #ORM\Table(name="groups")
* #ORM\Entity()
*/
class Groups implements RoleInterface
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
[...]
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="groups")
*/
private $users;
[...]
}
This entity is group entity and have the "other side" of relationship: $user
As you can see, there is #ORM\ManyToMany(targetEntity="User", mappedBy="groups") that indicates that realtionship is with class User and field into User class is groups.
Now you can run doctrine command for entity generation onto db php app/console doctrine:generate:entities Acme where Acme is bundle's name and the trick is done.
Some words on mappedBy and inversedBy:
There are "two" sides: the inverted side and the owning side. Remember that docrine will "observe" changes only into the owning side, so take care to place it into the right class
The inversed side is identified by mappedBy keyword and it's value is the name of owning side class
The owning side is identified with inversedBy keyword and it's value is the name of the inversed side class
manyToOne association has always the owning side
oneToMany association has always the inversed side
The owning side of oneToOne relationship is always the entity with external key
Into manyToMany relationship is the same

Mapping two tables to one entity in Doctrine2

I'm looking at using doctrine for an application I'm working on - but after reading the documentation I'm having trouble conceptualizing how to represent the database structure we have in terms of entities.
I have many tables which have partner tables which hold translation data like the following....
Where I would like to have one Entity (Navigation Element) which had access to the 'label' field depending on what Language I set in my application. The following from the Doctrine documentation seems to suggest that you need to define one (single) table which is used to persist an entity
http://www.doctrine-project.org/docs/orm/2.0/en/reference/basic-mapping.html
By default, the entity will be
persisted to a table with the same
name as the class name. In order to
change that, you can use the #Table
annotation as follows:
Or do I need to define two entities and link them (or allow the translation table to inherit from the element table).
And what strategy would I use to always insert a language_id clause to the Join (to ensure I'm pulling the right label for the currently set language). Is this something I would define in the entity itself, or elsewhere?
This seems to suit a One-To-Many Bidirectional association. This is the scenario from that page translated to your situation:
/** #Entity */
class NavigationElement
{
// ...
/**
* #OneToMany(targetEntity="NavigationElementTranslation", mappedBy="navigationElement")
*/
private $translations;
// ...
public function __construct() {
$this->translations = new \Doctrine\Common\Collections\ArrayCollection();
}
}
/** #Entity */
class NavigationElementTranslation
{
// ...
/**
* #ManyToOne(targetEntity="NavigationElement", inversedBy="translations")
* #JoinColumn(name="navigation_element_id", referencedColumnName="id")
*/
private $navigationElement;
// ...
}
You could add a getLabel($languageId) method to the NavigationElement entity that searches through the translations to get the correct label:
public function getLabel($languageId) {
foreach($this->translations as $trans) {
if($trans->languageId == $languageId)
return $trans->label;
}
throw new InvalidArgumentException();
}
And you could use the following DQL to ensure you only load the translation you want into the $translations property:
$query = $em->createQuery(
"SELECT ne, net
FROM Entity\NavigationElement ne
JOIN ne.translations net WITH net.languageId = :langId"
);
$query->setParameter('langId', $languageId);
$navigationElements = $query->execute();
This situation sounds like one where you would want to cache aggressively. Make sure you look into Doctrine 2's caching mechanisms too.
Also, internationalization can be handled reasonably well in PHP with gettext if you find join tables for translations start to become unmanageable.
I would also direct anyone who has to tackle this same problem to take a look at the following doctrine extension.
http://www.gediminasm.org/article/translatable-behavior-extension-for-doctrine-2