I'm looking to use elastic search on a project with model relation.
For now elastic search is working, I've followed this doc who explain how to start with this package :
elasticsearch/elasticsearch
babenkoivan/elastic-migrations
babenkoivan/elastic-adapter
babenkoivan/elastic-scout-driver
The problem is I need to able to search by relation.
this is my composant elastic migration :
Index::create('composant', function(Mapping $mapping, Settings $settings){
$mapping->text('reference');
$mapping->keyword('designation');
$mapping->join('categorie');
$settings->analysis([
'analyzer' => [
'reference' => [
'type' => 'custom',
'tokenizer' => 'whitespace'
],
'designation' => [
'type' => 'custom',
'tokenizer' => 'whitespace'
]
]
]);
});
Here my categorie elastic migration :
Index::create('categorie', function(Mapping $mapping, Settings $settings){
$mapping->keyword('nom');
$settings->analysis([
'analyzer' => [
'nom' => [
'type' => 'custom',
'tokenizer' => 'whitespace'
]
]
]);
});
My composant Model :
public function categorie()
{
return $this->belongsTo('App\Model\Categorie');
}
public function toSearchableArray()
{
return [
'reference' => $this->reference,
'designation' => $this->designation,
'categorie' => $this->categorie(),
];
}
and my categorie Model :
public function toSearchableArray()
{
return [
'nom' => $this->nom,
];
}
So if you look at the composant relation, you can see that the join mapping return the categorie relation. I dont now if I do it right but what I know is that elasticsearch didn't have any relation in the object I'm looking for.
And I didn't find any doc of how to use the join mapping method of the package.
OK, I've found the solution, the problem was in the migration you must use object in order to index the belongsToMany relationship like that
Index::create('stages', function (Mapping $mapping, Settings $settings) {
$mapping->text('intitule_stage');
$mapping->text('objectifs');
$mapping->text('contenu');
$mapping->object('mots_cles');
});
and in your model :
public function toSearchableArray()
{
return [
'intitule_stage' => $this->intitule_stage,
'objectifs' => $this->objectifs,
'contenu' => $this->contenu,
'n_stage' => $this->n_stage,
'mots_cles' => $this->motsCles()->get(),
];
}
And the result is as expected now
If you want to get "nom" of categorie, write this in composant Model instead
'categorie' => $this->categorie->nom ?? null,
$this->categorie() return the relationship, not the object.
Same problem with a belontoMany relation, and I've made the same things in order to get the relation as a nested object, but when I try to populate my index the field "mots_cles" stay empty, I don't understand why.
Here is the migration :
Index::create('stages', function (Mapping $mapping, Settings $settings) {
$mapping->text('intitule_stage');
$mapping->text('objectifs');
$mapping->text('contenu');
$mapping->nested('motsCles', [
'properties' => [
'mot_cle' => [
'type' => 'keyword',
],
],
]);
});
The model :
public function toSearchableArray()
{
return [
'intitule_stage' => $this->intitule_stage,
'objectifs' => $this->objectifs,
'contenu' => $this->contenu,
'n_stage' => $this->n_stage,
'mots_cles' => $this->motsCles(),
];
}
public function motsCles()
{
return $this->belongsToMany(MotsCle::class);
}
I have problem to save this data using Laravel-7 model
this is my data
$supplier = [
'name' => 'Supplier 1',
'pic' => [
[
'name' => 'PIC 1',
'phone_number' => [
['number' => '111111'],
['number' => '123456']
]
],
[
'name' => 'PIC 2',
'phone_number' => [
['number' => '222222']
]
]
]
];
And this is my models
Supplier.php
// Supplier.php
public function supplier_pic()
{
return $this->hasMany('SupplierPIC');
}
and the other models
// SupplierPIC.php
public function supplier()
{
return $this->belongsTo('Supplier');
}
public function pic_phone_number()
{
return $this->hasMany('SupplierPICPhoneNumber');
}
// SupplierPICPhoneNumber.php
public function supplier_pic()
{
return $this->belongsTo('SupplierPIC');
}
How to save those data on controller ?
Thank you
You just need to break it down into it's constituent objects.
In your case, it is one Supplier object with two SupplierPIC objects, each of which has a SupplierPICPhoneNumber
Create Supplier
$supplier = Supplier::firstOrCreate([
'name' => 'Supplier 1'
]);
Create Supplier PIC(s)
collect($data['pics'])->each(function ($pic) use ($supplier) {
// Create the PIC
$x = SupplierPIC::create([
'name' => $pic['name']
]);
// Attach it to the supplier
$supplier->supplier_pic()->save($x);
// Attach phone numbers
collect($pic['phone_number'])->each(function ($number) use ($x) {
// Create the PIC Phone number
$y = SupplierPICPhoneNumber::create([
'number' => $pic['number']
]);
// Attach the number to the PIC
$x->pic_phone_number()->save($y);
});
});
Suggestions
The naming of your relationships doesn't follow best practice which is a little confusing. Try naming things that are use a hasMany type relationship with a plural (i.e. pic_phone_numbers rather than pic_phone_number)
Do you need an entire model for SupplierPICPhoneNumber? A json column may be better suited.
I need your help!
I'm having problems returning pivot table information when using ApiResources.
If I have a model like this:
Post.php
public function likes()
{
return $this->belongsToMany(Like::class)
->withPivot(['points']) // I want this in my PostResource::collection !
}
When defining its Resources:
LikeResource.php
public function toArray($request)
{
return [
'like_field' => $this->like_field
];
}
PostResource.php
public function toArray($request)
{
return [
'title' => $this->title,
'likes' => LikeResource::collection($this->whenLoaded('likes'))
];
}
Then in PostController.php
return PostResource::collection(Post::with('likes')->get())
It will return something like this:
Controller Response
[
{
'title' => 'Post 1'
'likes' => [
{
'like_field' => 'Test'
},
{
'like_field' => 'Test 2'
}
]
},
{
'title' => 'Post 2',
...
}
]
The problem is, using that LikeResource::collection() it does not appends pivot information. How could I add 'points' of the pivot table when defining that PostResource??
Thats all,
Thx!
Solution
Well, simply reading a bit in Laravel Docs, to return pivot information you just has to use the method $this->whenPivotLoaded()
So, the PostResource becomes:
public function toArray($request)
{
return [
'title' => $this->title,
'likes' => LikeResource::collection($this->whenLoaded('likes')),
'like_post' => $this->whenPivotLoaded('like_post', function() {
return $this->pivot->like_field;
})
];
}
I'm trying to save multiple records via
AppSettings::create(
[
'name' => 'mail_host',
'type' => $emailsettingstype->id,
'value' => '',
],
[
'name' => 'mail_port',
'type' => $emailsettingstype->id,
'value' => '',
],
[
'name' => 'mail_username',
'type' => $emailsettingstype->id,
'value' => '',
],
);
But from the above, only the first array is getting created. Where am i going wrong? Any help is appreciated.
I think this should do
AppSettings::createMany([
[
'name'=>'mail_host',
'type'=>$emailsettingstype->id,
'value'=>'',
],
[
'name'=>'mail_port',
'type'=>$emailsettingstype->id,
'value'=>'',
],
[
'name'=>'mail_username',
'type'=>$emailsettingstype->id,
'value'=>'',
],
]);
Make sure you're passing an array of arrays, not a params of array.
UPDATE, you can use Model::insert() although according to what I've read, that method doesn't create/update the timestamps.
You can just use Eloquent::insert() link as below:
AppSettings::insert([
[
'name'=>'mail_host',
'type'=>$emailsettingstype->id,
'value'=>'',
],
[
'name'=>'mail_port',
'type'=>$emailsettingstype->id,
'value'=>'',
],
[
'name'=>'mail_username',
'type'=>$emailsettingstype->id,
'value'=>'',
],
]);
The problem with above is that it won't update timestamps, find examples here
The Create many Method createMany is available on relationship check reference to this link and this documentation from laravel
so far my example look like this.
I have two models Pricing and AvailableService Model
Pricing Model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Pricing extends Model
{
protected $fillable = ["name", "price"];
public function available(){
return $this->hasMany(AvailableService::class, "pricing_id", "id");
}
}
And the AvailableServiceMode look like this
namespace App;
use Illuminate\Database\Eloquent\Model;
class AvailableService extends Model
{
protected $fillable = ["pricing_id", "service_id"];
public function service(){
return $this->belongsTo(Service::class, "service_id", "id");
}
}
So createMany operation look like this
$insertMany = Pricing::create(['name'=>request('name')]);
$insertMany->available()->createMany([
['service_id'=>1],
['service_id'=>2],
['service_id'=>3],
['service_id'=>4],
['service_id'=>5],
]);
And it works for, you can give it a try too. THANKS
If you want to store multiple record in seeder use this method instead of insert because in my case I want to slug automatically created using spatie/laravel-sluggable pkg. If you used the insert or DB technique then you have to give the value for slug field also.
CategorySeeder
<?php
namespace Database\Seeders;
use App\Servcategory;
use Illuminate\Database\Seeder;
class CategorySeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
$categories = [
[
'name' => 'Automotive',
// 'slug' => 'automotive',
],
[
'name' => 'Business Services',
// 'slug' => 'business-services',
],
[
'name' => 'Computer, Telecom & IT Services',
// 'slug' => 'computer-telecom-&-it-services',
],
[
'name' => 'Education & Training',
// 'slug' => 'education-&-training',
],
[
'name' => 'Finance',
// 'slug' => 'finance',
],
[
'name' => 'Hospitals, Clinic, Medical',
// 'slug' => 'hospitals-clinic-medical',
],
[
'name' => 'Real Estate, Construction, Property',
// 'slug' => 'real-estate-construction-property',
],
[
'name' => 'Travel,Toursim & Hotels',
// 'slug' => 'travel-toursim-&-hotels',
],
];
// Servcategory::insert($categories);
collect($categories)->each(function ($category) { Servcategory::create($category); });
}
}
In case some one searching for eloquent model, I used the following method:
foreach($arCategories as $v)
{
if($v>0){
$obj = new Self(); // this is to have new instance of own
$obj->page_id = $page_id;
$obj->category_id = $v;
$obj->save();
}
}
$obj = new Self(); is a must otherwise it only saves single record when $this is used.
in seeder create an array and do foreach with Model::create(). All your records will be with timestamps
protected $array = [
[...],
[...],
[...]
];
public function run()
{
foreach ($this->array as $value) {
Model::create($value);
}
}
I am beginner. I explain the topic:
there is this relationship in the Ticket model:
public function getTyp()
{
return $this->hasOne(Typology::className(), [ 'id' =>'typ_id']);
}
and in the ticket table there is the typ_id column (it is in relationship with the id of the Typology table).
In the view views/ticket/index.php there is GridView::widgetwith these columns:
[
'attribute' => 'typ_id',
'value' => 'typ.typology'
],
I want to anchor the value of the relationship.
I have tried this:
[
'attribute' => 'typ_id',
'value' => function ($model) {
return Html::a (
'typ.typology',
'/typology/view?id='.$model->typ_id
);
}
]
but it doesn't work
someone can help me?
Html::a() interprets typ.typology as raw string. Use $model in value closure to get necessary property through relation.
Also instead of manually concatenate the url with its parameters, just pass them in array (see Url::to() to understand how link is constructed).
[
'attribute' => 'typ_id',
'value' => function ($model) {
return Html::a($model->typ->typology, ['/typology/view', 'id' => $model->typ_id]);
},
],