I have a Product
model with a hasMany
relationship
public function pricing()
{
return $this->hasMany('App\ProductPrice', 'prod_id', 'id');
}
I then get the relationship
Product::with('pricing')->all();
How can I retrieve the pricing
relationship with the id
as the key. I know I can do it on a Collection
with keyBy('id)
but it doesn't work on a query.
I want to acheive the same results as below but I want to get it from the Product
relationship.
ProductPrice::keyBy('id')
A quick workaround is to replace the current relation in you array using setRelation method. In your case:
$product = Product::with('pricing')->all();
$product->setRelation('pricing', $product->pricing->keyBy('id'));
You have to create your own relationship:
<?php
namespace App\Helpers\Classes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class HasManyKeyBy extends HasMany
{
private $keyBy;
public function __construct($keyBy, Builder $query, Model $parent, string $foreignKey, string $localKey)
{
$this->keyBy = $keyBy;
parent::__construct($query, $parent, $foreignKey, $localKey);
}
public function getResults()
{
return parent::getResults()->keyBy($this->keyBy);
}
protected function getRelationValue(array $dictionary, $key, $type)
{
return parent::getRelationValue($dictionary, $key, $type)->keyBy($this->keyBy);
}
}
For the sake of simplicity I also recommend you to create a trait:
<?php
namespace App\Helpers\Traits;
use Illuminate\Database\Eloquent\Relations\HasMany;
trait HasManyKeyBy
{
/**
* @param $keyBy
* @param $related
* @param null $foreignKey
* @param null $localKey
* @return HasMany
*/
protected function hasManyKeyBy($keyBy, $related, $foreignKey = null, $localKey = null)
{
// copied from \Illuminate\Database\Eloquent\Concerns\HasRelationships::hasMany
$instance = $this->newRelatedInstance($related);
$foreignKey = $foreignKey ?: $this->getForeignKey();
$localKey = $localKey ?: $this->getKeyName();
return new \App\Helpers\Classes\HasManyKeyBy($keyBy, $instance->newQuery(),
$this, $instance->getTable().'.'.$foreignKey, $localKey);
}
}
Now, you can include this trait into your model, and use $this->hasManyKeyBy
protected method:
[...]
class Product extends Model
{
use HasManyKeyBy;
public function pricing()
{
return $this->hasManyKeyBy('id', ProductPrice::class, 'prod_id', 'id');
}
[...]
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With