【问题标题】:In Laravel, how can I have "with" return a boolean instead of the object, true in case it exists, false if doesn't exist在 Laravel 中,我怎样才能让“with”返回一个布尔值而不是对象,如果它存在则返回 true,如果不存在则返回 false
【发布时间】:2016-08-04 13:17:29
【问题描述】:

例如,我们有一个歌曲表和一个收藏(歌曲)表。

如果我使用Songs::with('favorites')->get(),它将返回如下:

"songs": [
  {
    "id": 43,
    "name": "Song 1",
    "favorites": [
      {
        "id": 52,
        "user_id": 25,
        "song_id": 43
      }
    ]
  },
  {
    "id": 44,
    "name": "Song 2",
    "favorites": []
  },

我要做的是,如果歌曲被收藏,则返回1,如果没有,则返回0,如下:

  {
    "id": 43,
    "name": "Song 1",
    "favorites": true                (or 1)
  },
  {
    "id": 44,
    "name": "Song 2",
    "favorites": false              (or 0)
  },

有没有办法不用在 PHP 中手动遍历返回的集合数组?

【问题讨论】:

  • 你不想使用map
  • 无论如何,你似乎已经拥有了你想要的东西。如果 $song->favorites 为 null (false),否则为 true。
  • 映射不只是迭代结果集吗?我希望在模型加载到查询之前/期间做一些事情。
  • @Lucas 是的,你是对的。可以保持原样。只是我的好奇心改变它。
  • 您也可以使用更原始的 SQL 方法来做到这一点,但我不确定如何。

标签: php laravel collections


【解决方案1】:

我认为这是使用 Eloquent 最简单的解决方案

Song::withCount([
    'favorites' => function ($query) {
         $query->select(DB::raw('IF(count(*) > 0, 1, 0)'));
    }
])->orderBy('favorites_count', 'desc');

【讨论】:

    【解决方案2】:

    有很多不同的方法可以做你想做的事,这完全取决于最适合你的方法。

    如果你想在你的结果集中返回结果,你可以设置一个范围:

    class Song extends Model
    {
        public function scopeAddFavorite($query, $userId = null)
        {
            $andUser = !empty($userId) ? ' AND favorites.user_id = '.$userId : '';
            return $query->addSelect(\DB::raw('(EXISTS (SELECT * FROM favorites WHERE favorites.song_id = songs.id'.$andUser.')) as is_favorite')); 
        }
    }
    

    由于此范围修改了“选择”语句,因此您需要确保在添加到范围之前手动指定所需的其他列。

    $songs = Song::select('*')->addFavorite()->get();
    

    我添加了传入用户 ID 的功能,以防您想指定该列仅在歌曲已被特定用户收藏时才返回 true。

    $songs = Song::select('*')->addFavorite(25)->get();
    

    另一种选择,您可以在模型中添加一个访问器来为您处理检查。你可以read about accessors here

    class Song extends Model
    {
        // only do this if you want to include is_favorite in your json output by default
        protected $appends = ['is_favorite'];
    
        public function getIsFavoriteAttribute()
        {
            // if you always want to hit the database:
            return $this->favorites()->count() > 0;
    
            // if you're okay using any pre-loaded relationship
            // will load the relationship if it doesn't exist
            return $this->favorites->count() > 0;
        }
    }
    

    用法:

    $song = Song::find(1);
    
    // access is_favorite like a normal attribute
    var_dump($song->is_favorite);
    
    // with $appends, will show is_favorite;
    // without $appends, will not show is_favorite
    var_dump($song);
    

    【讨论】:

      【解决方案3】:

      使用原始 SQL 方法

      DB::select('SELECT s.*, (CASE WHEN f.id IS NULL THEN 0 ELSE 1 END) as favorites FROM songs s LEFT JOIN favorites f ON s.id = f.song_id GROUP BY s.id')
      

      将返回以下结构:

      [
        StdClass { 'id' => 1, 'name' => 'Song 1', 'favorites' => 1 },
        StdClass { 'id' => 2, 'name' => 'Song 2', 'favorites' => 0 },
        StdClass { 'id' => 3, 'name' => 'Song 3', 'favorites' => 1 },
      ]
      

      现在,使用 Eloquent

      Song::withCount('favorites')->get()
      

      将返回 Song 类的对象数组

      [
        Song { 'id' => 1, 'name' => 'Song 1', 'favorites_count' => 1 },
        Song { 'id' => 2, 'name' => 'Song 2', 'favorites_count' => 0 },
        Song { 'id' => 3, 'name' => 'Song 3', 'favorites_count' => 3 }
      ]
      

      不同之处在于第一个将返回 PHP 标准对象数组,而第二个将返回 Song 对象数组,第一个比第二个

      【讨论】:

        【解决方案4】:

        如果不首先以某种方式操作原始结果对象,您将无法执行此类操作。

        您并没有真正指定您需要如何使用或迭代数据,但也许Query Scopes 可以帮助您?无论哪种方式,您都需要对数据进行一次迭代以对其进行操作。像map 这样的高阶函数将帮助您做到这一点。

        【讨论】:

        • Scopes 只会返回有收藏夹的或者没有收藏夹的。我正在寻找类似 mutators 之类的东西,但要寻找以 'with' 返回的结果。
        • 映射不只是迭代结果集吗?我希望在模型加载到查询之前/期间做一些事情。但我想这样的事情仅靠 eloquent 是不可能的。
        • each 只是一个迭代器。 map 允许您从回调到新变量进行迭代和操作。 see docs for map
        【解决方案5】:

        假设你有 $songs 数组,你可以这样做,

        foreach($songs as $song)
            $song["favorites"] = is_null($song["favorites"]) ? true : false;
        

        【讨论】:

          猜你喜欢
          • 2021-09-11
          • 2018-04-10
          • 2017-11-17
          • 1970-01-01
          • 2023-03-28
          • 2018-10-22
          • 2010-11-30
          • 1970-01-01
          • 2019-02-15
          相关资源
          最近更新 更多