I have a User and Account model. The relationship is User belongs to Account, Account has many Users.
Here is the model code for both:
User Model:
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'account' => array(self::BELONGS_TO, 'Account', 'account_id'),
);
}
Account Model:
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'users' => array(self::HAS_MANY, 'User', 'account_id'),
'userCount'=>array(self::STAT,'User','account_id'),
);
}
I have this code in my UserIdentity.php for logging in which WAS working just fine:
public function authenticate()
{
$user=User::model()->findByAttributes(array('username'=>$this->username));
if($user===null)
$this->errorCode=self::ERROR_USERNAME_INVALID;
else{
if($user->password!==$user->encrypt($this->password))
$this->errorCode=self::ERROR_PASSWORD_INVALID;
else{
$this->_id=$user->id;
if($user->last_login_time==null)
$lastLogin=time();
else
$lastLogin=strtotime($user->last_login_time);
$this->setState('lastLoginTime', $lastLogin);
$this->setState('account',array('id'=>$user->account->id,'name'=>$user->account->name,));
$this->errorCode=self::ERROR_NONE;
}
}
return !$this->errorCode;
}
It started giving an error when I added another user to the account:
PHP Notice: Trying to get property of non-object.
The error points to
$this->setState('account',array('id'=>$user->account->id,'name'=>$user->account->name,));
When broken up into multiple lines:
'id'=>$user->account->id, is where the error lies.
To fix this, I simply changed it to this:
$account=Account::model()->findByPk($user->account_id);
$this->setState('account',array('id'=>$account->id,'name'=>$account->name,));
So the relationship worked just fine when I had a single user, but when I had 2 users, the relationship fails. I can continue using Yii as above, but I did like the simplicity of accessing the object directly. Did I not set up the relationships correctly? Why is this not working now with 2 users in one account?
EDIT:
var_dump($user) - http://pastebin.com/TEyrFnme
Also interesting is that I can access the user from the account using: $users=$account->users; and access all the $user[0] attributes just fine. So in reverse, the relationship seems to be working, just going forward seems to have difficulty.
Don't declare a variable in your model with the same name as a relation.
public $account;
will prevent the model from looking for the account relation, as Yii will first look for (and use) actual attributes before checking for relations of the same name.
Related
I am trying to query a different table inside my SRC/Model/Table/InspectorsTable.php file within the buildRules() function.
Background info:
Currently, my system uses a User table to store login information. HERE is the model.
This Users table has 3 different profile tables associated with it. Inspectors, Contractors, and Employees.
As of now, an Inspector, Contractor, and Employee record can use the same User foreign key to login.
I am trying to make it so that a single User record, can only use a single record from either Inspector OR Contractor OR Employee to login.
E.g. 1 User Record for 1 Employee Record/Inspector Record/Contractor Record.
I was thinking to do that, I could use the buildRules() function to check the other tables to see if the primary key of Users table is already being used by another table on the creation of an Inspector, Contractor, or Employee. If it is, it will not create the record.
My Attempt:
To try and implement the above logic, I have tried to query one of my other tables (as seen below). However, this is not working.
Here is the SRC/Model/Table/InspectorTables.php:
class InspectorsTable extends Table
{
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('inspectors');
$this->setDisplayField('id');
$this->setPrimaryKey('id');
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER',
]);
}
public function buildRules(RulesChecker $rules): RulesChecker
{
$rules->add($rules->existsIn(['user_id'], 'Users'), ['errorField' => 'user_id']);
// this line does not work
print_r($this->Contractor->get(10000000));
return $rules;
}
}
However, I am getting this error when I try to do this:
Undefined property Contractor. You have not defined the Contractor
association on App\Model\Table\InspectorsTable
I believe this is occurring because of the association's setup in the initialize() function of the InspectorsTable.php
Any help/alternative solutions would be great! Thank you!
There is no association between Inspectors and Contractors, hence there's no magic association property that you could access on your InspectorsTable class.
To access "unrelated" tables, use the table locator, for example via the LocatorAwareTrait:
class InspectorsTable extends Table
{
use Cake\ORM\Locator\LocatorAwareTrait;
// ...
public function buildRules(RulesChecker $rules): RulesChecker
{
// ...
$contractorsTable = $this->getTableLocator()->get('Contractors');
return $rules;
}
}
Not sure if your schema is the best solution for your problem domain, so I'm not really going to comment on that, just a note that it looks somewhat unoptimized with all that duplicate fields.
Here is model structure of my Laravel 5.3 project,
User.php (Model)
it has one invitation method that returns the invitation of a user.
public function invitations()
{
return $this->hasMany( 'App\Invitation', 'invitee_id', 'id' );
}
Invitation.php (Model)
This model has another method that would return the inviter detail of an invitation.
public function inviter()
{
return $this->hasOne( 'App\User', 'id', 'invited_by' );
}
If i want to retrieve all invitations of current user it works,
\Auth::user()->invitations;
But if i try to get the information about the inviter it won't work! (Question: How to do it?)
\Auth::user()->invitations->inviter;
Though i can query the inviter from a invitation eloquent object like this,
\App\Invitation::first()->inviter;
But this is not working when i try to access it from the user model -> invitation -> inviter!
Also can i use eager loading here?
\Auth::user()->invitations->inviter;
Looking at this, it appears that you're attempting to retrieve the inviter property from a collection of invitations. The reason Ken's suggestion to use \App\Invitation::first()->inviter; worked is because you are retrieving the inviter of only one invitation (in this instance, the first). To resolve this, loop through your invites before attempting to retrieve the properties for each one:
$invitations = \Auth::user()->invitations;
foreach ($invitations as $invitation) {
$inviter = $invitation->inviter;
}
There is also an each() method specific to Laravel Collections that will allow you to loop through your object.
I've used Eloquent hasOne to create a relationship between the user and the users_permissions table when the user register's to the website and group the user according to the input they put on the form and it worked fine, but the same method I think it does not recognize when the same user is signed in the website.
The below code work's when the user sign-up to the website
$user->permissions()->create(UserPermission::user_group($nature_of_entity));
But when I want to use the below method it, I get an error Trying to get property of non-object.
public function hasPermission($permission) {
return (bool) $this->permissions->$permission;
}
public function permissions() {
return $this->hasOne('App\User\UserPermission', 'user_id');
}
In the user database a table named users_permissions that has (id, user_id, is_group_one, is_group_two, is_group_three)
I'm trying to see it the user is in which group, like:
if($app->user->hasPermission('is_group_one')){
echo 'Group One';
}
But I get an error Trying to get property of non-object.
I'd really appreciate it if any can help and if they are ways I could do this and use Laravel Eloquent Relationships methods. I hope you can understand what I mean.
Create a scope that queries through the permissions relationship and checks if the column (i.e. $permission) is TRUE. Axe the (bool) bit...
public function scopeHasPermission($query, $permission)
{
return $query->permissions->where($permission, true);
}
Then in your controller, keep this the same as you had it:
if($app->user->hasPermission('is_group_one')) {
...
}
What would be the best way to create a relationship if it doesn’t exist already, within Eloquent, or at least a central location.
This is my dilemma. A User must have a Customer model relationship. If for whatever reason that customer record doesn’t exist (some bug that stopped it from being created) - I don’t want it to throw errors when I try to retrieve it, but I also request the customer object in multiple locations so I don’t want to test for existence in all those places.
I thought of trying the following in the User model:
public function getCustomerAttribute($value) {
// check $value and create if null
}
But that doesn’t work on relationships, $value is null.
EDIT
I already create a customer upon user creation, but I have come across a situation where it wasn't created and caused exceptions in many places, so I want to fallback.
User::created(function($user) {
$customer = Customer::create([
'user_id' => $user->id
]);
});
Is it possible for you to assume when a user is created that a customer needs to be created as well? If the rest of your system depends on this assumption I would make a model event.
use App\{User, Customer}; // assuming php7.0
UserServiceProvider extends ServiceProvider
{
/**
* Boot
*/
public function boot()
{
// on a side note, we're using "created" not "creating" because the $user->id needs to exist in order to save the relationship.
User::created(function($user) {
$customer = Customer::create([
'user_id' => $user->id
]);
});
}
}
Working with Yii framework I've got a question which I can not solve on my own.
How can I nicely check access to certain attributes of a model?
Context:
I use RBAC, a user may have multiple roles at the same time
I have a model with a bunch of attributes (for example, let's call it Profile)
Some attributes are allowed to be edited by any registered user (email, age, favorite color, etc.), and some - only by the users with some specific role (is_banned - can be changed by moderator or administrator, balance - can be changed only by administrators, etc.)
What I've done already:
At the moment I see only one possible way to accomplish this task:
function actionUpdate($id)
{
$model = Profile::model()->findByPk($id);
if (!$this->user->checkAccess('editProfile')) {
throw new AccessDeniedException();
}
if (isset($_POST['is_banned'])) {
if (!$this->user->checkAccess('toggleBan')) {
unset($_POST['is_banned']);
}
}
if (isset($_POST['balance'])) {
if (!$this->user->checkAccess('changeBalance')) {
unset($_POST['balance']);
}
}
$model->setAttributes($_POST);
$model->save();
}
Are there some better ways to solve such task? Thanks.
Consider using model scenarios (http://www.yiiframework.com/wiki/266/understanding-scenarios/):
Add scenario condition to your model rules:
public function rules()
{
return array(
array('balance', 'integer', 'on' => 'admin'),
);
}
Set model scenario in controller:
if ($this->user->checkAccess('admin')) {
$model->scenario = 'admin';
}
Now attributes that available by scenario are saved only.
Consider also using scenarios in search models.