【问题标题】:Get first image for each product获取每个产品的第一张图片
【发布时间】:2020-04-26 11:10:46
【问题描述】:

我尝试获取最新的 10 产品及其图片,但只有第一张图片 这就是我尝试的方法

$newProducts = \App\Product::latest()->with(['images', function($el){

   $el->first();

}])->with('category')->take(10)->get();

但它给了我这个错误

mb_strpos() expects parameter 1 to be string, object given

它在productimage 之间具有morph 关系

产品型号

class Product extends Model {
    public function images()
    {
        return $this->morphMany(Image::class, 'imageable');
    }
}

图像模型

class Image extends Model {
    public function imageable()
    {
        return $this->morphTo();
    }
}

【问题讨论】:

    标签: php laravel eloquent eloquent-relationship


    【解决方案1】:
    public function images()
    {
        return $this->hasMany(Image::class);
    }
    
    public function firstImage()
    {
        return $this->images()->first();
    }
    

    只需创建一个定义产品与其图像之间关系的函数。 然后创建一个获取第一张图片的函数

    【讨论】:

      【解决方案2】:

      以上解决方案都很好。我个人更喜欢另一种我认为会很理想的解决方案。

      我将为产品定义不同的关系:

      class Product extends Model {
          public function images()
          {
              return $this->morphMany(Image::class, 'imageable');
          }
      
          public function firstImage()
          {
              return $this->morphOne(Image::class, 'imageable');
          }
      }
      

      因此您可以直接访问第一张图片或急切加载关系:

      $product->firstImage;
      
      $product->load('firstImage');
      
      Product::with('firstImage');
      

      仅供参考,我从 Laracon Online 2018 的 Jonathan Reinink 那里了解了这个和其他有用的数据库技巧。

      【讨论】:

      • 我喜欢它更加优化和干净,没有任何外部包
      【解决方案3】:

      当使用 with 作为键值数组时,闭包的$el 参数将是一个尚未执行的查询构建器。

      限制结果查询生成器的方法是使用take()。因此,您的代码应如下所示。

      ->with(['images', function($el) {
          $el->take(1);
      }])
      

      编辑要使此解决方案有效,您将需要一个额外的package。使用以下特征应该使其工作并改用限制。请参阅以下post

      use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
      
      ->with(['images', function($el) {
          $el->limit(1);
      }])
      

      或者 Laravel 解决方案是使用转换之类的属性,您可以在其中创建自己的自定义属性,在函数命名中以 get 开头并以属性结尾。

      class Product {
          protected $appends = ['first_image'];
      
          public function getFirstImageAttribute() {
              return $this->images->first();
          }
      }
      

      现在,如果您使用标准的Laravel 序列化,所有产品都会有一个 first_image 字段,并且在您的代码中您可以像这样访问它。

      $product->first_image;
      

      为避免性能下降,请使用 with('images') 包含图像。

      【讨论】:

      • mutations 方式工作得很好,谢谢,但正如你所说,为了避免性能下降,使用 with('images') 包含图像我尝试了,但它得到了同样的错误
      • 这就是它的尝试$newProducts = \App\Product::latest()->with(['images', function($el){ $el->take(1); }])->get();
      • 您不能在 with 约束内使用 take()。急切加载的工作方式是加载所有父记录,然后使用where parent_id in ([previously loaded parent ids]) 加载所有子记录。当您执行 take() 时,它实际上是告诉它加载单个子 TOTAL,而不管有多少父母
      • @jfadich 你能告诉我怎么解决吗?
      • 使用 @mrhn 的“替代 Laravel 解决方案”应该可以。需要注意的是,如果您使用protected $appends = ['first_image'];,您还应该使用protected $with = ['images']
      猜你喜欢
      • 2021-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多