WP_Role could not be converted to string - php

I am receiving this error when trying to add new capabilities to two of my user roles:
Error: Object of class WP_Role could not be converted to string ... on line 67
The capability I am trying to add will allow the user to see a custom page that we have built in our WP setup. This is the code I have written to populate the roles:
public static function add_csv_capability():void {
$rolesToPopulate = array((get_role( 'administrator' )), (get_role( 'editor' )));
$roles = array_fill_keys(($rolesToPopulate),NULL);
echo $roles;
foreach ($roles as $role) {
if ($role) {
$role->add_cap('use_csv_uploader');
}
}
}
Someone asked if this would answer my question, and it does and it doesn't. It explains what the error is, but now that I know what the error is all about, I need to figure out how to get this code to do what I want, which is to allow me to add capabilities to more than one role.
Any help you can give would be greatly appreciated.
Thanks!

First, create an array of role names and then use array_fill_keys() to create an associative array with these role names as keys and null as values. You then loop through this array and retrieve the corresponding WP_Role object using get_role() and then add the capability to that role.
So you can use an array of role names instead of an array of WP_Role objects, like this
public static function add_csv_capability():void {
$rolesToPopulate = array('administrator', 'editor');
$roles = array_fill_keys($rolesToPopulate, NULL);
foreach ($roles as $role) {
if ($role) {
$role_obj = get_role($role);
$role_obj->add_cap('use_csv_uploader');
}
}
}
I hope this helps you fix the issue you are facing.

Related

Laravel model accessor, 'Call to a member function getAttribute() on null'

I'm trying to configure my Laravel app to store/retrieve user emails from a separate, related table. I want Laravel's built-in User model to retrieve its email record from a related Person model, which is linked by a person_id field on User.
I followed the steps in this answer, which is very similar to my scenario.
However, I'm encountering an issue:
I create a new user, and inspecting the records shows that everything has been set up properly: a Person model is created with extra information not included in User, and User properly references the Person model via a relation titled person. I can log in using the new user, which makes me think the service provider is properly linked as well.
When I send a password reset link, however, I get the error:
App\Models\User : 65
getEmailAttribute
'Call to a member function getAttribute() on null'
.
public function person()
{
return $this->belongsTo(Person::class);
}
public function getEmailAttribute()
{
// Error occurs here!
return $this->person->getAttribute('email');
}
public function getFirstNameAttribute()
{
return $this->person->getAttribute('firstName');
}
public function getLastNameAttribute()
{
return $this->person->getAttribute('lastName');
}
It seems like the code in Password::sendResetLink thinks that the person relation is null. I've checked which User id it's trying to reference, and a manual inspection shows that person is defined, I can even use the accessor normally, e.g. User::find({id})->email. I can't think of any reason why person would be null, as it's set up as a foreign key constraint on the database level...
Trying a password reset on another user account in my app - this one created by the database seeder - and it works fine...
Additionally, a nonsense email (not stored in DB) produces the same error... although I've confirmed that my first encounter with this error was using a proper email that is stored in the DB...
EDIT:
public function retrieveByCredentials(array $credentials)
{
if (
empty($credentials) ||
(count($credentials) === 1 &&
str_contains($this->firstCredentialKey($credentials), 'password'))
) {
return;
}
// First we will add each credential element to the query as a where clause.
// Then we can execute the query and, if we found a user, return it in a
// Eloquent User "model" that will be utilized by the Guard instances.
$query = $this->newModelQuery();
foreach ($credentials as $key => $value) {
if (str_contains($key, 'password')) {
continue;
}
if (is_array($value) || $value instanceof Arrayable) {
$query->with([$this->foreign_model => function ($q) use ($key, $value) {
$q->whereIn($key, $value);
}]);
} elseif ($value instanceof Closure) {
$value($query);
} else {
//This is not working
$query->with([$this->foreign_model => function ($q) use ($key, $value) {
$q->where($key, $value);
}]);
}
}
return $query->first();
}
.
'users' => [
'driver' => 'person_user_provider',
'model' => App\Models\User::class,
'foreign_model' => 'person'
],
In my experience, somehow you app is calling this logic with faulty data and you are not certain whats causing it. There is ton of exception services, that can give deeper insights to how this happens, context, url called from etc. Since you are here asking the question, i'm guessing you want it fixed and we can help with the first case i described.
Instead why not create a defensive approach that helps this case, which can keep coming up. Laravel has the optional() helper, that makes it possible to call on null objects without the code crashing, the variable will end up null.
return optional($this->person)->getAttribute('email');
PHP 8 has a ?-> nullsafe operator, which does the same. I'm assuming PHP 8 has not been widespread adopted, so optional will works in all cases.
return $this->person?->getAttribute('email');

how does laravel UPDATE method work

I am working on this laravel project where user can upload an avatar image. My users table does not have any column yet to store the file location. So i was testing this in phpunit following the TDD series in laracast.
After the file is uploaded successfully and moved to the desired location in the server, i called the update method on the authenticated user like below:
$user = auth()->user();
$user->update(['avatar_location' => 'avatars/avatar.jpg']);
Note that avatar_location is not yet there on the users table. I expected this to fail but it didn't. I tried to find out what was going on so i followed through to the update() method in the model class:
//file Illuminate/Database/Eloquent/Model.php
public function update(array $attributes = [], array $options = [])
{
//dd($attributes); //prints 'avatar_location"=>"avatars/avatar.jpg'
if (! $this->exists) {
//dd($attributes);
return false;
}
return $this->fill($attributes)->save($options);
}
till this point the dd($attribute) prints the value that i passed to the update() method.
So i followed into the fill() method that is being called with the attribute parameter. However when i die dumped the received parameter from inside the fill() method i am not seeing the key=>value pair that i passed. Instead it was showing the other attributes of the user:
/**
* Fill the model with an array of attributes.
*
* #param array $attributes
* #return $this
*
* #throws \Illuminate\Database\Eloquent\MassAssignmentException
*/
public function fill(array $attributes)
{
//dd($attributes);
//does not print 'avatar_location"=>"avatars/avatar.jpg'
//rather, prints:
//array:4 [
// "name" => "Armand Mraz"
// "email" => "akautzer#example.net"
// "password" => "$2y$10$h7OG9/Toh31MsyFQc8lfg.wHeQC7maP4Bh37bea.DXU//IuRuXZi."
// "remember_token" => "X0udISwEEM"
]
$totallyGuarded = $this->totallyGuarded();
foreach ($this->fillableFromArray($attributes) as $key => $value) {
$key = $this->removeTableFromKey($key);
// The developers may choose to place some attributes in the "fillable" array
// which means only those attributes may be set through mass assignment to
// the model, and all others will just get ignored for security reasons.
if ($this->isFillable($key)) {
$this->setAttribute($key, $value);
} elseif ($totallyGuarded) {
throw new MassAssignmentException($key);
}
}
return $this;
}
I spent a lot of time trying to figure out why?
can anyone please explain?
And why the update method is not failing even though i am trying to update a column that does not exist?
Thanks,Yeasir
When you're updating an object, Laravel is trying to match the keys of the array of data and the list of fillable fields. All pairs of key/valye missing from the fillable fields are not considered. It's the reason why it's not failing.
You have to update the fillable field list (property $fillable) in your user model.
Have a look at the documentation.
If you add avatar_location in your fillable fields list and the field doesn't exist, in this case, it will throw an exception.

Laravel's Eloquent table 'inheritence' with parents

I have a Laravel model acl_groups that has a JSON column inherits. What should I do, the "laravel way" to query the inherited groups when checking if a group can do something? The rights are stored in another JSON column, allow/deny so I can just do a in_array to check a single group if they have access.
On your model you can set a getter
public function getInheritsAttribute($v)
{
return $v ? json_decode($v, true) : [];
}
OR
if you dont want a getter you can try a pseudo getter
public function getPseudoAttribute()
{
return $this->inherits ? json_decode($this->inherits, true) : [];
}
Kind of maybe did mistake on second one.
And on other model the same thing
so when you call $item->inherits = you will get an array
First you may try to prepare the array like removing same keys or values
and after just check
if (array_key_exists('thing_to_check', $item->inherits)) {
return true;
}
This is not a working code, it is just an idea how you can do you.
Take a look at Cartalyst Sentinel how they check the permissions for groups and users.

Why is the Symfony2 Voter unanimous decision-strategy looping through the passed attributes?

I implemented a custom Symfony2 Voter and would pass an array of attributes to the first parameter of the denyAccessUnlessGranted like so in my controller:
$attr = [
'module' => 'userModule'
'action' => 'edit'
];
$this->denyAccessUnlessGranted($attr, $this, 'Not authorize to edit user');
This works alright if the decision manager approach is set to affirmative. However when I shifted to the unanimous approach all of sudden things didn't work because of the way my custom voter is designed. I looked through the Symfony source code and found that the reason is because the method for determining the result of a vote for the unanimous approach loops through the attributes before calling all the registered voters (instead of simply passing them to the voters as is the case for the affirmative and consensus approaches).
Snippets of the Symfony/Component/Security/Core/Authorization/AccessDecisionManager are included below:
private function decideAffirmative(TokenInterface $token, array $attributes, $object = null)
{
$deny = 0;
foreach ($this->voters as $voter) {
$result = $voter->vote($token, $object, $attributes);
...
}
}
private function decideConsensus(TokenInterface $token, array $attributes, $object = null)
{
foreach ($this->voters as $voter) {
$result = $voter->vote($token, $object, $attributes);
...
}
}
private function decideUnanimous(TokenInterface $token, array $attributes, $object = null)
{
$grant = 0;
// ***** THIS IS THE ISSUE: WHY LOOP THROUGH THE ATTRIBUTES ****
foreach ($attributes as $attribute) {
foreach ($this->voters as $voter) {
$result = $voter->vote($token, $object, array($attribute));
...
}
}
}
The one for the unanimous decision making is the third one. What's the reasoning behind having to loop through the attributes? This means I will have to recode my custom voter depending on what decision making strategy I use, which I find really strange.
PS: The details of the implementation of my custom voter is not really important to this question so I decided not to put it here.
PS #2: This isn't my code, this is code from the Symfony2 framework (https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php). I just want to know the reasoning behind it so that I can use the Voter functionality correctly. I'm guessing the best people to answer this would be people who knows the Symfony2 source code intimately.
Look at class RoleVoter.
Voter::Vote() returns VoterInterface::ACCESS_GRANTED if any of the attributes passed as arguments is authorised (there is at least one allow vote). If there are many attributes and some of there are authorised and some not - VoterInterface::ACCESS_GRANTED is casted anyway.
But unanimous voting need that every attribute is authorised (no deny votes); thus we need test every attribute separately.

Calling function with return value in cakephp

I am new to cakephp. I have a problem with calling the function. here is my issue.
In Contrloller file i get all the values using the following function
public function index()
{
$conditions = array(
'order' => array('Histroy.chat_sk DESC')
);
$this->set('histroys', $this->Histroy->find('all',$conditions));
}
In My model file have the following,
class Histroy extends AppModel
{
public $tablePrefix = 'plc_';
public $useTable = 'chat_history';
}
In my view file i have listed the values using foreach() function and that as follows
foreach ($histroys as $histroy):
$oper_name = $histroy['Histroy']['operator_fk'];
$operator_email = $histroy['Histroy']['email'];
endforeach
in that opertaor_fk is a field in history table. So i need get the operator name by another table as operators. So i need to call that function in the view.
Ex : In core we can do like as,
$operator_name = operator_name($fetch['operator_id']);
Function should be like this:
function operator_name($id)
{
// Select the value for the matched field in the operator
return $operator_name;
}
In cakephp how can i retrieve the values.
Please help me out to fix this. Thanks in Advance
Follow the blog tutorial for cake. It'll explain how to create associations and relationships between tables to let you do what is is you want, but in a nutshell, you need to create a relationship between History and Operator models and work from there.

Categories