Yii2 relations with junction table - yii2

I have free tables: user, book, user_book, offers
user table has method:
public function getBooks()
{
return $this->hasMany(UserBook::className(), ['user_id' => 'id']);
}
user_book table has two fields: user_id, book_id; and methods
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'user_id']);
}
public function getBook()
{
return $this->hasOne(Book::className(), ['id' => 'book_id']);
}
table offer have method like: getUser(), getBook(),
and now I would like show Books which user don't have. I try do something like
$query = Offer::find()
->with('user')
->andWhere([
'offer.status' => Offer::STATUS_ACTIVE,
]);
$query->andWhere(['not in', 'offer.book_id', 'user.books.book_id']);
but it doesn't work. Do you have some ideas how can I make it?

Yii2 docs, relation via junction table
In database modelling, when the multiplicity between two related
tables is many-to-many, a junction table is usually introduced. For
example, the order table and the item table may be related via a
junction table named order_item. One order will then correspond to
multiple order items, while one product item will also correspond to
multiple order items.
When declaring such relations, you would call either via() or
viaTable() to specify the junction table. The difference between via()
and viaTable() is that the former specifies the junction table in
terms of an existing relation name while the latter directly uses the
junction table. For example,
class Order extends ActiveRecord
{
public function getItems()
{
return $this->hasMany(Item::className(), ['id' => 'item_id'])
->viaTable('order_item', ['order_id' => 'id']);
}
}
or alternatively,
class Order extends ActiveRecord
{
public function getOrderItems()
{
return $this->hasMany(OrderItem::className(), ['order_id' => 'id']);
}
public function getItems()
{
return $this->hasMany(Item::className(), ['id' => 'item_id'])
->via('orderItems');
}
}

Related

Storing password in Users table or Employees/Admin table

Let's say I have tables:
employees
administrators
(maybe) users
Employees and Administrators have different columns (e.g. Department, Salary column only in Employees).
Where should I store the password? I'm using Laravel, so the Users table is already created when I initialized the project. I'm torn between storing the password in both the Employees and Administrators, or only in the Users table, but I have no idea how I should implement the relationships of the tables if I were to add the users table.
I would probably keep the authentication associated with the users table, as per the default for laravel.
Here is an example of adding those relationships you would need.
// User model
public function employee()
{
return $this->hasOne(Employee::class, 'user_id', 'id');
}
public function administrator()
{
return $this->hasOne(Employee::class, 'user_id', 'id');
}
// Employee model
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
// Administrator model
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}

many-to-many relationship: order by on pivot table not working

I have these relationship between school and associate models:
// School model
public function associates()
{
return $this->belongsToMany('Associate', 'school_associate', 'school_id', 'associate_id')
->withPivot('start_date', 'end_date');
}
// Associate model
public function schools()
{
return $this->belongsToMany('School', 'school_associate', 'associate_id', 'school_id')
->withPivot('start_date', 'end_date');
}
I need to get all associates of one school ordered by start_date.
This is what I tried without success (in this try I am searching in all schools):
dd(\App\Associate::with(['schools' => function ($q) {
$q->orderBy('pivot_start_date', 'desc');
}])->toSql());
And I get this sql (notice no order by clause):
select * from `associate`
I tried to edit the relationship like this:
// Associate model
public function schools()
{
return $this->belongsToMany('School', 'school_associate', 'associate_id', 'school_id')
->withPivot('start_date', 'end_date')
->orderBy('pivot_start_date', 'desc'); // also tried without "pivot_"
}
And according to this post, I also tried :
// Associate model
public function schools()
{
return $this->belongsToMany('School', 'school_associate', 'associate_id', 'school_id')
->withPivot('start_date', 'end_date')
->orderBy('school_associate.start_date', 'desc');
}
But I always get the same query and the results are not ordered.
I solved using query builder in this way.
This function is in Associate model:
public function scopeLast($query, $school_ids = [])
{
$query->join('school_associate', "{$this->table}.{$this->primaryKey}", '=', 'school_associate.associate_id')
->join('school', 'school.school_id', '=', 'school_associate.school_id')
->whereIn('school.school_id', $school_ids)
->orderBy('school_associate.start_date', 'desc');
return $query;
}

Select records that haven't specific value as a child

I want to get users filtered by category, so I send category_id as a parameter and should select users who haven't records in users_categories_restrictions table with this category_id.
How can I make this eloquent query ??
You could use whereDoesntHave
$users = App\User::whereDoesntHave('categories', function ($query) use($cat_id) {
$query->where('categories.id', '=', $cat_id);
})->get();
I assume you have defined many to many relation between user and category model
class User extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class, 'users_categories_restrictions', 'user_id');
}
}
class Category extends Model
{
public function users()
{
return $this->belongsToMany(User::class, 'users_categories_restrictions', 'category_id');
}
}

Yii2 How to create a globally accessible variable that converts user's id to employee's id

I have two tables that are related directly in a one-to-one relationship. One is the standard Yii2 user table (abbreviated field list here for clarity) and the other is the employee table that contains user_id. How can I create a globally accessible variable (and the actual code to access the employee id) that I can use anywhere in my application that will give me the logged in user's employee id and how would I call that variable? I wish I could say that I've tried a few things, but unfortunately I am relatively new to Yii2 and have no idea where to start with global variables like this. Thanks for any help.
user table:
id
username
password
etc
employee table:
id
user_id (related in a one-to-one relationship to the user table)
The Employee Model:
<?php
namespace frontend\models\base;
use Yii;
/**
* This is the base model class for table "employee".
*
* #property integer $id
* #property integer $user_id
*
* #property \common\models\User $user
*/
class Employee extends \yii\db\ActiveRecord
{
public function rules()
{
return [
[['user_id', 'required'],
[['user_id'], 'integer'],
[['user_id'], 'unique']
];
}
public static function tableName()
{
return 'employee';
}
public function attributeLabels()
{
return [
'id' => Yii::t('app', 'ID'),
'user_id' => Yii::t('app', 'User ID'),
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getUser()
{
return $this->hasOne(\common\models\User::className(), ['id' => 'user_id']);
}
}
A very simple way is the use of $param array
You can initially config the default value in
your_App\config\param.php
and accessing using
\Yii::$app->params['your_param_key']
Looking to your Employee model (for me ) you don't need a global var you could simply use the getUser
$myUser = Employee::user();
but you need the param you can assign using
\Yii::$app->params['my_user'] = Employee::user();
or in user
\Yii::$app->params['my_user'] = Yii::$app->user->id
or for retrive the model related to actual user from table
$myEmpModel = Employee::find()->where['user_id' => Yii::$app->user->id]->one();
I believe proper way is to use relations in your User model. First method is proper relation with activerecord, second one will get id using relation defined above it. so You will add these methods in your User model:
/**
* #return \yii\db\ActiveQuery
*/
public function getEmployee()
{
return $this->hasOne(Employee::className(), ['user_id' => 'id']);
}
public function getEmployeeId()
{
return $this->employee ? $this->employee->id : NULL; // set to NULL or anything you expect to be if record is not found
}
Then you can call it like this from everywhere in your app:
$employee_id = Yii::$app->user->identity->employeeid;
This will only work for User model because it implements Identity, otherwise you would need to instantiate model class first, lets say like this:
$user_id = 5; // 5 is id of user record in DB
$user = User::findOne($user_id);
$employee_id = $user->employeeid;
// or using first of 2 relations ...
$employee_id = $user->employee->id;

action Update() in Yii to update another model's update

I have the database like this
=== Invoice ===
id
customer_id (FK)
description
=== Customer ===
id
firstname
lastname
I have multimodel for both the form so that Cstomer table will be load in Invoice. So that I can easily access the two models from a single view. For that I have made relation in both models just like this
In Invoice model the realtion is like this
public function relations()
{
return array(
'customer' => array(self::BELONGS_TO,'Customer','customer_id'),
);
}
In Customer Model the relation is like this
public function relations()
{
return array(
'invoice' => array(self::HAS_MANY, 'Invoices','customer_id')
);
}
Everything is working fine.But when I am going for actionUpdate() in Invoice controller file there is Customer model is not defined. So I made it define like this
public function actionView($id)
{
$this->render('view',array(
'model'=>$this->loadModel($id),
'customers'=>Customers::model()->findByPk(array('customer_id'=>$_GET['id']));
));
}
It is showing as Undefined offset: 0. I want here in ('customer_id'=>$_GET['id']) the value of id so that I can easily show and update the values for each ids.
If I am giving the value like this
public function actionView($id)
{
$this->render('view',array(
'model'=>$this->loadModel($id),
'customers'=>Customers::model()->findByPk(28);
));
}
It is easily showing the value from Customer id. So how to get those values?Any help and suggestions will be highly appriciable.
Try this
public function actionView($id)
{
$model = $this->loadModel($id);
$this->render('view',array(
'model'=>$model,
'customers'=>Customers::model()->findByPk($model->customer_id);
));
}