Add custom RBAC rule to PhpManager in Yii 2.0 - php

I want to add a custom rule to PhpManager RBAC in Yii 2.0.
Here is the custom rule (#app/rbac/OwnerRule.php):
<?php
namespace app\rbac;
use yii\rbac\Rule;
/**
* Checks if userID matches user passed via params
*/
class OwnerRule extends Rule
{
public $name = 'isOwner';
public function execute($user, $item, $params)
{
$access = false;
if(isset($params['id'])){
// My custom logic used to set $access
}
return $access;
}
}
Here is the RBAC hierarchy file (#app/data/rbac.php)
<?php
use yii\rbac\Item;
return [
'manageThing0' => ['type' => Item::TYPE_OPERATION, 'description' => '...', 'bizRule' => NULL, 'data' => NULL],
'manageThing1' => ['type' => Item::TYPE_OPERATION, 'description' => '...', 'bizRule' => NULL, 'data' => NULL],
'manageThing2' => ['type' => Item::TYPE_OPERATION, 'description' => '...', 'bizRule' => NULL, 'data' => NULL],
// AND THE ROLES
'guest' => [
'type' => Item::TYPE_ROLE,
'description' => 'Guest',
'bizRule' => NULL,
'data' => NULL
],
'user' => [
'type' => Item::TYPE_ROLE,
'description' => 'User',
'children' => [
'guest',
'manageThing0', // User can edit thing0
],
'bizRule' => 'return !Yii::$app->user->isGuest;',
'data' => NULL
],
'moderator' => [
'type' => Item::TYPE_ROLE,
'description' => 'Moderator',
'children' => [
'user', // Can manage all that user can
'manageThing1', // and also thing1
],
'bizRule' => NULL,
'data' => NULL
],
'admin' => [
'type' => Item::TYPE_ROLE,
'description' => 'Admin',
'children' => [
'moderator', // can do all the stuff that moderator can
'manageThing2', // and also manage thing2
],
'bizRule' => NULL,
'data' => NULL
],
];
How do I use my custom rule in the hierarchy file?

See these links hope you will find what you are looking for,
http://www.yiiframework.com/doc-2.0/guide-security-authorization.html
http://yii2-user.dmeroff.ru/docs/custom-access-control
RBAC for basic yii2 template

Related

Laravel: Edit value only if it appears in the request?

in my app the user can update the info of stripe connected account, however I ONLY want to actullay update the value of the fields that appear in the request payload, I could do this with a simple if check but the way I update the stripe array method makes this issue more complicated .
Is there any syntax sugar or trick to make this easier.
How my update method looks;
public function editConnectedAccount(Request $request)
{
$account = Account::retrieve($request->connectedAccountId);
Account::update(
$request->connectedAccountId,
[
'type' => 'custom',
'country' => 'ES',
'email' => $request->userEmail,
'business_type' => 'individual',
'tos_acceptance' => [ 'date' => Carbon::now()->timestamp, 'ip' => '83.46.154.71' ],
'individual' =>
[
'dob' => [ 'day' => $request->userDOBday, 'month' => $request->userDOBmonth, 'year' => $request->userDOByear ],
'first_name' => $request->userName,
'email' => $request->userEmail,
'phone' => $request->userPhone,
'last_name' => $request->userSurname,
//'ssn_last_4' => 7871,
'address' => [ 'city' => $request->userBusinessCity, 'line1' => $request->userBusinessAddress, 'postal_code' => $request->userBusinessZipCode, 'state' => $request->userBusinessCity ]
],
'business_profile' =>
[
'mcc' => 5812, //got it
'description' => '',
//'url' => 'https://www.youtube.com/?hl=es&gl=ES', //got it
],
'capabilities' => [
'card_payments' => ['requested' => true],
'transfers' => ['requested' => true],
],
]
);
return response()->json([
'account' => $account,
], 200);
Consider using a Form Request where you preform validation. This will neaten up your controller for a start and also make validation (never trust user input!) reusable.
Assuming validation is successful, calling $request->validated() from inside your controller method will return only the fields present and validated. You can then use either fill($request->validated()) or update($request->validated()).

Cannot use models in the config folder in Laravel

I have a plugin that generates a navbar using PHP. The folder is in project/config/menu.php
It looks like this:
<?php
return [
//HORIZONTAL MENU LAYOUT - MENU
'horizontal' => [
[
'title' => 'bar',
'link' => '/bar/all',
'active' => 'bar*',
'icon' => 'fa fa-sign-in',
],
[
'title' => 'foo',
'link' => '/foo/all',
'active' => 'foo*',
'icon' => 'fa fa-sign-out',
],
]
];
I want to add some model information.
This is my attempt:
<?php
use Auth;
$id = Auth::user()->id;
return [
//HORIZONTAL MENU LAYOUT - MENU
'horizontal' => [
[
'title' => 'bar',
'link' => '/bar/'. $id,
'active' => 'bar*',
'icon' => 'fa fa-sign-in',
],
[
'title' => 'foo',
'link' => '/foo/all',
'active' => 'foo*',
'icon' => 'fa fa-sign-out',
],
]
];
I get this error: Class 'Auth' not found. I have also tried with models:
$model = \App\Model::count();
Which gives me this error:
Call to a member function connection() on null
How do I use these models here?
laravel config loads before any other things, so instantiating model will give an error, and that error you are getting is due to no database connection information loaded during this specific config file loads. I wonder why you need to call model in config, you can simply build something like templates of menu layout like below:
<?php
return [
//HORIZONTAL MENU LAYOUT - MENU
horizontal' => [
[
'title' => 'bar',
'link' => '/bar/%d', // here %d is userId from database
'active' => 'bar*',
'icon' => 'fa fa-sign-in',
],
[
'title' => 'foo',
'link' => '/foo/all',
'active' => 'foo*',
'icon' => 'fa fa-sign-out',
],
]
];
and later replace that %d with value from model.

Change Fieldset Fields' required parameter dynamically

I have a moneyFieldset with 2 fields, amount and currency.
class MoneyFieldset ...
{
public function __construct($name = null, $options = array())
{
parent::__construct($name, $options);
$this->setHydrator(...);
$this->add(array(
'name' => 'currency',
'type' => 'select',
'options' => array(
'value_options' => \Core\Service\Money::getAvailableCurrencies(true),
),
'attributes' => array(
'value' => \Core\Service\Money::DEFAULT_CURRENCY,
),
));
$this->add(array(
'name' => 'amount',
'type' => 'text',
));
}
}
public function getInputFilterSpecification()
{
$default = [
'amount' => [
'required' => false,
'allow_empty' => true,
'filters' => [
['name' => AmountFilter::class]
],
'validators' => [
]
],
'currency' => [
'required' => false,
'allow_empty' => true,
'filters' => [
['name' => StringToUpper::class]
],
'validators' => [
]
]
];
return \Zend\Stdlib\ArrayUtils::merge($default, $this->filterSpec, true);
}
I'm using moneyFieldset in my other fieldsets like this:
// Price Field
$this->add(array(
'name' => 'price',
'type' => 'form.fieldset.moneyFieldset',
'attributes' => array(
'required' => true,
'invalidText' => 'Please type an amount'
),
'options' => array(
...
),
));
When I set filter like this:
function getInputFilterSpecification()
{
'price' => [
'required' => true,
'allow_empty' => false,
],
}
It's not working because price has 2 fields, so how can I say price[amount] and price[curreny] is required?
You can provide the input specifications for the nested fieldset (within the context of the form) using the following array structure.
public function getInputFilterSpecification()
{
return [
// ...
'price' => [
'type' => 'Zend\InputFilter\InputFilter',
'amount' => [
'required' => true,
],
'currency' => [
'required' => true,
]
],
//...
];
}
If you are dynamically modifying the values of the input filter it might be worth considering creating the validator using a service factory class and then attaching it to a form using the object API rather than arrays.
As I said in #AlexP's comment, a field, or a group of field declared as Required like this :
function getInputFilterSpecification()
{
'price' => [
'required' => true,
'allow_empty' => false,
],
}
Not means that it will be print an html like this :
<input type="text" required="required"/>
It just check when you'll do $form->isValid() if your fields are empty and required or other checks.
To achieve that, you just have to set in attributes that you want to require those fields. As you already did. Attributes can add, same as class attribute, html code to an input.
P.S : AlexP's answer is the best answer I just give more info about it.

Yii2 ListView custom data-attribute based on currend DP model

I need to set custom data-attribute to the ListView elements. As example I try to get current DataProvider model id. But I still view error "htmlspecialchars() expects parameter 1 to be string, object given". Please check my code and halp me - how I should get this ID?
<?= ListView::widget([
'dataProvider' => $photoProvider,
'id' => 'photo-list',
'itemView' => '_photoListItem',
'viewParams' => [
'fullView' => true,
],
'options' => [
'tag' => 'ul',
'class' => 'list-view'
],
'itemOptions' => [
'tag' => 'li',
'class' => 'item',
'data' =>[
'test' => function ($model, $key, $index, $widget) {
return Html::encode($model->id);
}
]
],
'pager' => [
'class' => ScrollPager::className(),
'container' => '#photo-list',
'item' => '.item',
'triggerText' => '<div class="btn more">Load More</div>',
'noneLeftText' => '',
'triggerOffset' => 2,
'negativeMargin' => 200
],
'layout' => "{items}\n{pager}",
]);
?>
This is not possible in the ListView, according to the doc:
'data' => [
'test' => function ($model, $key, $index, $widget) {
return Html::encode($model->id);
}
]
You cannot use a function here. Only static values are allowed.
Alternatively, you can provide those attributes in tags of your _photoListItem view file.

CakePHP 3 fixtures not Importing

I am using phpunit for testing a CakePHP 3 Controller. The problem is that it does not importing the fixtures. It is just importing live DB data. Reading and writing just uses the LIVE DB even though I have defined a test DB and fixtures. Am I doing something wrong below?
My Fixture
class ToursFixture extends TestFixture {
public $connection = 'test';
public $fields = [
'id' => ['type' => 'integer'],
'title' => ['type' => 'string', 'length' => 255, 'null' => false],
'created' => 'datetime',
'modified' => 'datetime'
'_constraints' => [
'primary' => ['type' => 'primary', 'columns' => ['id']]
]
];
public $records = [
[
'title' => 'tour 1',
'created' => '2015-07-24 09:15:48',
'modified' => '2015-07-24 09:15:48',
],
];
}
My Test Class
namespace App\Test\TestCase\Controller;
use Cake\ORM\TableRegistry;
use Cake\TestSuite\IntegrationTestCase;
use Cake\TestSuite\TestCase;
use App\Controller\ToursController;
use Cake\TestSuite\Fixture\TestFixture;
require '../../bootstrap.php';
class ToursControllerTest extends IntegrationTestCase {
public $fixtures = ['app.tours'];
App Config DB
'test' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',

Categories