create rule class in dektrium module rbac in basic project yii2 - yii2

I installed dektrium\user and dektrium\rbac\ modules for manage user and access control.Related tables and files installed completely and i can see several tabs in /user/admin path ( Users, Roles, Permissions, Rules, Create ) for work with modules.I can manage users perfectly(create user, reset password, edit,..). buy I can not create a rule.
I created a class in app\rbac\rules folder named AuthorRule :
<?php
namespace app\rbac\rules;
use yii\rbac\Rule;
use app\models\News;
/**
* Checks if authorID matches user passed via params
*/
class AuthorRule extends Rule
{
public $name = 'isAuthor';
/**
* #param string|int $user the user ID.
* #param Item $item the role or permission that this rule is associated with
* #param array $params parameters passed to ManagerInterface::checkAccess().
* #return bool a value indicating whether the rule permits the role or permission it is associated with.
*/
public function execute($user, $item, $params)
{
return isset($params['news']) ? $params['news']->createdBy == $user : false;
}
}
(I created news class with model,controler,views)
but when I entered name and class rule in my modules. Neither the data is logged nor the error message. I can't add the rest of the sections until I get into the rule.

I certainly hope the OP has solved their problem by now, but other people might encounter it.
First a remark: as described, the Save fails silently. This is because the form is submitted with Ajax (XHR). The error can be seen in the browser console.
This is the relevant part of the error message:
preg_match(): Compilation failed: invalid range in character class at offset 8
Due to the architecture of Yii 2, the actual regexp is a little tricky to find. It is in the model for Rules in yii2-rbac vendor/dektrium/yii2-rbac/models/Rule.php, line 86.
The original regexp is /^[\w][\w-.:]+[\w]$/
PHP 7.3 uses the PCRE2 library instead of the original PCRE, and the pattern above is wrong. The dash (-) needs to be escaped.
The full line should now be:
['name', 'match', 'pattern' => '/^[\w][\w\-.:]+[\w]$/'],
As the yii2-rbac package is abandoned, you can just modify the file. A more robust solution would be to override the Class.

Related

How can I translate Laravel's default validation errors in JSON file?

I need to translate Laravel's default validation errors in JSON files. The problem is if I want to overwrite a translation, like the 'required' validation error in resourses/lang/de.json file, it doesn't work.
The reason why I have to do this is the Phrase translator system what I am using.
Any idea? Thanks!
UPDATE
After some research, now I see what is my 'problem'. Laravel using the trans() function for translating the validation errors but if you want to use Laravel's JSON translation then you have to use the __() function. Okey, I know why they are doing in that way, because the validation errors are structured by 'short keys' and the JSON formatted translation if for use strings as keys.
But what if I still want to translate the default errors in the JSONish (I know it's a futuristic word) way? Follow my solution here:
First of all you have to create a form request (https://laravel.com/docs/7.x/validation#creating-form-requests):
php artisan make:request UserUpdateRequest
In the newly created form request file you have to overwrite the messages function to be able to translate the validation errors:
namespace App\Http\Requests\v1;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use App\Exceptions\ApiValidationException;
class UserUpdateRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => ['required', 'string', 'min:3', 'max:255'],
];
}
/**
* Get custom messages for validator errors.
*
* #return array
*/
public function messages()
{
return [
'name.required' => __('The user name is required.'),
'name.string' => __('The user name must be a string.'),
'name.min' => __('The user name must be at least three characters.'),
'name.max' => __('The user name may not be greater than 255 characters.'),
];
}
}
Now we have to create the translations files (https://laravel.com/docs/7.x/localization#using-translation-strings-as-keys) and put the new translation strings into them.
# resourses/lang/de.json
{
"The user name is required." : "The user name is required.",
"The user name must be a string." : "The user name must be a string.",
"The user name must be at least three characters." : "The user name must be at least three characters.",
"The user name may not be greater than 255 characters." : "The user name may not be greater than 255 characters."
}
And that's all.
I hope this description of translation process it will be useful for someone else.
I need to translate Laravel's default validation errors in JSON files. The problem is if I want to overwrite a translation, like the 'required' validation error in resourses/lang/de.json file, it doesn't work.
The reason why I have to do this is the Phrase translator system what I am using.
Any idea? Thanks!
ANSWER
After some research, now I see what is my 'problem'. Laravel using the trans() function for translating the validation errors but if you want to use Laravel's JSON translation then you have to use the __() function. Okey, I know why they are doing in that way, because the validation errors are structured by 'short keys' and the JSON formatted translation if for use strings as keys.
But what if I still want to translate the default errors in the JSONish (I know it's a futuristic word) way? Follow my solution here:
First of all you have to create a form request (https://laravel.com/docs/7.x/validation#creating-form-requests):
php artisan make:request UserUpdateRequest
In the newly created form request file you have to overwrite the messages function to be able to translate the validation errors:
namespace App\Http\Requests\v1;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use App\Exceptions\ApiValidationException;
class UserUpdateRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => ['required', 'string', 'min:3', 'max:255'],
];
}
/**
* Get custom messages for validator errors.
*
* #return array
*/
public function messages()
{
return [
'name.required' => __('The user name is required.'),
'name.string' => __('The user name must be a string.'),
'name.min' => __('The user name must be at least three characters.'),
'name.max' => __('The user name may not be greater than 255 characters.'),
];
}
}
Now we have to create the translations files (https://laravel.com/docs/7.x/localization#using-translation-strings-as-keys) and put the new translation strings into them.
# resourses/lang/de.json
{
"The user name is required." : "The user name is required.",
"The user name must be a string." : "The user name must be a string.",
"The user name must be at least three characters." : "The user name must be at least three characters.",
"The user name may not be greater than 255 characters." : "The user name may not be greater than 255 characters."
}
And that's all.
I hope this description of translation process it will be useful for someone else.
Based on the answer provided I digged some more and discovered the double underscore function is working as intended in the default validation.php file! I tested it with Laravel 5.6.
I have a similar issue that I need to provide a way for users to give translations for everything in the web app and so I started to test the solution. While it works as explained it does not use the placeholder attribute anymore and therefore it is not very scalable in my situation.
I tested using the double underscore function with the following requirements:
locale and fallback_locale are set to 'en' in app.php
There is an en folder inside resources/lang
There is a validation.php file inside the en folder
There is a locale json file (like pt-br.json) inside resources/lang folder
The application sets the locale dynamically using App::setlocale()
All that is needed to change in validation.php is to use the function in the string, like the following:
# before
'unique' => 'The :attribute has already been taken.',
#after
'unique' => __('The :attribute has already been taken.'),
And the json file needs to have a string key with the same string, like the following:
"The :attribute has already been taken.": ":attribute j\u00e1 existe!"
Thanks for making me thinking more on this problem. I think Laravel should have better support for use cases like this.

Yii2 relation based on attribute values instead of keys

I have 2 tables in the db (mysql), and between the 2 there is no classic relationship through keys or ids. The only way I could define relationship would be through attribute values. E.g. table wheel and car and certain wheels would match certain cars because of the size only. Can it be defined on DB level, and/or in yii2, and if yes, how?
In the relations I can add an onCondition(), but you have to define an attribute (???), too:
public function getWheels() {
return $this->hasMany(\app\models\Wheel::className(), ['???' => '???'])->onCondition(['<', 'wheelsize', $this->wheelsize]);
}
I could use a fake attribute and set it in all records like to 1, but it seems a little bit odd for me.
I find nothing on the web regarding this or maybe I'm just searching the wrong way, or maybe I'm trying something that's totally bad practice. Can you please point me to the right direction?
Hypothetically you can set an empty array as a link, but for security reasons (I think) the condition "0 = 1" is automatically added in the select.
I faced your own problem several times and the best solution I could find was to use ActiveQuery explicitly (similar to what happens for hasOne and hasMany):
public function getWheels() {
return new ActiveQuery(\app\models\Wheel::className(), [
'where' => 'my condition' // <--- inserte here your condition as string or array
'multiple' => true // true=hasMany, false=hasOne
// you can also add other configuration params (select, on condition, order by, ...
]);
}
This way you can get both the array and the ActiveQuery to add other conditions:
var_dump($model->wheels); // array of wheels objects
var_dump($model->getWheels()); // yii\db\ActiveQuery object
$model->getWheels()->andWhere(...); // customize active query
I don't think that you could achieve this through relation.
But there is a way to work around the limitation.
<?php
namespace app\models;
class Car extend \yii\db\ActiveRecord
{
/**
* #var \app\models\Wheel
*/
private $_wheels;
/**
* #return \app\models\Wheel[]
*/
public function getWheels()
{
if (!$this->_wheels) {
$this->_wheels = Wheel::find()
->where(['<', 'wheelsize', $this->wheelsize])
//->andWhere() customize your where here
->all();
}
return $this->_wheels;
}
}
Then you could access the wheels attribute just as relation does.
<?php
$car = Car::find(1);
$car->wheels;
Beware that this way does not support Eager Loading

How can I get the _registryAlias from Entity

Let say I have:
$user = $this->Users->newEntity();
So now how can I get the text 'Users' from the $user entity?
In the Entity class I see the _registryAlias, but it is protected and don't have any function to get that. (I dont want to modify the core also)
I need this for my global function that I want to pass only the $user (not to pass both $user and 'Users' to that function).
Thanks.
If you look closely there is a method that returns that properties value: EntityTrait::source()
See API > \Cake\Datasource\EntityTrait::source()
[...]
If called with no arguments, it returns the alias of the repository this entity came from if it is known.
[...]

Zend_Db_Table Base table or view not found

I have taken over an application written with the use of the Zend MVC and Zend_Db_Table for DB access. I am trying to add a new table but get the error:
Base table or view not found: 1146 Table 'maa_agencies.contact' doesn't exist
However maa_agcencies.contact very much DOES exists and is in the same DB as the rest of the tables being accessed.
Here are my steps and code:
Step 1:
Create the Model Class
file: application/models/DbTable/Contact.php
class Model_DbTable_Contact extends Zend_Db_Table_Abstract
{
protected $_name = 'contact';
}
Step 2:
Instantiate the Class the same way it's done a dozen time in a controller (all other tables work)
file: application/modules/agency/controllers/IndexController.php (also step 3)
$agency_contact = new Model_DbTable_Contact();
Step 3:
Write my data to my new table ($store_contact is an assoc array with key = column name value = value)
$agency_contact->insert($store_contact);
Is there some caching function in Zend I am unaware of?
Some special thing I need to do to tell it I added a new table?
All documentation I have come across says this is all that is required, and as I state above the file I am trying to access my table through is already accessing 2 other tables in the same DB, in fact the line just above where I instantiate my Contact model is this statement that works fine:
$sm = new Model_DbTable_SentEmail();
The name space idea seems awesome! If this system wasn't some bastardization of the framework. Here is a currently working Model
/**
* #category Model_DbTable
* #package Model_DbTable_States
class Model_DbTable_States extends Zend_Db_Table_Abstract
{
protected $_name = 'state_list';
}
Is there some vodoo in the commenting perhaps, I am unable to find anywhere in the code where a namespace is registered at all.
Change your Class names of Model Directory. Add Prefix Application_
Example: Application_Model_DbTable_Contact
You forgot to add the namespace to your class
class Yournamespace_Model_DbTable_Contact extends Zend_Db_Table_Abstract
{
protected $_name = 'contact';
}
IN your application.ini ad this line
autoloaderNamespaces[] = "Yournamespace_"

MAGENTO: cannot find catalog_product table. How does $installer->getTable('catalog/product') work then?

I looked through the file Mage/Catalog/sql/catalog_setup/install-1.6.0.0.php.
The part of code:
$installer = $this;
/* #var $installer Mage_Catalog_Model_Resource_Setup */
$installer->startSetup();
/**
* Create table 'catalog/product'
*/
$table = $installer->getConnection()
->newTable($installer->getTable('catalog/product'))
->addColumn('entity_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
'identity' => true,
'unsigned' => true,
'nullable' => false,
'primary' => true,
), 'Entity ID')
You can see here catalog_product implementation: $installer->getTable('catalog/product').
But I couldn't find this table in DB.
How does it work then? I always thought that catalog/product = catalog_product.
The following function
getTable('catalog/product')
can be traced back to
app/code/core/Mage/Core/Model/Resource.php
checking the public function getTableName($modelEntity) you will see that the logic treats also resource table names:
<catalog_resource>
<class>Mage_Catalog_Model_Resource</class>
<deprecatedNode>catalog_resource_eav_mysql4</deprecatedNode>
<entities>
<product>
<table>catalog_product_entity</table>
</product>
more resources about this:
Magento ORM: Entity Attribute Value; Part 1 and
Magento Setup Resources from Alan Storm
As is often the case in Magento, configuration is being used. Here's the call stack:
Mage_Core_Model_Resource_Setup::getTable('catalog/product')
Mage_Core_Model_Resource::getTableName('catalog/product');
When a '/' is present in the argument passed to the core/resource class's getTableName method, the configuration DOM is inspected. First the method will resolve the resourceModel node with the following line:
$resourceModel = (string) Mage::getConfig()->getNode()->global->models->{$model}->resourceModel;
Then, the core/resource class calls its getEntity() method, with the resourceModel node passed as the argument. This method simply looks under the resolved (resource) model node for the entity declaration (i.e. tablename):
Mage::getConfig()->getNode()->global->models->{$model}->entities->{$entity};
In the case of catalog/product, the above maps to:
Mage::getConfig()->getNode()->global->models->catalog_resource->entities->product;
If you look in Mage_Catalog's configuration xml, you'll see this borne out. The reason why it is best to access the tablename via configuration is that it is possible to specify table prefix, and using this method will return the correct name.