Creating Roles - insufficient information for romanbican - laravel

i am using " romanbican - bicon roles ", i don't see sufficient information for the " Creating Roles ",
code is available but i don't know where i paste this code, please suggest quick steps to implement permissions.

I used this same laravel package and simply created a new controller and route pointing to the the following controller methods:
public function getRoleAdmin()
{
$adminRole = Role::create([
'name' => 'Admin',
'slug' => 'admin',
'description' => 'System Administrator', // optional
'level' => 1, // optional, set to 1 by default
]);
}
public function getRoleModerator()
{
$moderatorRole = Role::create([
'name' => 'Forum Moderator',
'slug' => 'forum.moderator',
'description' => 'Forum Moderator',
'level' => 1,
]);
}
I then created a simple view with a button for each calling the appropriate route/controller/method to create either a new moderator or administrator role. You will see that calling Role::create simply creates a new record in the roles table with these attributes which you could easily perform with a standard DB call to insert into the table. I used the same approach for creating/deleting permissions.

Related

Using roles with jwt / zizaco/entrust

In my new Laravel 5.8 app I read next article to use roles with jwt extention :
https://scotch.io/tutorials/role-based-authentication-in-laravel-with-jwt
and in seed I add several roles, like :
\DB::table('roles')->insert(array (
0 =>
array (
'id' => 1,
'name' => 'Admin',
'display_name' => 'Admin',
'description' => 'Administrator. Can do all operations in system',
'created_at' => '2019-04-29 11:03:50',
),
1 =>
array (
'id' => 2,
'name' => 'Manager',
'display_name' => 'Manager. Can do all operations in frontend and CRUD for Hostels/CMS items in Backend',
'description' => 'Manager description...',
'created_at' => '2019-04-29 11:03:50',
),
2 =>
array (
'id' => 3,
'name' => 'Customer',
'display_name' => 'Customer. Can do all operations in frontend',
'description' => 'Customer description...',
'created_at' => '2019-04-29 11:03:50',
),
));
and I see assignRole method, when I need to assign some role to user.
What is unclear for me what for Permissions and “permission_role” data.
Do I need them for my simple app structure? If yes, please provide some examples...
Thanks!
We can't answer your question if you don't specify what your application needs to do. You can have roles without permissions or permissions without roles depending on your application. But if you want the provided tutorial to work you need them.
Permissions are specific actions of a role.
Example Permisson table data:
Permission-id: 1
Permission-name: 'Create Blog Post'
You can assign this permission to a role 'Admin' (Role-id: 1).
Your permission_role table contains the relationship between those two. So for the above example:
permission_role
'permission_id': 1, 'role_id': 1;
Which means that The admin role can 'Create Blog Post' in this case.

Relations in resources?

So I'm planning to start using resources for my "API" (vue endpoint). So I started to search for some tutorials about the subject, and found a youtuber that describes the process. And I started making my own API resource. The youtuber shows briefly how to use the relations, but the thing is that I receive Property [description] does not exist on this collection instance. when trying to use the relation in the resource.
The current setup is:
$stack = Stack::select(['id', 'name', 'subject_id', 'description', 'image'])->where('id', '=', $requestId)->first();
$questions = $stack->load('question.choiceInRandomOrder');
return $questions;
And with resource it would be something like (notice choiceInRandomOrde, I would need that relation also):
return [
'subject' => $this->subject->name,
'name' => $this->name,
'slug' => $this->slug,
'description' => $this->description,
'image' => $this->image,
'questions' => [
'description' => $this->question->description,
'is_info' => $this->question->is_info,
'source' => $this->question->source,
'image' => $this->question->image,
]
];
}
And for testing, I have setup the following in my routes web.php
use App\Stack;
use App\Http\Resources\StackResource;
Route::get('/json', function(){
$stack = Stack::find(2);
return new StackResource($stack);
});
You try to access the name of subject in 'subject' => $this->subject->name, but you do not load the relation.
i don't know if i'm right but i thnk it has to be with the fact that ure not doing an Eloquent call but a Query Builder call (when doing $stack = Stack::select ... ). Why select just some fields in the call if you can choose the parameters to show directly in the model class? (see this).
Try to doing an Eloquent call instead (something like Stack::find(1)) and test it. It should work.

How to properly hydrate and extract Doctrine Entities from Zend Forms

I'm just starting out with Doctrine and was rewriting some code to use Doctrine entities in some Forms.
I have an Entity Business which has some 1:n relations with addresses, employees, emails etc. the Setup is really basic and working fine.
To add new Businesses i created a BusinessForm and Fieldsets for each of my entities. Here the constructor of the form:
public function __construct($scenario='create', $entityManager = null) {
parent::__construct('business_form');
$this->scenario = $scenario;
$this->entityManager = $entityManager;
$this->setAttribute('method', 'post');
$businessFieldset = new BusinessFieldset($this->entityManager);
$businessFieldset->setUseAsBaseFieldset(true);
$this->add($businessFieldset);
$hydrator = new DoctrineHydrator($this->entityManager, new Business());
$this->setHydrator($hydrator);
$this->addElements();
$this->addInputFilter();
}
addElements just adds a Submit and CSRF input.
And here the Controller action:
public function addAction(){
$form = new BusinessForm('create', $this->entityManager);
if ($this->getRequest()->isPost()) {
$data = $this->params()->fromPost();
$form->setData($data);
if($form->isValid()) {
// save Object
return $this->redirect()->toRoute('subcontractor', ['action'=>'index']);
}
}
return new ViewModel([
'form' => $form
]);
}
The form validates and i can get the Data from the form with $form->getData(). But i cant figure out how to get a populated Object from the form using the form's hydrator. When I use setObject(new Business()) at the start of the controller i get an error while $form->isValid() is running :
Zend\Hydrator\ArraySerializable::extract expects the provided object to implement getArrayCopy()
Isnt that the wrong hydrator being called ?
If i dont setObject() but instead use $form->bind(new Business()) after the validation i get an empty Object from $form->getObject(). If i get the data and hydrate a new Object with the form's hydrator like so : $form->getHydrator()->hydrate($data['business], new Business()) i do get the populated Object i was expecting. (Business being the name of the base fieldset)
So my question is, how to i get the result of the last call from just using $form->getObject() after the validation?
[EDIT]
The Problem seems to be with the Collections of Fieldsets used as sub-fieldsets in the businessfieldset. If i validate the form without using the collections i do get the expected Business Object from $form->getData()
Here an example how i add the collection (in the business fieldset):
$this->add([
'name' => 'emails',
'type' => 'Zend\Form\Element\Collection',
'attributes' => [
'id' => 'business_emails',
],
'options' => [
'label' => 'Emails',
'count' => 1,
'should_create_template' => true,
'template_placeholder' => '__index__',
'allow_add' => true,
'target_element' => [
'type' => 'LwsSubcontractor\Form\EmailFieldset',
],
'target_class' => 'LwsSubcontractor\Entity\Email'
],
]);
and here the EmailFieldset:
public function __construct() {
parent::__construct('email');
$this->setObject(new Email());
$this->addElements();
}
protected function addElements() {
$this->add([
'name' => 'email',
'type' => 'Zend\Form\Element\Email',
'attributes' => [
'placeholder' => 'E-Mail (z.B. email#muster-email.de)',
'class' => 'form-control',
'required' => true,
'size' => 50,
],
'options' => [
'label' => 'Email',
],
]);
}
}
If using the Collections i get the Error message from above. So after adding a hydrator to each Fieldset i was fine.
Although i was under the impression that setting the hydrator for the form would result in the used fieldsets to inherit that hydrator.Or was this because of using the fieldsets as collections and not directly ?
You have to add the hydrator to all your fieldsets, personally I use DoctrineModule\Stdlib\Hydrator\DoctrineObject for doctrine entities.
I would also look at using the init() method to initialize your forms and add elements then register and retrieve your form and fieldsets through the FormElementManager, $serviceLocator->get('FormElementManager')->get(yourFieldsetorForm::class). The form can than be injected into your controller.
I hope this helps.

Laravel ACL Kodeine permission slug function

I use Entrust before to control ACL in Laravel when my project is still Laravel 4, and now with Laravel 5.2 Entrust no longer work, especialy in route filtering.
And then I find this package and trying to use it, but still got a lot of question, so to make it more simple I will explain my use case when I use entrust:
First I want to make a permission for create, view, update and delete for article, in Entrust I will create permission like create_article, view_article, update_article and delete_article.
But now in Kodeine when I create permission there is "slug" so I tried to do this like in documentation say
$permUser = $permission->create([
'name' => 'article',
'slug' => [ // pass an array of permissions.
'create' => true,
'view' => true,
'update' => true,
'delete' => true
],
'description' => 'Manange article'
]);
So from what I read it will be just grouping all of my article permission into one place and there is slug with each parameters view, create, update, delete.
The problem I see is, if I want to make my users to only can view article, how to do that based on permission that I created up there?
Since from documentation the to assignPermission is only give permission name and that mean it will include all slug in there and it will be all true?
So if I want to make users only can view article I need to create something like
$permUser = $permission->create([
'name' => 'article_view',
'slug' => [ // pass an array of permissions.
'view' => true,
],
'description' => 'view article'
]);
And if I want to make users only can create article then I will mean I need to create
$permUser = $permission->create([
'name' => 'article_create',
'slug' => [ // pass an array of permissions.
'create' => true,
],
'description' => 'create article'
]);
then what's the point of slug - is it just pretty much the same like role but with parameter in slug?
As I wrote in your github issue, I suggest you to keep all your article permissions as you alredy have it, in one big group but all of them set to false (keep in mind that you may need to change your 'most_permissive_wins' variable in your acl config file). You can create a "child" group permission for your users role using Inheritance, setting to true all of those permissions your users need. You can then asign that child group to your users role (not the big one) and the user role tou your specific user. To clarify my answer, lets say you have this group:
$permArticles = $permission->create([
'name' => 'articles',
'slug' => [ // pass an array of permissions.
'create' => false,
'view' => false,
'update' => false,
'delete' => false,
],
'description' => 'All articles module permissions'
]);
then you can create something like:
$articlesPermUser = Permission::create([
'name' => 'articles.user',
'slug' => [ // an array of permissions only for student
'view' => true,
],
// we use permission inheriting.
'inherit_id' => $permArticles->getKey(),
'description' => 'user articles permissions'
]);
then you assign your new permission to your user role (I am assuming you alredy have a role name 'user'):
$userRole = Role::where('slug', 'user')->first();
$userRole->assignPermission('articles.user');
And finally you assign that role to... let say your logged user:
Auth::user()->assignRole($userRole);
You can also solve this problem by overwriting the permission, this could be done assigning a specific permission value to a user (but yes, you would need to do this for every single user in your app if needed, so I dont like this solution at all).
Lets say we keep our big group:
$permArticles = $permission->create([
'name' => 'articles',
'slug' => [ // pass an array of permissions.
'create' => false,
'view' => false,
'update' => false,
'delete' => false,
],
'description' => 'All articles module permissions'
]);
As this group says, any rol with your article permission assgined will not be able to do anything in your articles module. Lets say your user role alredy has this permission, but you want a certain user (lets say the logged one) be able to update an article. You can set the specific update permission value to true like so:
Auth::user()->addPermission('update.articles', true);
//or
Auth::user()->addPermission('articles', [
'update' => true,
]);
Thank you for the answer but over the time, I already find a perfect solution that match what I need. It is not much different from what I do in entrust.
So first I will just create a permission like this for view article
$class = 'article';
$permission = new Kodeine\Acl\Models\Eloquent\Permission();
$permUser = $permission->create([
'name' => $class.'_view',
'slug' => [
'view' => true,
],
'description' => 'View '.$class
]);
and then another one for example create article
$class = 'article';
$permission = new Kodeine\Acl\Models\Eloquent\Permission();
$permUser = $permission->create([
'name' => $class.'_create',
'slug' => [
'create' => true,
],
'description' => 'Create '.$class
]);
and later just assign those permission to user role, for example I want to make this user role to be can view article
$roleAdmin = Kodeine\Acl\Models\Eloquent\Role::where('name','=','user_1');
$roleAdmin->assignPermission('article_view');
I still don't understand about Inheritance feature, and I needed to do this quickly. It maybe not an ideal way, but it's works for me.

Cakephp auth component with two models session

I have two cakephp2 applications running on same database, but having different Auth tables and different $this->Auth->userModel values accordingly.
Authentication works well and users from one app can't log into other.
BUT.. as apps uses same CAKEPHP session cookie, this happens:
when user from app 'one' logs in, it can access any Auth protected action in app 'two'!
I will probably use different user roles and cookie names.
But still, why Auth component is ignoring Auth->userModel settings when checking the session? Is there a way to configure it to work right in this situation?
Thanks in advance for any suggestions.
If not configured otherwise, AuthComponent will write the authenticated user record to the Auth.User session key in CakePHP 2. But it can be changed:
AuthComponent::sessionKey
The session key name where the record of the current user is stored. If unspecified, it will be "Auth.User".
(In CakePHP 1.3 this was different: Auth.{$userModel name})
So, if your apps share a Session, which they do, if cookie name and Security.salt match, the logged in record will be shared.
There are two possibilities to solve this:
Separate the logins
Simply set a different AuthComponent::sessionKey for your two models. This will allow them to keep the logged in user separately
Separate the sessions
Configure different Cookie names and Salts for both apps, so their sessions cannot override each other. This is probably the cleaner solution, because it also covers the risk of other session keys being double-used.
I have a similar issue which is why I've started a bounty on this question. Basically I have a public facing part of the application which lets users login from one table and an administrative part of the application which lets admins login using a different table. My AppController looks something like this:
public $components = array(
'Session',
'Auth' => array(
'autoRedirect' => false,
'authenticate' => array(
'Form' => array(
'userModel' => 'User'
)
),
'loginAction' => array('controller' => 'users', 'action' => 'login'),
'loginRedirect' => array('controller' => 'users', 'action' => 'overview'),
'logoutRedirect' => array('controller' => 'users', 'action' => 'loggedout')
)
);
and I have another AdminController where I have this:
public $components = array(
'Session',
'Auth' => array(
'authenticate' => array(
'CustomForm' => array(
'userModel' => 'Admin'
)
),
'loginAction' => array('controller' => 'admin', 'action' => 'login'),
'loginRedirect' => array('controller' => 'admin', 'action' => 'index'),
'logoutRedirect' => array('controller' => 'home', 'action' => 'index')
)
);
But as mentioned in this question, sessions from the two don't get along and overwrite each other. What's the best way to overcome this?
Extend the Model/Datasource/Session/DatabaseSession.php session handler with something like MyDatabaseSession and overwrite the write and read methods. Maybe simply copy the existing code of both methods and add something like
'app_id' => Configure::read('App.appId')
to the read() conditions and do the same in the write method. And do not forget to add the field to your session database schema and to configure the session to use your handler.
<?php
App::uses('DatabaseSession', 'Model/Datasource/Session');
class ExtendedDatabaseSession extends DatabaseSession {
public function read($id) {
$row = $this->_model->find('first', array(
'conditions' => array(
'app_id' => Configure::read('App.appId'),
$this->_model->primaryKey => $id)));
if (empty($row[$this->_model->alias]['data'])) {
return false;
}
return $row[$this->_model->alias]['data'];
}
public function write($id, $data) {
if (!$id) {
return false;
}
$expires = time() + $this->_timeout;
$record = compact('id', 'data', 'expires');
$record[$this->_model->primaryKey] = $id;
$record['app_id'] = Configure::read('App.appId');
return $this->_model->save($record);
}
}
I do not know your app, so were you write the app id to the config data is up to you, bootstrap or beforeFilter() maybe. You should add it before the session gets initialized I think or you'll need to re-init the session or something. I leave it up to you to look the right point up. :)

Resources