【问题标题】:How to make relation between 3 tables in laravel using laravel relation?如何使用 laravel 关系在 laravel 中的 3 个表之间建立关系?
【发布时间】:2019-12-05 13:58:32
【问题描述】:

我有三张桌子:

SET NAMES utf8;
SET time_zone = '+00:00';

DROP TABLE IF EXISTS `api_credentials`;
CREATE TABLE `api_credentials` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
    `user_id` bigint(20) unsigned NOT NULL,
    `api_provider_id` bigint(20) unsigned NOT NULL,
    `access` text COLLATE utf8_unicode_ci,
    `created_at` timestamp NULL DEFAULT NULL,
    `updated_at` timestamp NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    KEY `api_credentials_user_id_foreign` (`user_id`),
    KEY `api_credentials_api_provider_id_index` (`api_provider_id`),
    CONSTRAINT `api_credentials_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
    CONSTRAINT `api_credentials_api_provider_id_foreign` FOREIGN KEY (`api_provider_id`) REFERENCES `api_providers` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

DROP TABLE IF EXISTS `api_providers`;
CREATE TABLE `api_providers` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
    `name` char(255) COLLATE utf8_unicode_ci NOT NULL,
    `table_prefix` char(255) COLLATE utf8_unicode_ci NOT NULL,
    `created_at` timestamp NULL DEFAULT NULL,
    `updated_at` timestamp NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
    `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
    `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
    `email_verified_at` timestamp NULL DEFAULT NULL,
    `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
    `remember_token` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
    `created_at` timestamp NULL DEFAULT NULL,
    `updated_at` timestamp NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `users_email_unique` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

-- 2019-12-05 13:38:06

这是我的模型: 1.ApiCredential

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Pivot;

class ApiCredential extends Pivot
{

}
  1. ApiProvider
<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class ApiProvider extends Model
{
    protected $fillable = [
        'name',
        'table_prefix'
    ];

    public function users()
    {
        return $this->belongsToMany('App\Models\User')->using('App\Models\ApiCredential');
    }
}
  1. 用户模型
namespace App\Models;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

use App\Models\ApiProvider;
use App\Models\ApiCredential;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
    */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    public function apiProvider()
    {  
        return $this->belongsToMany('App\Models\ApiProvider','api_providers','user_id','api_provider_id');
    } 

    public function hasCredentials(String $apiProvider)
    {
        return $this->apiProvider()->where('name', $apiProvider)->get();
    } 
}

现在我想要什么: 我想根据userapi_providerapi_credentials 表中获取记录。假设我在api_providers 中有三条记录(名称是 adscane、cpalead、offertorro)。

我正在运行这个函数来获取cpalead的api_credential。

User::find(1)->hasCredentials('cpalead');

但它没有给出预期的结果。

谁能帮我解决这个问题。

【问题讨论】:

  • User 类的apiProvider() 函数不应该使用api_credentials 而不是api_providers 作为其数据透视表吗?
  • 或者甚至使用自定义数据透视模型,例如 ApiProvider 类的 user() 函数

标签: laravel eloquent relationship laravel-6.2


【解决方案1】:

我相信

# User model
public function apiProvider()
{  
    return $this->belongsToMany('App\Models\ApiProvider','api_providers','user_id','api_provider_id');
}

应该是

# User model
public function apiProvider()
{  
    return $this->belongsToMany('App\Models\ApiProvider','api_credentials','user_id','api_provider_id');
}

编辑访问 api_credentials:

  1. 使用hasMany 关系
# User model
public function apiCredentials()
{
    return $this->hasMany('App\Models\ApiCredential')
}
# ApiProvider model
public function apiCredentials()
{
    return $this->hasMany('App\Models\ApiCredential');
}
# ApiCredential model
public function user()
{
    return $this->belongsTo('App\Models\User');
}

public function apiProvider()
{
    return $this->belongsTo('App\Models\ApiProvider');
}

然后,我们重新定义hasCredentials() 函数,使其工作如下:

# User model
public function hasCredentials(String $apiProvider)
{
    $this->apiCredentials()->whereHas('apiProvider', function ($query) use ($apiProvider) {
         $query->where('name', '=', $apiProvider);
    })
    ->get();
}

使用数据如下所示:

$user = User::find($id);

foreach($user->hasCredentials('api_provider_name') as $apiCredential)
{
    // $apiCredential->name
    // $apiCredential->table_prefix
}

【讨论】:

  • 第一个选项有效,但它从 api_credential 表返回记录,而我想从 api_credentials 表中匹配记录。
  • 您想要的是访问可以在记录到记录的基础上或通过第二个关系完成的数据透视。我将在我的答案中编辑这些选项。
  • 我只想要来自 api_creentias 的基于用户和 api_provider_name 的信息
  • 我编辑了我的答案。我相信定义和使用 hasMany 关系可能是您的最佳方式。
  • 感谢第二个解决方案 Using a hasMany relationship 解决了我的问题..
【解决方案2】:

这样使用

namespace App\Model;


use Illuminate\Database\Eloquent\Model;

class ApiCredential extends Model
{

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function apiProvider()
    {
        return $this->belongsTo(ApiProvider::class);
    }
}

namespace App\Model;


use Illuminate\Database\Eloquent\Model;

class ApiProvider extends Model
{

    public function ApiCredentials()
    {
        return $this->hasMany(ApiCredential::class);
    }

}

namespace App\Model;

use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
use Spatie\Activitylog\Traits\LogsActivity;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    public function ApiCredentials()
    {
        return $this->hasMany(ApiCredential::class);
    }

}

现在这样查询

    User::with('apiCredentials.apiProvider',)
        ->where('id',1)
        ->whereHas('apiCredentials.apiProvider', function ($query)  {
        $query->where('name','cpalead' );
    })->get();

【讨论】:

  • 我尝试了您的解决方案,但它不起作用。 @IGP 提供的解决方案运行良好。
猜你喜欢
  • 2019-01-20
  • 2017-07-09
  • 1970-01-01
  • 2020-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-03
  • 2019-05-17
相关资源
最近更新 更多