Laravel caching Database queries - laravel-5.7

i have created the project with user roles and permissions
Here is my Tables and Model
users--list of the application users --Model Name [User],
roles--list of the roles available inside the application --Model Name [Role],
permissions--list of the Permisisons available inside the application --Model Name [Permisions],
Here is my relationship tables
role_user Which hold the relationship between the roles table and users table
permission_role Which hold the relationship between the permissions table and roles table
permission_user Which hold the relationship between the permissions table and users table
My Relationship Code inside Model
User.php Model
/**
* Many-to-Many relations with Role.
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function roles()
{
return $this->belongsToMany(Role::class);
}
/**
* Many-to-Many relations with Permission.
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function permissions()
{
return $this->belongsToMany(Permission::class);
}
public function hasPermission($permission)
{
return $this->hasPermissionThroughRole($permission) || (bool) $this->permissions->where('name',$permission->name)->count();
}
public function hasPermissionThroughRole($permission)
{
foreach($permission->roles as $role)
{
if($this->roles->contains($role))
{
return true;
}
}
return false;
}
public function hasRoles($roles)
{
$roles = is_array($roles) ? $roles : func_get_args();
foreach ($roles as $role)
{
if ($this->hasRole($role))
{
return true;
}
}
return false;
}
/**
* Returns if the given user has an specific role.
*
* #param string $role
*
* #return bool
*/
public function hasRole($role)
{
return $this->roles
->where('name', $role)
->first() != null;
}
Role.php Model
/**
* Many-to-Many relations with Permissions.
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function permissions()
{
return $this->belongsToMany(Permission::class);
}
/**
* Many-to-Many relations with Users.
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function users()
{
return $this->belongsToMany(User::class);
}
Permission.php Model
/**
* Belongs-to-Many relations with Role.
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function roles()
{
return $this->belongsToMany(Role::class);
}
/**
* Belongs-to-Many relations with User.
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function users()
{
return $this->belongsToMany(User::class);
}
/**
* Belongs-to-Many relations with Modules.
*
* #return \Illuminate\Database\Eloquent\Relations\belongsToMany
*/
And then finally i have create the ServiceProvider named as
PermissionServiceProvider
and Inside the boot method of the serviceprovider i have added the code
public function boot()
{
if (Schema::hasTable('permissions'))
{
Permission::get()->map(function ($permission)
{
Gate::define($permission->name, function ($user) use ($permission)
{
return $user->hasPermission($permission);
});
});
}
Blade::directive('role', function ($role)
{
return "<?php if(Auth::user()->hasRole({$role})): ?>";
});
Blade::directive('endrole', function ($role)
{
return "<?php endif; ?>";
});
}
Every functions and relationship is working fine but the Queries are running every time i hit the refresh button
Is there any way to cache all the permisisons and roles to logged in user
Edited
As per Some Suggestions i have tried laravel cache package
It is not working for me

You are looking for laravel model caching pakage https://github.com/GeneaLabs/laravel-model-caching.
I recommend to install package with redis. Also it is very useful when working with queues.
Works as expected. Screenshots from my project.
Before:
After:

Related

Reference setting value in entity symfony

I have a doubt about code organization using symfony3 and doctrine: I'll try to explain as clear as I can. Let's say I have a FootballClub entity:
class FootballClub
{
// other code
private $memberships;
public function addMembership(Membership $membership) : FootballClub
{
$this->memberships[] = $membership;
return $this;
}
public function removeMembership(Membership $membership) : bool
{
return $this->memberships->removeElement($membership);
}
}
The entity is in a many-to-one relationship with another entity, Membership, which represents the contract a player has with the club. Let's say each club
has only a limited number of membership it can acquire, number that is represented as a setting, for example, as a property in a Setting entity.
The question is: how should I reference that setting when removing a membership from the club and check that is respected? Entities should not have any dependency, so what would be the correct way to implement this? A service? can you provide an example? Thank you for your time.
You could create a Settings entity, linked in OneToOne relation with FootballCluc entity.
Define Settings like this and instanciate it in the FootballClub's constructor
Settings entity
/** #Entity */
class Settings
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="integer")
*/
private $maxMembership;
// Other configurable properties ...
__constructor($maxMembership = 50)
{
$this->maxMembership = $maxMembership;
}
public function getMaxMembership()
{
return $this->maxMembership;
}
public function setMaxMembership($maxMembership)
{
$this->maxMembership = $maxMembership;
}
}
Football Entity
class FootballClub
{
/**
* One FootballClub has One Settings.
* #OneToOne(targetEntity="Settings")
* #JoinColumn(name="settings_id", referencedColumnName="id")
*/
private $settings;
// other code
private $memberships;
__constructor(Settings $settings = null)
{
if (null === $settings) {
$settings = new Settings();
}
$this->settings = $settings;
}
public function addMembership(Membership $membership) : FootballClub
{
if ($this->settings->getMaxMembership() <= count($this->memberships)) {
// throw new Exception("Max number of membership reached"); Strict mode
// return false // soft mode
}
$this->memberships-> = $membership;
return $this;
}
public function removeMembership(Membership $membership) : bool
{
return $this->memberships->removeElement($membership);
}
}

Symfony 3.4.9 many-to-many relation not saved in DB

I'm developing a crowfunding website and I have two entities: User and Campaign
One user can be two things: team and funder
for now I have:
class Campaign
{
public function __construct() {
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Many Groups have Many Users.
* #ORM\ManyToMany(targetEntity="User", mappedBy="teams")
*/
private $team;
/**
* #param Team $team
*/
public function setTeam(User $team)
{
$this->team[] = $teams;
}
public function getTeam()
{
return $this->team;
}
}
The problem is that the teams are not saved in the DB (all the other info on the form are saved normaly). Would you help me understand what I did wrong please ?
Thank you
Are you sure about your method setTeam ? You give $team in parameter but in your assignation of the array $this->team you only use $teams with an s and no the $team which is in param.
/**
* #param Team $team
*/
public function setTeam(User $team)
{
$this->team[] = $teams;
}

symonfy/doctrine, get associated entity return null , but return actual data if a call to `dump()` is added

This is one is a bit weird
I'm using symfony3/php7
I have the following ProUser entity linked to a Organization entity, used to identity pro account, (important part is the "isEnabled" method), when I try to login with a ProUser that has a linked Organization (they all have, but I made triple sure to choose one that had in database), I got an error that the organization is null, but if i had a dump method to debug, then the organization is correctly retrieved from database by doctrine...
/**
* Represent a professional owner (i.e a theater owner etc.)
*
* #ORM\Entity
* #ORM\Table(name="pro_user")
*/
class ProUser implements AdvancedUserInterface, \Serializable
{
/**
* #ORM\Column(name="id", type="guid")
* #ORM\Id
*/
protected $id;
/**
* #ORM\OneToOne(targetEntity="Organization", cascade={"persist"}, mappedBy="legalRepresentative")
*/
private $organization;
public function getOrganization()
{
return $this->organization;
}
public function setOrganization(Organization $organization)
{
$this->organization = $organization;
return $this;
}
/**
* Note: needed to implement the UserInterface
*/
public function getUsername()
{
return $this->email;
}
// for AdvancedUserInterface
public function isEnabled(): bool
{
$organization = $this->getOrganization();
// when this line is not present,
// it throws an exception that $organization is null,
// no problem when this line is present
dump($organization);
return $organization->isValidated();
}
public function isAccountNonExpired()
{
return true;
}
public function isAccountNonLocked()
{
return true;
}
public function isCredentialsNonExpired()
{
return true;
}
}
The stacktrace :
Symfony\Component\Debug\Exception\FatalThrowableError:
Call to a member function isValidated() on null
at src/AppBundle/Entity/ProUser.php:151
at AppBundle\Entity\ProUser->isEnabled()
(vendor/symfony/symfony/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php:277)
at Symfony\Component\Security\Core\Authentication\Token\AbstractToken->hasUserChanged(object(ProUser))
(vendor/symfony/symfony/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php:101)
at Symfony\Component\Security\Core\Authentication\Token\AbstractToken->setUser(object(ProUser))
(vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/ContextListener.php:176)
at Symfony\Component\Security\Http\Firewall\ContextListener->refreshUser(object(RememberMeToken))
(vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/ContextListener.php:109)
at Symfony\Component\Security\Http\Firewall\ContextListener->handle(object(GetResponseEvent))
(vendor/symfony/symfony/src/Symfony/Bundle/SecurityBundle/Debug/WrappedListener.php:46)
at Symfony\Bundle\SecurityBundle\Debug\WrappedListener->handle(object(GetResponseEvent))
(vendor/symfony/symfony/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php:35)
at Symfony\Bundle\SecurityBundle\Debug\TraceableFirewallListener->handleRequest(object(GetResponseEvent), object(RewindableGenerator))
(vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall.php:56)
at Symfony\Component\Security\Http\Firewall->onKernelRequest(object(GetResponseEvent))
(vendor/symfony/symfony/src/Symfony/Bundle/SecurityBundle/EventListener/FirewallListener.php:48)
Is it due to the code happening in the Security Component, and the entity was unserialized instead of being retrieved by doctrine, so that getOrganization() does not yet return a doctrine proxy ?
This is because of Doctrine's lazy loading of relations (it basically only knows the primary ids of the connected entities untill one or more of them are called, like with dump()).
You can add the fetch attribute to your mapping, where LAZY is default, you can set this to EAGER.

silex symfony doctrine ORM many to many: getRoles at login returns empty List

Hello Silex (and Symfony) experts,
I need to implement a database authentification User/Role model via Doctrine /ORM.
This is my silex composer setup:
"require": {
"silex/web-profiler": "^2.0",
"monolog/monolog": "1.13.*",
"symfony/twig-bridge": "^3.2",
"symfony/monolog-bridge": "^3.2",
"symfony/console": "^3.2",
"symfony/yaml": "^3.2",
"symfony/security-bundle": "^3.2",
"doctrine/orm": "^2.5",
"dflydev/doctrine-orm-service-provider": "^2.0",
"symfony/form": "^3.2",
"symfony/validator": "^3.2",
"symfony/config": "^3.2",
"symfony/doctrine-bridge": "^3.2",
"doctrine/migrations": "^1.5"
},
Users can register. Registered users can login and logout. Non registered visitors have anonymous role.
The symfony profiler is working, so I can see the security status (authentification/authoriszation). I also track the apache logfile for php errors.
I started from here https://github.com/fredjuvaux/silex-orm-user-provider (User from db, roles as array) and tried to expand it to get user roles from database via doctrine many-to-many relation.
There are:
class MyUserController (different user actions like user,edit, register,... )
class MyUserManager implements UserProviderInterface (loadUserByUsername, ...)
class MyUserServiceProvider implements ServiceProviderInterface, ControllerProviderInterface, BootableProviderInterface (controller routing and template setting)
The ORM entities are:
User:
/**
* MyUser
*
* #Entity
* #Table(name="myuser")
*/
class MyUser implements UserInterface, \Serializable
{
....
/**
* #ManyToMany(targetEntity="MyRole", inversedBy="users")
*
*/
private $roles;
...
* Constructor.
*
* #param string $email
*/
public function __construct($email)
{
$this->email = $email;
$this->created = time();
$this->salt = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
$this->roles = new ArrayCollection();
}
...
/**
*
* #return ArrayCollection list of the user's roles.
*/
public function getRoles()
{
$result = $this->roles->toArray(); // throws error for login:
// $result = $this->roles; // test // thhrows error : null object
dump($this->roles);
// $result = array("ROLE_USER", "ROLE_OTHER"); // static setting and
works for login
return $result;
}
...
}
Roles (implements Roleinterface)
/**
* MyRole
*
* #Entity
* #Table(name="myrole")
*/
class MyRole implements RoleInterface
{
/**
* #var string
* #Column(name="role", type="string", length=20, unique=true)
*/
private $role;
/**
* #ManyToMany(targetEntity="MyUser", mappedBy="roles")
*/
private $users;
...
/*
* methods for RoleInterface
* #return string|null A string representation of the role, or null
*/
public function getRole()
{
$result = $this->role;
return $result;
}
}
When a user registers, he gets for that session the ROLE_USER role,
authentification and authorisation are ok and a user is created in the
database.
Then I can assign new roles ("role_test1", "role_test2") in the controller for the new user, the many-to-many table myuser_myrole is filled (myuser_id myrole_id).
When I change the roles, they are correctly updated by the entity manager.
When I access the user Entity from the userController to work on it, I can access the assigned roles:
// MyUserController.php
$user = $em->getRepository('MyEntities\MyUser')->find($id);
$roles= $user->getRoles()
$role_length = count($roles);
$role_list = array();
for ($i=0; $i <$role_length ; $i++)
{
array_push($role_list,$roles[$i]->getRole()); // MyRole::getRole() prints out something to screen.
}
printf("<br> role-list:"); dump($role_list);
Calling this controller prints out the assigned roles via MyRole::getRole(), so ORM access works here.
Now comes the strange:
I want to login the new user with the login form.
When I use
// MyUser::getRoles()
return $this->roles;
It throws:
Argument 4 passed to Symfony\\Component\\Security\\Core\\Authentication\\Token\\UsernamePasswordToken::__construct() must be of the type array, object given,
Ok, makes maybe sense because the $roles is an Doctrine ArrayCollection.
When I use
// MyUser::getRoles()
return $this->roles->toArray();
I can login with user password,but am not authenticated (yellow status). Dumping out the roles, I receive an empty array ArrayCollection.
roles:
ArrayCollection {#388 ▼
-elements: []
}
The UsernamePasswordToken has an empty role-array.
When I use
// MyUser::getRoles()
return array("ROLE_HELLO1", "ROLE_HELLO2"); // static role array with strings
I can login and am authenticated with these roles:
Roles
array:2 [▼
0 => "ROLE_HELLO1"
1 => "ROLE_HELLO2"
]
There are old docs about this (Managing Roles in the Database) for symfony 2 http://symfony.com/doc/2.0/cookbook/security/entity_provider.html, but it doesnt work in symfony3.
Here they use
//class User
public function getRoles()
{
return $this->groups->toArray();
}
//class Group extends Role (not RoleInterface, old?)
public function getRole()
{
return $this->role;
}
The actual symfony docs for user management do not show how to use roles stored in database.
In summary:
Login and user/role do not work as expected:
MyUser::getRoles()
does not receive the Roles from database via doctrine ORM.
has to return a string array of roles for login.
delivers the correct role association in another controller.
Questions:
(1) Is this a Silex specific issue?
(2) How to use it correctly or where is a good link/doc for a workaround?
(3) Does the method LoadUserByUsername() interfere with all this?
(4) Do I need a class MyUserRepository extends EntityRepository {} to do the query and get the Role List?
(5) Do I need to use the Role Hierarchy service?
(6) Are there special naming conventions(tablename or class name) for "user" and "role"?
I found many posts asking the same/similar but they do not help here.
Thank you for help, I am really stuck on that!
dirk
Try this:
public function getRoles()
{
return $this->roles->map(function (MyRole $role) {
return $role->getRole();
})->toArray();
}
You should also check if the relationship is correctly saved in database.
If there is ManyToMany relationship between MyUser and MyRole, you have to ensure that relationship is saved in both entities.
//class MyUser
public function addRole(MyRole $role)
{
$this-roles->add($role);
$role->users->add($user);
}
I had a break on this, but now it seems to work. Thank you miikes for the addRole() suggestion!
finally I have: MyUser.php:
//Myuser.php
/**
* MyUser
*
* #Entity
* #Table(name="myuser")
*/
class MyUser implements UserInterface, \Serializable //, ObjectManagerAware
{
...
/**
* #ManyToMany(targetEntity="MyRole", inversedBy="users")
*/
private $roles;
public function __construct($email)
{
(...)
$this->roles = new ArrayCollection();
/**
*
* #return ArrayCollection list of the user's roles.
*/
public function getRoles()
{
$result = $this->roles->toArray();
return $result;
}
public function assignToRole($role)
{
$this->roles[] = $role;
}
public function setRole($myrole)
{
$this->roles= $myrole;
}
public function hasRole($role)
{
return in_array(strtoupper($role), $this->getRoles(), true);
}
public function addRole(MyRole $role)
{
$this->roles->add($role);
//$role->users->addRole($this); // could not access roles->user->...
// because private variable in MyRole but it works
}
/**
* Remove the given role from the user.
*
* #param string $role
*/
public function removeRole($role)
{
dump($role);
$this->roles->removeElement($role);
}
(...) // other setters getters
public function serialize()
{
return serialize(array(
$this->id,
$this->username,
$this->password,
$this->salt,
));
}
/**
* #see \Serializable::unserialize()
*/
public function unserialize($serialized)
{
list (
$this->id,
$this->username,
$this->password,
$this->salt,
) = unserialize($serialized);
}
}
and MyRole.php:
// MyRole.php
/**
* MyRole
*
* #Entity
* #Table(name="myrole")
*/
class MyRole implements RoleInterface
{
(...)
/**
* #ManyToMany(targetEntity="MyUser", mappedBy="roles")
*/
private $users;
/**
* #var string
* #Column(name="role", type="string", length=20, unique=true)
*/
private $role;
/*
* methods for RoleInterface
* #return string|null A string representation of the role, or null
*/
public function getRole()
{
$result = $this->role;
return ($result);
}
public function setRole($role)
{
$this->role= $role;
return $this;
}
(...)
/**
* Constructor
*/
public function __construct()
{
$this->users = new ArrayCollection();
}
/**
* Add user
* #param \MyEntities\MyUser $user
* #return MyRole
*/
public function addUser($user)
{
$this->users[] = $user;
return $this;
}
public function setUser($user)
{
$this->users[] = $user;
return $this;
}
/**
* Remove user
*
* #param \MyEntities\MyUser $user
*/
public function removeUser($user)
{
$this->users->removeElement($user);
}
/**
* Get users
*
* #return ArrayCollection $users
*/
public function getUsers()
{
return $this->users;
}
/**
* __toString()
*
* #return string
*/
public function __toString()
{
return $this->bezeichnung;
}
}
With the help of the doctrine orm commands
vendor/bin/doctrine orm:validate-schema
vendor/bin/doctrine orm:schema-tool:update --dump-sql
the correct manyToMany table myuser_myrole was generated and the role setting works at login of a user.
I think, the most important was the correct use of the function addRole() (with this->roles->add($role), and not something like this->roles->addRole($role) ) to let doctrine do the magic stuff in the background.
Thanks for any help and comments!
dirk

Remove and Filter element In ArrayCollection Symfony 2

I have registered users in my application, when a user wants to unsubscribe or is locked in the database is marked as Locked
ArrayCollection all need to be changed or do I have to make a new function for each ArrayCollection?
for Example:
this is arrayCollection
/**
* Get like
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getLike()
{
return $this->like;
}
When I user is locked i have to create a new function like:
/**
* Get like2
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getLike2()
{
//USE CRITERIA OR
$out = array();
foreach ($this->like as $like2) {
if (!getUser()->getLocked()) {
$out[] = $like2;
}
}
}
Or I can use the "default" ArrayCollection with some modifications

Resources