Home > Net >  Joins with Laravel Eloquent
Joins with Laravel Eloquent

Time:02-16

I'm learning a bit of Laravel coming over from Symfony, and i'm a little confused with how joins work with eloquent. so that i have have the returned object as my model class rather than a stdClass.

Currently i am doing this:

$query = DB::table('caravan')
            ->join('type','caravan.type_id', '=', 'type.id')
            ->join('category','caravan.category_id', '=', 'category.id')
            ->where('type.name','=', 'New')
            ->where('category.name', '=', ucwords(strtolower($category)))
            ->orderBy($orderBy,$order);

This works, it brings through all the correct records with the joined columns, but i don't want it to be a stdClass.

My caravan model looks like this:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasOne;

/**
 * Class Caravan
 * @package App\Models
 * @property int $stock
 * @property int $branch_id
 * @property int $category_id
 * @property int $type_id
 * @property string $reg
 * @property string $make
 * @property string $model
 * @property string $specification
 * @property string $derivative
 * @property string $engine_size
 * @property string $engine_type
 * @property string $transmission
 * @property string $colour
 * @property int $year
 * @property int $mileage
 * @property boolean $commercial
 * @property double $sales_siv
 * @property double $retail
 * @property double $web_price
 * @property string $sub_heading;
 * @property string $advertising_notes
 * @property string $manager_comments
 * @property double $previous_price
 * @property double $guide_retail_price
 * @property boolean $available_for_sale
 * @property boolean $advertised_on_own_website
 * @property int $berths
 * @property int $axles
 * @property string $layout_type
 * @property double $width
 * @property double $length
 * @property double $height
 * @property int $kimberley_unit_id
 * @property \DateTime $kimberley_date_updated
 *
 */
class Caravan extends Model
{
    use HasFactory;

    /**
     * @var string
     */
    public $table = 'caravan';

    /**
     * @var string[]
     */
    protected $casts = [
        'kimberley_date_updated' => 'datetime:Y-m-d H:i:s',
        'created_at' => 'datetime:Y-m-d H:i:s',
        'updated_at' => 'datetime:Y-m-d H:i:s',
        'web_price' => 'decimal: 2',
        'previous_price' => 'decimal: 2'
    ];


    /**
     * @return HasOne
     */
    public function category() : HasOne
    {
        return $this->hasOne(Category::class, 'id', 'category_id');
    }

    /**
     * @return HasOne
     */
    public function type() : HasOne
    {
        die("DD");
        return $this->hasOne(Type::class, 'id', 'type_id');
    }
    
    /**
     * @return int
     */
    public function getStock(): int
    {
        return $this->stock;
    }


    /**
     * @param int $stock
     * @return $this
     */
    public function setStock(int $stock): self
    {
        $this->stock = $stock;
        return $this;
    }

    /**
     * @return int
     */
    public function getBranchId(): int
    {
        return $this->branch_id;
    }


    /**
     * @param int $branch_id
     * @return $this
     */
    public function setBranchId(int $branch_id): self
    {
        $this->branch_id = $branch_id;
        return $this;
    }

    /**
     * @param Branch $branch
     * @return $this
     */
    public function setBranch(Branch $branch) : self
    {
        $this->branch_id = $branch->id;
        return $this;
    }

    /**
     * @return int
     */
    public function getCategoryId(): int
    {
        return $this->category_id;
    }


    /**
     * @param int $category_id
     * @return $this
     */
    public function setCategoryId(int $category_id): self
    {
        $this->category_id = $category_id;
        return $this;
    }

    /**
     * @param Category $cat
     * @return $this
     */
    public function setCategory(Category $cat) : self
    {
        $this->category_id = $cat->id;
        return $this;
    }

    /**
     * @return int
     */
    public function getTypeId(): int
    {
        return $this->type_id;
    }


    /**
     * @param int $type_id
     * @return $this
     */
    public function setTypeId(int $type_id): self
    {
        $this->type_id = $type_id;
        return $this;
    }

    /**
     * @param Type $type
     * @return $this
     */
    public function setType(Type $type) : self
    {
        $this->type_id = $type->id;
        return $this;
    }

    /**
     * @return string
     */
    public function getReg(): string
    {
        return $this->reg;
    }


    /**
     * @param string $reg
     * @return $this
     */
    public function setReg(string $reg): self
    {
        $this->reg = $reg;
        return $this;
    }

    /**
     * @return string
     */
    public function getMake(): string
    {
        return $this->make;
    }


    /**
     * @param string $make
     * @return $this
     */
    public function setMake(string $make): self
    {
        $this->make = $make;
        return $this;
    }

    /**
     * @return string
     */
    public function getModel(): string
    {
        return $this->model;
    }


    /**
     * @param string $model
     * @return $this
     */
    public function setModel(string $model): self
    {
        $this->model = $model;
        return $this;
    }

    /**
     * @return string
     */
    public function getSpecification(): string
    {
        return $this->specification;
    }


    /**
     * @param string $specification
     * @return $this
     */
    public function setSpecification(string $specification): self
    {
        $this->specification = $specification;
        return $this;
    }

    /**
     * @return string
     */
    public function getDerivative(): string
    {
        return $this->derivative;
    }


    /**
     * @param string $derivative
     * @return $this
     */
    public function setDerivative(string $derivative): self
    {
        $this->derivative = $derivative;
        return $this;
    }

    /**
     * @return string
     */
    public function getEngineSize(): string
    {
        return $this->engine_size;
    }


    /**
     * @param string $engine_size
     * @return $this
     */
    public function setEngineSize(string $engine_size): self
    {
        $this->engine_size = $engine_size;
        return $this;
    }

    /**
     * @return string
     */
    public function getEngineType(): string
    {
        return $this->engine_type;
    }


    /**
     * @param string $engine_type
     * @return $this
     */
    public function setEngineType(string $engine_type): self
    {
        $this->engine_type = $engine_type;
        return $this;
    }

    /**
     * @return string
     */
    public function getTransmission(): string
    {
        return $this->transmission;
    }


    /**
     * @param string $transmission
     * @return $this
     */
    public function setTransmission(string $transmission): self
    {
        $this->transmission = $transmission;
        return $this;
    }

    /**
     * @return string
     */
    public function getColour(): string
    {
        return $this->colour;
    }


    /**
     * @param string $colour
     * @return $this
     */
    public function setColour(string $colour): self
    {
        $this->colour = $colour;
        return $this;
    }

    /**
     * @return int
     */
    public function getYear(): int
    {
        return $this->year;
    }


    /**
     * @param int $year
     * @return $this
     */
    public function setYear(int $year): self
    {
        $this->year = $year;
        return $this;
    }

    /**
     * @return int
     */
    public function getMileage(): int
    {
        return $this->mileage;
    }


    /**
     * @param int $mileage
     * @return $this
     */
    public function setMileage(int $mileage): self
    {
        $this->mileage = $mileage;
        return $this;
    }

    /**
     * @return bool
     */
    public function isCommercial(): bool
    {
        return (bool)$this->commercial;
    }


    /**
     * @param bool $commercial
     * @return $this
     */
    public function setCommercial(bool $commercial): self
    {
        $this->commercial = (int)$commercial;
        return $this;
    }

    /**
     * @return float
     */
    public function getSalesSiv(): float
    {
        return $this->sales_siv;
    }


    /**
     * @param float|int $sales_siv
     * @return $this
     */
    public function setSalesSiv(float $sales_siv = 0): self
    {
        $this->sales_siv = $sales_siv;
        return $this;
    }

    /**
     * @return float
     */
    public function getRetail(): float
    {
        return $this->retail;
    }


    /**
     * @param float|int $retail
     * @return $this
     */
    public function setRetail(float $retail = 0): self
    {
        $this->retail = $retail;
        return $this;
    }

    /**
     * @return float
     */
    public function getWebPrice(): float
    {
        return $this->web_price;
    }

    /**
     * @param float|int $web_price
     * @return $this
     */
    public function setWebPrice(float $web_price = 0): self
    {
        $this->web_price = $web_price;
        return $this;
    }

    /**
     * @return string
     */
    public function getSubHeading(): string
    {
        return $this->sub_heading;
    }


    /**
     * @param string $sub_heading
     * @return $this
     */
    public function setSubHeading(string $sub_heading): self
    {
        $this->sub_heading = $sub_heading;
        return $this;
    }

    /**
     * @return string
     */
    public function getAdvertisingNotes(): string
    {
        return $this->advertising_notes;
    }

    /**
     * @param string $advertising_notes
     * @return $this
     */
    public function setAdvertisingNotes(string $advertising_notes): self
    {
        $this->advertising_notes = $advertising_notes;
        return $this;
    }

    /**
     * @return string
     */
    public function getManagerComments(): string
    {
        return $this->manager_comments;
    }


    /**
     * @param string $managerComments
     * @return $this
     */
    public function setManagerComments(string $managerComments): self
    {
        $this->manager_comments = $managerComments;
        return $this;
    }

    /**
     * @return float
     */
    public function getPreviousPrice(): float
    {
        return $this->previous_price;
    }


    /**
     * @param float $previous_price
     * @return $this
     */
    public function setPreviousPrice(float $previous_price): self
    {
        $this->previous_price = $previous_price;
        return $this;
    }

    /**
     * @return float
     */
    public function getGuideRetailPrice(): float
    {
        return $this->guide_retail_price;
    }


    /**
     * @param float $guide_retail_price
     * @return $this
     */
    public function setGuideRetailPrice(float $guide_retail_price): self
    {
        $this->guide_retail_price = $guide_retail_price;
        return $this;
    }

    /**
     * @return bool
     */
    public function isAvailableForSale(): bool
    {
        return $this->available_for_sale;
    }


    /**
     * @param bool $available_for_sale
     * @return $this
     */
    public function setAvailableForSale(bool $available_for_sale): self
    {
        $this->available_for_sale = (int)$available_for_sale;
        return $this;
    }

    /**
     * @return bool
     */
    public function isAdvertisedOnOwnWebsite(): bool
    {
        return $this->advertised_on_own_website;
    }


    /**
     * @param bool $advertised_on_own_website
     * @return $this
     */
    public function setAdvertisedOnOwnWebsite(bool $advertised_on_own_website): self
    {
        $this->advertised_on_own_website = (int)$advertised_on_own_website;
        return $this;
    }

    /**
     * @return int
     */
    public function getBerths(): int
    {
        return $this->berths;
    }

    /**
     * @param int $berth
     */
    public function setBerths(int $berths): self
    {
        $this->berths = $berths;
        return $this;
    }

    /**
     * @return int
     */
    public function getAxles(): int
    {
        return $this->axles;
    }


    /**
     * @param int $axles
     * @return $this
     */
    public function setAxles(int $axles): self
    {
        $this->axles = $axles;
        return $this;
    }

    /**
     * @return string
     */
    public function getLayoutType(): string
    {
        return $this->layout_type;
    }

    /**
     * @param string $layout_type
     * @return $this
     */
    public function setLayoutType(string $layout_type): self
    {
        $this->layout_type = $layout_type;
        return $this;
    }

    /**
     * @return float
     */
    public function getWidth(): float
    {
        return $this->width;
    }


    /**
     * @param float $width
     * @return $this
     */
    public function setWidth(float $width): self
    {
        $this->width = $width;
        return $this;
    }

    /**
     * @return float
     */
    public function getLength(): float
    {
        return $this->length;
    }


    /**
     * @param float $length
     * @return $this
     */
    public function setLength(float $length): self
    {
        $this->length = $length;
        return $this;
    }

    /**
     * @return float
     */
    public function getHeight(): float
    {
        return $this->height;
    }


    /**
     * @param float $height
     * @return $this
     */
    public function setHeight(float $height): self
    {
        $this->height = $height;
        return $this;
    }

    /**
     * @return int
     */
    public function getKimberleyUnitId(): int
    {
        return $this->kimberley_unit_id;
    }


    /**
     * @param int $kimberley_unit_id
     * @return $this
     */
    public function setKimberleyUnitId(int $kimberley_unit_id): self
    {
        $this->kimberley_unit_id = $kimberley_unit_id;
        return $this;
    }

    /**
     * @return \DateTime
     */
    public function getKimberleyDateUpdated(): \DateTime
    {
        return $this->kimberley_date_updated;
    }

    /**
     * @param \DateTime $kimberley_date_updated
     * @return $this
     */
    public function setKimberleyDateUpdated(\DateTime $kimberley_date_updated): self
    {
        $this->kimberley_date_updated = $kimberley_date_updated;
        return $this;
    }


    

}

So i have the HasOne parts at the top to be able to use the model to get the type and category, but how would i do this to replace my query above with the where clause?

I have tried something like:

Caravan::with(['type','category'])->where('type.name','New');

This doesn't work, just says type doesn't exist in so many words.

So what i want to get back, is the model like i would just running say Caravan::all() which i would then be able to loop and use something like $caravan->type->name

EDIT

Answer below from Wahyu:

Caravan::with(['type' => function ($query) {
    $query->where('name', 'New');
}, 'category' => function($query) use ($category) {
        $query->where('name',ucwords(strtolower($category)));
    }])->orderBy($orderBy,$order);

This query runs fine however, it's bringing results back where type is Used as well as New so the query isn't working.

Also, looping the results, i still can't use the HasOne method in my model to do $caravan->type->name

However, Caravan::all() as a test allows me to use $caravan->type->name in the loop and that works ok, so the where query is still an issue

CodePudding user response:

You can accomplish by passing an array of relationships to the with method where the array key is a relationship name and the array value is a closure that adds additional constraints to the eager loading query:

Caravan::with(['type' => function ($query) {
    $query->where('name', 'New');
}, 'category'])->get();

Update (different question):

i still can't use the HasOne method in my model to do $caravan->type->name

public function type() : HasOne
{
    return $this->hasOne(Type::class, 'id', 'type_id');
}

So, you can access the Type model from Caravan model. You can define the inverse of a hasOne relationship using the belongsTo method:

public function type()
{
    return $this->belongsTo(Type::class);
}

When invoking the type method, Eloquent will attempt to find a Type model that has an id which matches the type_id column on the Caravan model.

CodePudding user response:

If you are using a recent version of Laravel you can do something like:

Caravan::query()
    ->whereRelation('type', 'name', 'New')
    ->whereRelation('category', 'name', ucwords(strtolower($category)))
    ->orderBy($orderBy, $order)
    ->get();

Otherwise, you can use the eloquent whereHas() method to achieve the same result.

Caravan::query()
    ->whereHas('type', fn (Builder $query) => $query->where('name', 'New'))
    ->whereHas('category', fn (Builder $query) => $query->where('name', ucwords(strtolower($category))))
    ->orderBy($orderBy, $order)
    ->get();

Looking at your model relations I think your relations should be one to many instead of one to one. If so your relations should be:

public function type()
{
    return $this->belongsTo(Type::class);
}

public function category()
{
    return $this->belongsTo(Category::class);
}
  • Related