I try to build a grid view with many-to-many relations. So I need a query for the ActiveDataProvider .
I have a table 'ressource', a table 'type' and between them a table 'historique'.
I have the good relation in my models but I don't know how to create the dataProvider.
In my model Ressource :
public function getHistorique()
{
return $this->hasMany(Historique::className(), ['idType' => 'idType']);
}
public function getType()
{
return $this->hasMany(Type::className(), ['idType' => 'idType'])
->viaTable(Historique::className(), ['idRessource' => 'idRessource']);
}
In my model Historique :
public function getType()
{
return $this->hasOne(Type::className(), ['idType' => 'idType']);
}
public function getRessource()
{
return $this->hasOne(Ressource::className(), ['idRessource' => 'idRessource']);
}
and finally in my model Type :
public function getHistorique()
{
return $this->hasMany(Historique::className(), ['idType' => 'idType']);
}
public function getRessource()
{
return $this->hasMany(Ressource::className(), ['idRessource' => 'idRessource'])
->viaTable(Historique::className(), ['idType' => 'idType']);
}
So in the Controller (in fact my ModelSearch), I want to have ressources with type from the table historique. I don't know what I have to add after
Ressource::find();
I think you use RessourceSearch()->search() method. So inside it you have something like this:
$query = Ressource::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
// Here is list of searchable fields of your model.
$query->andFilterWhere(['like', 'username', $this->username])
->andFilterWhere(['like', 'auth_key', $this->auth_key])
return $dataProvider;
So, basically, you need to add additional Where you your query and force to join relation table. You can do that using joinWith method to join additional relation and andFilterWhere using table.field notation for adding filter parameters. For example:
$query = Ressource::find();
$query->joinWith(['historique', 'type']);
$query->andFilterWhere(['like', 'type.type', $this->type]);
$query->andFilterWhere(['like', 'historique.historique_field', $this->historique_field]);
Also do not forget to add rules for additional filters in your search model. For example above, you should add to your rules() array something like that:
public function rules()
{
return [
// here add attributes rules from Ressource model
[['historique_field', 'type'], 'safe'],
];
}
You can use any additional validation rules for that fields
Related
Fiddling with Laravel and coming from Symfony, I'm trying to replicate some code.
I'm trying to PUT a Suggestion model (overwritting anything, even relationships) and wanted to know the proper way to overwrite the model.
Since tags attribute in fillable doesn't exist, I certainly get an error (Undefined column: 7 ERROR: column "tags" of relation "suggestions" does not exist).
Suggestions and tags both have their own tables and a pivot table that contains two foreign keys to both tables id.
Request & Response :
{
"id":2,
"content":"Magni.",
"tags":[{"id":13,"name":"MediumAquaMarine"}]
}
{
"id":2,
"content":"Magni.",
"tags":[{"id":10,"name":"Navy"},{"id":13,"name":"MediumAquaMarine"}]
}
public function update(Request $request, Suggestion $suggestion)
{
$validator = Validator::make($request->all(), [
'content' => 'required',
'tags.id' => 'numeric',
]);
if ($validator->fails()) {
return response()->json($validator->messages(), Response::HTTP_BAD_REQUEST);
}
$suggestion->fill($request->only($suggestion->getFillable()))->save();
return new SuggestionResource($suggestion);
}
class Suggestion extends Model
{
use HasFactory;
protected $fillable = ['content', 'tags'];
protected $with = ['tags'];
public function tags()
{
return $this->belongsToMany(Tag::class, 'suggestions_tags')->withTimestamps();
}
}
class Tag extends Model
{
use HasFactory;
protected $hidden = ['pivot'];
public function suggestions()
{
return $this->belongsToMany(Suggestion::class, 'suggestions_tags')->withTimestamps();
}
}
You could just pass an array of IDs for tags instead of the whole object.
Do:
"tags":[10, 13]
Instead of:
"tags":[{"id":10,"name":"Navy"},{"id":13,"name":"MediumAquaMarine"}]
Change the validation rules accordingly and then you can remove tags from $fillable and do something like:
$suggestion->update($request->validated());
$suggestion->tags()->sync($request->tags);
Hi i have REGION model but i dont know how rewrite this DB::select. I want it with findOrFail or something for ,,If i find this slug i show page if no i show 404
My web.php route
Route::get('/turnaje/{slug}', [RegionController::class, 'show']);
My Region Controller
public function show($slug)
{
$regions = DB::select('select * from regions where slug = ?', [$slug]);
$regions_list = DB::select('select * from regions');
return view('tournaments.show', [
'regions' => $regions,
'regions_list' => $regions_list,
]);
}
So you can use the model as a facade and write a similar query. I'm assuming you want an exception thrown when there is no region with that slug?
https://laravel.com/docs/8.x/eloquent#not-found-exceptions
public function show($slug)
{
$regions = Region::where('slug', $slug)->firstOrFail();
$regions_list = Region::all();
return view('tournaments.show', [
'regions' => $regions,
'regions_list' => $regions_list,
]);
}
You may want to handle the ModelNotFoundException
You have 2 options:
Changing route model binding form id to slug by defining getRouteKeyName function in your model:
public function getRouteKeyName()
{
return 'slug';
}
Using firstOrFail:
Region::where('slug', $slug)->firstOrFail();
I have a yii2 form which contain a checkbox list items which i made like this:
<?php $CheckList = ["users" => 'Users', "attendance" => 'Attendance', "leave" => 'Leave', "payroll" => 'Payroll'];?>
<?= $form->field($model, 'MenuID')->checkboxList($CheckList,['separator'=>'<br/>']) ?>
Now what i need is to save the values in the database column as a comma separated value.
I tried to modify the create function in my controller in this way:
public function actionCreate()
{
$model = new Role();
if ($model->load(Yii::$app->request->post())) {
if ($model->MenuID != " ") {
$model->MenuID = implode(",", $model->MenuID);
}
$model->save();
return $this->redirect(['view', 'id' => $model->RoleID]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
But the values are not being saved in the database
You need to set your model rules().
When you call $model->load(Yii::$app->request->post()); the framework call method setAttributes() with param $safeOnly = true. This method with param $safe = true check if attributes are safe or not according to the rules of model. If you haven't any rules on the model all attributes are considered unsafe so your model is not populated.
Add rules() on your model and your code works
class Role extends yii\db\ActiveRecord
{
...
public function rules()
{
return [
['MenuID', 'your-validation-rule'],
];
}
...
Some additional info
N.B. If you do not specify scenario in the rules the default scenario is 'default' and if during instantiate of model object you set scenario to another didn't work. My example:
You have the same rules as I wrote before and you run this code
...
$model = new Role(['scenario' => 'insert']);
if ($model->load(Yii::$app->request->post())) {
...
model is empty after load becouse any rules is founded in 'insert' scenario and your problem is back. So if you want a rule that work only in particular scenario you must add 'on' rules definition. Like this:
...
public function rules()
{
return [
['MenuID', 'your-validation-rule', 'on' => 'insert'],
];
}
...
For more example and explanations visit:
Declaring Rules
load()
setAttributes()
safeAttributes()
I have question about Laravel Eloquent. I created few tables and models, ~like this:
Trip
id
name
user
User
id
email
Message
id
content
trip
user
How can I get all message for single user with all foreign keys? You know, all data from this tables. Like this:
[
1 => [
'content',
'trip' => [
'name'
],
'user' => [
'email'
]
]
]
It's possible, to get in easy way all data?
My models:
// Message.php:
public function user()
{
return $this->belongsTo('App\User');
}
public function trip()
{
return $this->belongsTo('App\Trip');
}
// Trip.php:
public function user()
{
return $this->belongsTo('App\User');
}
// User.php:
public function trips()
{
return $this->hasMany('App\Trip');
}
public function messages()
{
return $this->hasMany('App\Message');
}
My Code
dd(
User::with([
'sent',
'recipient'
])->find(2)->toArray()
);
And what I want to get:
screen
I believe you are looking for the load method.
Lets say you have a user
$user->load('messages'); // var_dump($user);
If you vardump your user object you will see the related messages were loaded.
Use eager loading to achieve that.
Try this:
$users = User::with([
'messages.trip',
])->get();
dd($users);
Ref: https://laravel.com/docs/5.3/eloquent-relationships#eager-loading
I added
$query->joinWith('projectParticipants');
in search model but got this error:
relation is correct and returns data if I var_dump in view.
Tried as well
->leftJoin('project_participants', 'project_participants.user_id = user_cards.id')
but the same error. :(
With different relations the same problem and in Yii Debugger all queries are correct.
Where I could go wrong?
What is this empty property?
In model relation looks:
public function getProjectParticipants()
{
return $this->hasMany(ProjectParticipants::className(), ['user_id' => 'id']);
}
UPDATED
public function search($params)
{
$query = UserCards::find();
$query->joinWith('projectParticipants');
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => array('pageSize' => 45),
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
$query->andFilterWhere([
'project_participants.proj_id' => $this->projects,
]);
$query->andFilterWhere(['ilike', 'name', $this->fullName ])->orFilterWhere(['like', 'surname', $this->fullName ]);
return $dataProvider;
}
The issue was with primary key - user_cards model was generated from db view where is no pk.
So the solution was to add
public static function primaryKey(){
return array('id');
}
in model.