I am working on a Laravel project. I am using Scout based on Algolia. But I struggling to apply whereIn on the relationships. I have 2 models as follow.
Place.php
class Place extends Model
{
use Searchable, Localizable;
protected $with = [
'images',
'phones',
'emails',
'categories'
];
protected $casts = [
'is_featured' => 'boolean'
];
public function categories()
{
return $this->belongsToMany(Category::class, 'place_category');
}
public function searchableAs()
{
return "places_index";
}
public function toSearchableArray()
{
$record = $this->toArray();
$record['_geoloc'] = [
'lat' => $record['latitude'],
'lng' => $record['longitude'],
];
$record['categories'] = $this->categories->map(function ($data) {
return [
'id' => $data['id'],
'en_name' => $data['en_name'],
'mm_name' => $data['mm_name'],
];
})->toArray();
unset($record['created_at'], $record['updated_at'], $record['latitude'], $record['longitude']);
unset($record['images'], $record['phones'], $record['emails']);
return $record;
}
}
Category.php
class Category extends Model
{
use Searchable;
protected $touches = [
'places',
];
public function places()
{
return $this->belongsToMany(Place::class, 'place_category');
}
}
Now, I am searching the Place models/ data filtering by category. As you can see, I have also indexed the categories with places in toSearchableArray method.
I am trying to achieve something like this.
Place::search($keyword)->whereIn('categories', ????);//how can I filter by the Ids here
How can I do that?
Related
I'm having trouble translating a pivot column.
I've been trying all day to add this translation but it still doesn't work.
I'm using the package: https://github.com/Astrotomic/laravel-translatable
Plain tables work fine, but pivot doesn't.
My code (the naming was quick, as the code will work, I'm going to refactor it):
class Offer extends Model implements TranslatableContract
use HasFactory, Translatable;
public array $translatedAttributes = [
'name',
'description'
];
public function attributes(): BelongsToMany
{
return $this->belongsToMany(Attribute::class, 'attribute_offer')->using(AttributeOffer::class)->withTimestamps();
}
class Attribute extends Model implements TranslatableContract
{
use HasFactory, Translatable;
public array $translatedAttributes = [
'name',
];
public function values(): BelongsToMany
{
return $this->belongsToMany(Offer::class, 'attribute_offer', 'attribute_id', 'offer_id')->using(AttributeOffer::class);
}
class AttributeOffer extends Pivot implements TranslatableContract
{
use Translatable;
public $incrementing = true;
public array $translatedAttributes = [
'content',
];
protected $fillable = [
'attribute_id',
'offer_id',
];
}
class AttributeOfferTranslation extends Model
{
protected $table = 'attribute_offer_translations';
public $timestamps = false;
protected $fillable = [
'content',
];
}
class OfferController extends Controller
{
private function updateAttributeValues($offer, $attributes)
{
foreach ($attributes as $slug => $values) {
$pivot = $offer->attributes()->whereSlug($slug)->first()->pivot;
foreach ($values as $locale => $value) {
$pivot->translate($locale)->content = $value;
}
}
}
The structure of the attributes is:
[
'test' =>[
'en' => 'test',
'es' => 'test',
'de' => 'test',
],
'test2' =>[
'en'=> 'test',
'es'=> 'test',
'de' => 'test',
],
]
Unfortunately pivot->translate() always returns null.
Also, when I manually add transactions to the database, it does not display it.
I will be very grateful for help with this translation.
Okay, I fixed it like this, only I have to pass id instead of slugs.
class Offer extends Model implements TranslatableContract
{
...
public function attributeValues(): HasMany
{
return $this->hasMany(AttributeOffer::class);
}
}
class AttributeOffer extends Pivot implements TranslatableContract
{
...
protected $translationForeignKey = 'attribute_offer_id';
...
}
private function updateAttributeValues($offer, $attributes)
{
foreach ($attributes as $id => $values) {
$offer->attributeValues()->whereAttributeId($id)->first()->update($values);
}
}
good afternoon!
I would like some help from them regarding the scenario below:
I have 3 tables, 1 is the Moviment which is the main one, the 2 is the cart_moviments which is the secondary one which when I enter the movement data, it saves some data in cart_moviments and I have the 3 table called vehicles, which I have all the vehicle information, all of them have a foreignId, just to relate them.
So on my return from the resource, I have Moviment->cartMoviment, and I want to access it from cartMoviment ->vehicles, which I can't, because it doesn't relate.
My code Store:
public function store(StoreMovimentRequest $request, StoreCartMovimentRequest $requestCart, StoreDocumentRequest $requestDocument)
{
$this->authorize('create', Moviment::class);
$moviment = Moviment::create($request->validated());
$moviment->cartMoviment()->create($request->validated());
foreach(array($request['key_number']) as $notasFiscais) {
foreach($notasFiscais as $notas) {
$moviment->document()->create($notas);
}
}
return new MovimentResource($moviment);
}
My CartMoviment MOdel:
class CartMoviment extends Model
{
use HasApiTokens, HasFactory, Notifiable, UserTenant;
protected $fillable = ['type', 'vehicle_cart_id'];
// protected $table = 'cart_moviments';
public function Moviment() {
return $this->belongsTo(Moviment::class);
}
public function Vehicle() {
return $this->belongsTo(Vehicle::class, 'vehicle_cart_id');
}
My Moviment Model:
class Moviment extends Model
{
use HasApiTokens, HasFactory, Notifiable, UserTenant;
protected $fillable = [
'document_type_id', 'people_id', 'company_id', 'vehicle_id', 'department_id'
];
public function Vehicle() {
return $this->belongsTo(Vehicle::class);
}
public function cartMoviment() {
return $this->belongsToMany(Moviment::class, cartMoviment::class);
}
`
My resource Array:
public function toArray($request)
{
return [
'id' => $this->id,
// 'count' => $this->count(),
'type' => $this->type,
'department_id' => $this->department_id,
'person_id' => $this->people_id,
'person_name' => $this->person->name,
'vehicle_id' => $this->vehicle_id,
'vehicle_board' => $this->vehicle->board,
'vehicle_status' => $this->vehicle->status,
'vehicle_manufacturer' => $this->vehicle->vehicleModel->name,
'vehicle_type' => $this->vehicle->vehicleType->type,
'cart_moviment' => $this->cartMoviment,
My return resource
"cart_moviment": [
],
"documents": [
],
`
I need relationship , thanks you very match.
in this query i have three table such as radio, radio_channels and radio_channels_files which into that i want to calculate one column which that is into radio_channels_files table as new column such as duration_sum, my below code work but i can't calculate this column
class Radio extends Model
{
use SoftDeletes;
protected $guarded = ['id'];
protected $casts = [
'logo_path' => 'array',
'cover_path' => 'array'
];
public function category()
{
return $this->belongsTo(RadioCategory::class);
}
public function channels()
{
return $this->hasMany(RadioChannels::class);
}
}
class RadioChannelsFiles extends Model
{
protected $guarded = ['id'];
protected $casts = [
'image' => 'array',
//'keywords' => 'array',
];
public function channel()
{
return $this->belongsTo(RadioChannels::class,'playlist_id');
}
}
class RadioChannels extends Model
{
protected $guarded = ['id'];
protected $casts = [
'image' => 'array'
];
public function channel()
{
return $this->belongsTo(Radio::class);
}
public function files()
{
return $this->hasMany(RadioChannelsFiles::class , 'playlist_id');
}
public function duration_sum()
{
return $this->hasOne(RadioChannelsFiles::class ,'playlist_id')
->select('duration',
DB::raw('sum(duration)')
)->groupBy('duration');
}
}
$channels = Radio::with(['category', 'channels' => function ($query) {
$query->with(['files','duration_sum']);
}])->paginate(50);
i get null output:
#relations: array:2 [▼
"files" => Illuminate\Database\Eloquent\Collection {#1422 ▶}
"duration_sum" => null //should return sum of duration from files
]
i figured out how can i get it
public function getRadiosList(Request $request)
{
$radios = Radio::with(['category', 'playLists' => function ($query) {
$query->with(['files','duration_sum']);
}])->get();
return response()->json(['data' => $radios, 'statusCode' => 1], 200);
}
model:
public function duration_sum()
{
return $this->hasOne(RadioPlaylistsFiles::class, 'playlist_id')
->select('playlist_id',
DB::raw('sum(duration) as `all_duration`')
)->groupBy('playlist_id');
}
I'm having problems returning the data for two relationships when using paginate.
$things = $this->model->with('fruits')->with('animals')->paginate(5, ['id, 'name']);
Returns the "things" I want but the "fruits" and "animals" arrays are empty.
To clarify, the relationships check out, things "has Many" fruits and also "has many through (fruits)" animals.
public function fruits()
{
return $this->hasMany('App\Fruit');
}
public function animals()
{
return $this->hasManyThrough('\App\Animal', '\App\Fruit');
}
I would like to be able to load "things" along with any relationships while being able to paginate the "things"
with() only tells Eloquent to pre-fetch the related models, so you can avoid the N+1 query problem. It does not mean that when you return the model, that information is also returned.
I would create an Eloquent Resource:
Class FruitResource extends \Illuminate\Http\Resources\Json\Resource {
public function toArray($request) {
return [
'id' => $this->id,
'name' => $this->name
];
}
}
Class AnimalResource extends \Illuminate\Http\Resources\Json\Resource {
public function toArray($request) {
return [
'id' => $this->id,
'name' => $this->name
];
}
}
Class ThingResource extends \Illuminate\Http\Resources\Json\Resource {
public function toArray($request) {
return [
'id' => $this->id,
'fruits' => FruitResource::collection($this->fruits),
'animals' => AnimalResource::collection($this->animals)
];
}
}
Once you created these resource, you can alter your controller to do the following:
$things = $this->model->with('fruits')->with('animals')->paginate(5, ['id, 'name']);
return ThingsResource::make($things);
By structuring your resources, you can easily get more control on what you return. Make life a lot nicer...
I try to include a relationship in my resource array if it has been eager loaded, but don't get it working.
Anyone has an idea, how I can check the relationships in the ResourceCollection?
Database schema looks like this:
Here is my Post Model
class Post extends Model
{
function categories() {
return $this->belongsToMany('App\Category');
}
}
Here is my Category Model
class Category extends Model
{
function posts() {
return $this->belongsToMany('App\Post');
}
}
Here is my Post Controller
Class PostController extends Controller
{
public function index()
{
return new PostResourceCollection(Post::with("categories")->get());
}
}
Here is my Post ResourceCollection
class PostResourceCollection extends ResourceCollection
{
public function toArray($request)
{
return [
'data' => $this->collection->transform(function($page){
return [
'type' => 'posts',
'id' => $page->id,
'attributes' => [
'name' => $page->title,
],
];
}),
//'includes' => ($this->whenLoaded('categories')) ? 'true' : 'false',
//'includes' => ($this->relationLoaded('categories')) ? 'true' : 'false',
];
}
}
Maybe too late, below solution is a workaround for this case:
return [
...,
'includes' => $this->whenLoaded('categories', true),
];
Loading custom attribute:
return [
...,
'includes' => $this->whenLoaded('categories', fn() => $this->categories->name),
];
You relationship is wrong, a post belongs to many categories while a category has many posts so change:
class Category extends Model
{
function posts() {
return $this->belongsToMany('App\Post', 'category_post');
}
}
to
class Category extends Model
{
function posts() {
return $this->hasMany('App\Post', 'category_post');
}
}
Now when you load the post you can load the categories also:
$posts = Post::with('categories')->get();
got it.. That was the missing piece. if anyone has a better solution for this it would be much appreciated.
foreach ($this->collection as $item) {
if ($item->relationLoaded('categories')) {
$included = true;
}