Lumen/Laravel - 为什么数据会自动插入结点table?
Lumen/Laravel - Why is data automatically inserted into junction table?
我有 3 个 tables:
Ad_users
Ad_groups
Ad_usersxad_groups
Ad_usersxad_groups 是其他两个的交汇点 table。
现在,我在一个 lumen/laravel 项目中工作,我们正在使用 eloquent 模型。
我有以下型号 ad_users table 和 ad_groups table:
ad_user.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Ad_user extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'common_name',
'location',
'description',
'postalcode',
'physical_delivery_office_name',
'telephone_number',
'initials',
'street_address'
];
/**
* Hides pivot in return queries.
*
* @var array
*/
protected $hidden = [
'pivot'
];
/**
* Many-To-Many relationship.
*/
public function ad_groups()
{
return $this->belongsToMany('App\Ad_group', 'Ad_usersxad_groups');
}
}
ad_group.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Ad_group extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name'
];
/**
* Hides pivot from return queries.
*
* @var array
*/
protected $hidden = [
'pivot'
];
/**
* Many-To-Many relationshipl.
*/
public function ad_users()
{
return $this->belongsToMany('App\Ad_user', 'Ad_usersxad_groups');
}
public function extensiontables()
{
return $this->belongsToMany('App\extensiontables_registry', 'extensiontables_registryxad_groups');
}
}
ad_groups和ad_user里面的数据基本来自我们公司的LDAP服务器。
因此,当用户登录时,中间件会建立与 ldap 的连接并检索用户数据。然后数据会同步到我们的本地数据库,这意味着它要么被更新,要么被创建。
为了完整起见,以下是用户访问登录路由时执行的代码:
AuthController.php
public function login(Request $request)
{
$ldap = new LDAP;
$jwt = new JWTAuth;
$response = new Response;
$this->validate($request, [
'username' => 'string|required',
'password' => 'string|required'
]);
if(!$ldap->authenticateUser($request->username, $request->password))
{
return response()->json([
'error' => 'User could not be authenticated'
], 401);
}
/**
* Synchronizes the user's data from ldap with the local db.
* Used for better performance and mitigating network overhead.
*/
$ldap->syncData($request->username);
$response->header('Authorization', 'Bearer '.$jwt->generateJWT($request->username));
return $response;
}
这里,重要的部分是$ldap->syncData($request->username);
。
它调用 LDAP.php,执行此代码的位置:
LDAP.php
public function syncData($username)
{
try
{
if(!$this->connect())
{
$this->disconnect();
return false;
}
$userData = $this->getUser($username, [
'cn',
'l',
'description',
'postalcode',
'physicaldeliveryofficename',
'telephonenumber',
'initials',
'memberof',
'streetaddress'
]);
$user = Ad_user::updateOrCreate(
['common_name' => $userData['cn']],
[
'common_name' => $userData['cn'],
'location' => $userData['l'],
'description' => $userData['description'],
'postalcode' => $userData['postalcode'],
'physical_delivery_office_name' => $userData['physicaldeliveryofficename'],
'telephone_number' => $userData['telephonenumber'],
'initials' => $userData['initials'],
'street_address' => $userData['streetaddress']
]
);
// Remove everything but the user roles
foreach($userData['memberof'] as $key=>$role)
{
preg_match("/^CN=.+?,/", $role, $role);
$userData['memberof'][$key] = substr($role[0], 3, -1);
}
// Loop through every role because updateOrCreate cant handle arrays
foreach($userData['memberof'] as $value)
{
$roles[] = Ad_group::updateOrCreate(
['name' => $value],
['name' => $value]
)->id;
}
// Syncs current roles received from ldap with the local db
$user->ad_groups()->sync($roles);
}
catch(\Exception $e)
{
$error = array("exception_code" => $e->getCode(), "error_message" => $e->getMessage());
Log::error($error);
return false;
}
finally
{
$this->disconnect();
}
}
我发现每当用户登录系统时,记录都会插入连接 table。
每次,这意味着会创建大量冗余数据。
我想导致这个问题的代码的重要部分是这样的:
$user->ad_groups()->sync($roles)
例如,同一用户登录 7 次后,结点 table 如下所示:
select * from ad_usersxad_groups;
+------------+-------------+------------+------------+
| Ad_user_id | Ad_group_id | created_at | updated_at |
+------------+-------------+------------+------------+
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 1 | 4 | NULL | NULL |
| 1 | 5 | NULL | NULL |
| 1 | 6 | NULL | NULL |
| 1 | 7 | NULL | NULL |
| 1 | 8 | NULL | NULL |
| 1 | 9 | NULL | NULL |
| 1 | 10 | NULL | NULL |
| 1 | 11 | NULL | NULL |
| 1 | 12 | NULL | NULL |
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 1 | 4 | NULL | NULL |
| 1 | 5 | NULL | NULL |
| 1 | 6 | NULL | NULL |
| 1 | 7 | NULL | NULL |
| 1 | 8 | NULL | NULL |
| 1 | 9 | NULL | NULL |
| 1 | 10 | NULL | NULL |
| 1 | 11 | NULL | NULL |
| 1 | 12 | NULL | NULL |
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 1 | 4 | NULL | NULL |
| 1 | 5 | NULL | NULL |
| 1 | 6 | NULL | NULL |
| 1 | 7 | NULL | NULL |
| 1 | 8 | NULL | NULL |
| 1 | 9 | NULL | NULL |
| 1 | 10 | NULL | NULL |
| 1 | 11 | NULL | NULL |
| 1 | 12 | NULL | NULL |
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 1 | 4 | NULL | NULL |
| 1 | 5 | NULL | NULL |
| 1 | 6 | NULL | NULL |
| 1 | 7 | NULL | NULL |
| 1 | 8 | NULL | NULL |
| 1 | 9 | NULL | NULL |
| 1 | 10 | NULL | NULL |
| 1 | 11 | NULL | NULL |
| 1 | 12 | NULL | NULL |
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 1 | 4 | NULL | NULL |
| 1 | 5 | NULL | NULL |
| 1 | 6 | NULL | NULL |
| 1 | 7 | NULL | NULL |
| 1 | 8 | NULL | NULL |
| 1 | 9 | NULL | NULL |
| 1 | 10 | NULL | NULL |
| 1 | 11 | NULL | NULL |
| 1 | 12 | NULL | NULL |
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 1 | 4 | NULL | NULL |
| 1 | 5 | NULL | NULL |
| 1 | 6 | NULL | NULL |
| 1 | 7 | NULL | NULL |
| 1 | 8 | NULL | NULL |
| 1 | 9 | NULL | NULL |
| 1 | 10 | NULL | NULL |
| 1 | 11 | NULL | NULL |
| 1 | 12 | NULL | NULL |
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 1 | 4 | NULL | NULL |
| 1 | 5 | NULL | NULL |
| 1 | 6 | NULL | NULL |
| 1 | 7 | NULL | NULL |
| 1 | 8 | NULL | NULL |
| 1 | 9 | NULL | NULL |
| 1 | 10 | NULL | NULL |
| 1 | 11 | NULL | NULL |
| 1 | 12 | NULL | NULL |
+------------+-------------+------------+------------+
这既不理想也不接受table,但由于我对lumen/laravel以及此处使用的php LDAP API还很陌生,所以我有真的不知道什么可能导致这种行为 Oo 至少我很确定 MySQL/MariaDB 不会影响这种行为,因为 FOREIGN KEY 没有附加到它们的 CASCADE。
我想知道我是否在模型定义中做错了什么,但我不知道是什么 xD
非常感谢您的帮助^^
编辑:
日志已显示角色数组:
[2020-01-31 08:57:27] local.INFO: array (
0 => 1,
1 => 2,
2 => 3,
3 => 4,
4 => 5,
5 => 6,
6 => 7,
7 => 8,
8 => 9,
9 => 10,
10 => 11,
11 => 12,
)
仅供参考,这里是数据库的外键,当然也包括与本题相关的外键。我很确定我正确配置了它们,但也许我只是瞎了眼所以它们在这里:
| TABLE_NAME | COLUMN_NAME | CONSTRAINT_NAME | REFERENCED_TABLE_NAME | REFERENCED_COLUMN_NAME |
+------------------------------------+-----------------------------+--------------------------------------+--------------------------+------------------------+
| ad_usersxad_groups | Ad_user_id | fk_ad_groupxad_user | ad_users | id |
| ad_usersxad_groups | Ad_group_id | fk_ad_userxad_group | ad_groups | id |
| extensiontables_registryxad_groups | ad_group_id | fk_ad_groupxextensiontables_registry | ad_groups | id |
| extensiontables_registryxad_groups | extensiontables_registry_id | fk_extensiontables_registryxad_group | extensiontables_registry | id |
| extensiontable_itc | coretable_id | fk_extensiontable_itc_coretable | coretable | id |
| inaccessibletable | coretable_id | fk_inaccessibletable_coretable | coretable | id |
+------------------------------------+-----------------------------+--------------------------------------+--------------------------+------------------------+
据我所知,转储的数组和代码看起来都不错。
我不是 Laravel 专家,但我建议在定义你们的关系时尝试更具体一些,看看是否可以解决您的问题。
在您的 Ad_user
模型中,更改:
public function ad_groups()
{
return $this->belongsToMany('App\Ad_group', 'Ad_usersxad_groups');
}
至:
public function ad_groups()
{
return $this->belongsToMany('App\Ad_group', 'Ad_usersxad_groups', 'Ad_user_id', 'Ad_group_id');
}
在你的 Ad_group
模型中,更改:
public function ad_users()
{
return $this->belongsToMany('App\Ad_user', 'Ad_usersxad_groups');
}
至:
public function ad_users()
{
return $this->belongsToMany('App\Ad_user', 'Ad_usersxad_groups', 'Ad_group_id', 'Ad_user_id');
}
我有 3 个 tables:
Ad_users
Ad_groups
Ad_usersxad_groups
Ad_usersxad_groups 是其他两个的交汇点 table。 现在,我在一个 lumen/laravel 项目中工作,我们正在使用 eloquent 模型。 我有以下型号 ad_users table 和 ad_groups table:
ad_user.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Ad_user extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'common_name',
'location',
'description',
'postalcode',
'physical_delivery_office_name',
'telephone_number',
'initials',
'street_address'
];
/**
* Hides pivot in return queries.
*
* @var array
*/
protected $hidden = [
'pivot'
];
/**
* Many-To-Many relationship.
*/
public function ad_groups()
{
return $this->belongsToMany('App\Ad_group', 'Ad_usersxad_groups');
}
}
ad_group.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Ad_group extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name'
];
/**
* Hides pivot from return queries.
*
* @var array
*/
protected $hidden = [
'pivot'
];
/**
* Many-To-Many relationshipl.
*/
public function ad_users()
{
return $this->belongsToMany('App\Ad_user', 'Ad_usersxad_groups');
}
public function extensiontables()
{
return $this->belongsToMany('App\extensiontables_registry', 'extensiontables_registryxad_groups');
}
}
ad_groups和ad_user里面的数据基本来自我们公司的LDAP服务器。 因此,当用户登录时,中间件会建立与 ldap 的连接并检索用户数据。然后数据会同步到我们的本地数据库,这意味着它要么被更新,要么被创建。 为了完整起见,以下是用户访问登录路由时执行的代码:
AuthController.php
public function login(Request $request)
{
$ldap = new LDAP;
$jwt = new JWTAuth;
$response = new Response;
$this->validate($request, [
'username' => 'string|required',
'password' => 'string|required'
]);
if(!$ldap->authenticateUser($request->username, $request->password))
{
return response()->json([
'error' => 'User could not be authenticated'
], 401);
}
/**
* Synchronizes the user's data from ldap with the local db.
* Used for better performance and mitigating network overhead.
*/
$ldap->syncData($request->username);
$response->header('Authorization', 'Bearer '.$jwt->generateJWT($request->username));
return $response;
}
这里,重要的部分是$ldap->syncData($request->username);
。
它调用 LDAP.php,执行此代码的位置:
LDAP.php
public function syncData($username)
{
try
{
if(!$this->connect())
{
$this->disconnect();
return false;
}
$userData = $this->getUser($username, [
'cn',
'l',
'description',
'postalcode',
'physicaldeliveryofficename',
'telephonenumber',
'initials',
'memberof',
'streetaddress'
]);
$user = Ad_user::updateOrCreate(
['common_name' => $userData['cn']],
[
'common_name' => $userData['cn'],
'location' => $userData['l'],
'description' => $userData['description'],
'postalcode' => $userData['postalcode'],
'physical_delivery_office_name' => $userData['physicaldeliveryofficename'],
'telephone_number' => $userData['telephonenumber'],
'initials' => $userData['initials'],
'street_address' => $userData['streetaddress']
]
);
// Remove everything but the user roles
foreach($userData['memberof'] as $key=>$role)
{
preg_match("/^CN=.+?,/", $role, $role);
$userData['memberof'][$key] = substr($role[0], 3, -1);
}
// Loop through every role because updateOrCreate cant handle arrays
foreach($userData['memberof'] as $value)
{
$roles[] = Ad_group::updateOrCreate(
['name' => $value],
['name' => $value]
)->id;
}
// Syncs current roles received from ldap with the local db
$user->ad_groups()->sync($roles);
}
catch(\Exception $e)
{
$error = array("exception_code" => $e->getCode(), "error_message" => $e->getMessage());
Log::error($error);
return false;
}
finally
{
$this->disconnect();
}
}
我发现每当用户登录系统时,记录都会插入连接 table。 每次,这意味着会创建大量冗余数据。 我想导致这个问题的代码的重要部分是这样的:
$user->ad_groups()->sync($roles)
例如,同一用户登录 7 次后,结点 table 如下所示:
select * from ad_usersxad_groups;
+------------+-------------+------------+------------+
| Ad_user_id | Ad_group_id | created_at | updated_at |
+------------+-------------+------------+------------+
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 1 | 4 | NULL | NULL |
| 1 | 5 | NULL | NULL |
| 1 | 6 | NULL | NULL |
| 1 | 7 | NULL | NULL |
| 1 | 8 | NULL | NULL |
| 1 | 9 | NULL | NULL |
| 1 | 10 | NULL | NULL |
| 1 | 11 | NULL | NULL |
| 1 | 12 | NULL | NULL |
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 1 | 4 | NULL | NULL |
| 1 | 5 | NULL | NULL |
| 1 | 6 | NULL | NULL |
| 1 | 7 | NULL | NULL |
| 1 | 8 | NULL | NULL |
| 1 | 9 | NULL | NULL |
| 1 | 10 | NULL | NULL |
| 1 | 11 | NULL | NULL |
| 1 | 12 | NULL | NULL |
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 1 | 4 | NULL | NULL |
| 1 | 5 | NULL | NULL |
| 1 | 6 | NULL | NULL |
| 1 | 7 | NULL | NULL |
| 1 | 8 | NULL | NULL |
| 1 | 9 | NULL | NULL |
| 1 | 10 | NULL | NULL |
| 1 | 11 | NULL | NULL |
| 1 | 12 | NULL | NULL |
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 1 | 4 | NULL | NULL |
| 1 | 5 | NULL | NULL |
| 1 | 6 | NULL | NULL |
| 1 | 7 | NULL | NULL |
| 1 | 8 | NULL | NULL |
| 1 | 9 | NULL | NULL |
| 1 | 10 | NULL | NULL |
| 1 | 11 | NULL | NULL |
| 1 | 12 | NULL | NULL |
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 1 | 4 | NULL | NULL |
| 1 | 5 | NULL | NULL |
| 1 | 6 | NULL | NULL |
| 1 | 7 | NULL | NULL |
| 1 | 8 | NULL | NULL |
| 1 | 9 | NULL | NULL |
| 1 | 10 | NULL | NULL |
| 1 | 11 | NULL | NULL |
| 1 | 12 | NULL | NULL |
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 1 | 4 | NULL | NULL |
| 1 | 5 | NULL | NULL |
| 1 | 6 | NULL | NULL |
| 1 | 7 | NULL | NULL |
| 1 | 8 | NULL | NULL |
| 1 | 9 | NULL | NULL |
| 1 | 10 | NULL | NULL |
| 1 | 11 | NULL | NULL |
| 1 | 12 | NULL | NULL |
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 1 | 4 | NULL | NULL |
| 1 | 5 | NULL | NULL |
| 1 | 6 | NULL | NULL |
| 1 | 7 | NULL | NULL |
| 1 | 8 | NULL | NULL |
| 1 | 9 | NULL | NULL |
| 1 | 10 | NULL | NULL |
| 1 | 11 | NULL | NULL |
| 1 | 12 | NULL | NULL |
+------------+-------------+------------+------------+
这既不理想也不接受table,但由于我对lumen/laravel以及此处使用的php LDAP API还很陌生,所以我有真的不知道什么可能导致这种行为 Oo 至少我很确定 MySQL/MariaDB 不会影响这种行为,因为 FOREIGN KEY 没有附加到它们的 CASCADE。
我想知道我是否在模型定义中做错了什么,但我不知道是什么 xD 非常感谢您的帮助^^
编辑: 日志已显示角色数组:
[2020-01-31 08:57:27] local.INFO: array (
0 => 1,
1 => 2,
2 => 3,
3 => 4,
4 => 5,
5 => 6,
6 => 7,
7 => 8,
8 => 9,
9 => 10,
10 => 11,
11 => 12,
)
仅供参考,这里是数据库的外键,当然也包括与本题相关的外键。我很确定我正确配置了它们,但也许我只是瞎了眼所以它们在这里:
| TABLE_NAME | COLUMN_NAME | CONSTRAINT_NAME | REFERENCED_TABLE_NAME | REFERENCED_COLUMN_NAME |
+------------------------------------+-----------------------------+--------------------------------------+--------------------------+------------------------+
| ad_usersxad_groups | Ad_user_id | fk_ad_groupxad_user | ad_users | id |
| ad_usersxad_groups | Ad_group_id | fk_ad_userxad_group | ad_groups | id |
| extensiontables_registryxad_groups | ad_group_id | fk_ad_groupxextensiontables_registry | ad_groups | id |
| extensiontables_registryxad_groups | extensiontables_registry_id | fk_extensiontables_registryxad_group | extensiontables_registry | id |
| extensiontable_itc | coretable_id | fk_extensiontable_itc_coretable | coretable | id |
| inaccessibletable | coretable_id | fk_inaccessibletable_coretable | coretable | id |
+------------------------------------+-----------------------------+--------------------------------------+--------------------------+------------------------+
据我所知,转储的数组和代码看起来都不错。
我不是 Laravel 专家,但我建议在定义你们的关系时尝试更具体一些,看看是否可以解决您的问题。
在您的 Ad_user
模型中,更改:
public function ad_groups()
{
return $this->belongsToMany('App\Ad_group', 'Ad_usersxad_groups');
}
至:
public function ad_groups()
{
return $this->belongsToMany('App\Ad_group', 'Ad_usersxad_groups', 'Ad_user_id', 'Ad_group_id');
}
在你的 Ad_group
模型中,更改:
public function ad_users()
{
return $this->belongsToMany('App\Ad_user', 'Ad_usersxad_groups');
}
至:
public function ad_users()
{
return $this->belongsToMany('App\Ad_user', 'Ad_usersxad_groups', 'Ad_group_id', 'Ad_user_id');
}