Luc*_*oni 1 php mysql database database-design laravel
users transactions tasks
+----+--------+ +----+---------------+ +----+--------+
| id | name | | id | name | | id | name |
+----+--------+ +----+---------------+ +----+--------+
| 1 | User 1 | | 1 | Transaction 1 | | 1 | Task 1 |
| 2 | User 2 | | 2 | Transaction 2 | | 2 | Task 2 |
+----+--------+ +----+---------------+ +----+--------+
templates transaction_user task_transaction
+----+---------------+ +---------+----------------+ +---------+----------------+
| id | name | | user_id | transaction_id | | task_id | transaction_id |
+----+---------------+ +---------+----------------+ +---------+----------------+
| 1 | Template 1 | | 1 | 1 | | 1 | 1 |
| 2 | Template 2 | | 2 | 2 | +---------+----------------+
+----+---------------+ +---------+----------------+
task_template
+---------+-------------+
| task_id | template_id |
+---------+-------------+
| 2 | 2 |
+---------+-------------+
Run Code Online (Sandbox Code Playgroud)
动机:
如果有登录用户,说ID为1的用户,并且他/她想要查看任务(说ID为1的任务)那么我想确保ID为1 Belongs to的任务用户之前我让他看看吧.此外,我还需要向用户显示属于他的所有任务.任务只是一个模型..我需要为所有模型处理这个.我在下面分享了我的代码,我是否努力了?
我可能在这里省略了一些细节,所以请随时提问.谢谢.
码
<?php namespace SomeProject\Repositories;
use User;
use Account;
use Task;
use Document;
use Transaction;
use Property;
use DB;
use Respond;
abstract class DbRepository
{
/**
* The many to many relationships are handeled using pivot tables
* We will use this array to figure out relationships and then get
* a particular resource's owner / account
*/
public $pivot_models = array(
'Task' => array(
'Transaction' => 'task_transaction'
),
'Transaction' => array(
'User' => 'transaction_user'
),
'Document' => array(
'Property' => 'document_property',
'Task' => 'document_task',
'Message' => 'document_message'
)
);
public $entity_ids;
public function getOwnersByEntity(array $ids, $entity)
{
$this->entity_ids = [];
$user_ids = [];
$entity = ucfirst(strtolower($entity)); // arrays keys are case sensitive
if( $this->getPivotIds($ids, $entity) )
{
foreach ($this->entity_ids as $entity_name => $entity_ids_arr)
{
$entity_name_lowercase = strtolower($entity_name);
if($entity_name_lowercase != 'user')
{
$user_ids_from_entity = $entity_name::whereIn('id', $entity_ids_arr)
->lists('user_id');
}
else
{
// We already have the IDs if the entity is User
$user_ids_from_entity = $entity_ids_arr;
}
array_push($user_ids, $user_ids_from_entity);
}
$merged_user_ids = call_user_func_array('array_merge', $user_ids);
return array_unique($merged_user_ids);
}
else
{
return $entity::whereIn('id', $ids)->lists('user_id');
}
}
public function getPivotIds(array $ids, $entity)
{
$entity_lowercase = strtolower($entity);
if( array_key_exists($entity, $this->pivot_models) )
{
// Its a pivot model
foreach ($this->pivot_models[$entity] as $related_model => $table) // Transaction, Template
{
$related_model_lowercase = strtolower($related_model);
$this->entity_ids[$related_model] = DB::table($table)
->whereIn($entity_lowercase . '_id', $ids)
->lists($related_model_lowercase . '_id');
if( $this->getPivotIds($this->entity_ids[$related_model], $related_model) )
{
unset($this->entity_ids[$related_model]);
}
}
return true;
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
要检查给定的模型是否与另一个模型相关,如果我找到你就是你想要的,你需要的只是这个小方法充分利用Eloquent:
(中实现它BaseModel,Entity或范围,任何适合你)
// usage
$task->isRelatedTo('transactions.users', $id);
// or
$template->isRelatedTo('tasks.transactions.users', Auth::user());
// or any kind of relation:
// imagine this: User m-m Transaction 1-m Item m-1 Group
$group->isRelatedTo('items.transaction.users', $id);
Run Code Online (Sandbox Code Playgroud)
魔术发生在这里:
/**
* Check if it is related to any given model through dot nested relations
*
* @param string $relations
* @param int|\Illuminate\Database\Eloquent\Model $id
* @return boolean
*/
public function isRelatedTo($relations, $id)
{
$relations = explode('.', $relations);
if ($id instanceof Model)
{
$related = $id;
$id = $related->getKey();
}
else
{
$related = $this->getNestedRelated($relations);
}
// recursive closure
$callback = function ($q) use (&$callback, &$relations, $related, $id)
{
if (count($relations))
{
$q->whereHas(array_shift($relations), $callback);
}
else
{
$q->where($related->getQualifiedKeyName(), $id);
}
};
return (bool) $this->whereHas(array_shift($relations), $callback)->find($this->getKey());
}
protected function getNestedRelated(array $relations)
{
$models = [];
foreach ($relations as $key => $relation)
{
$parent = ($key) ? $models[$key-1] : $this;
$models[] = $parent->{$relation}()->getRelated();
}
return end($models);
}
Run Code Online (Sandbox Code Playgroud)
isRelatedTo() 像这样工作:
检查传递$id是模型还是只是一个id,并准备$related模型及其$id在回调中使用.如果你没有传递一个对象,那么Eloquent需要实例化$relations(relation1.relation2.relation3...)链上的所有相关模型以获得我们感兴趣的那个 - 这就是发生的事情getNestedRelated(),非常简单.
然后我们需要做这样的事情:
// assuming relations 'relation1.relation2.relation3'
$this->whereHas('relation1', function ($q) use ($id) {
$q->whereHas('relation2', function ($q) use ($id) {
$q->whereHas('relation3', function ($q) use ($id) {
$q->where('id', $id);
});
});
})->find($this->getKey());
// returns new instance of current model or null, thus cast to (bool)
Run Code Online (Sandbox Code Playgroud)因为我们不知道嵌套关系有多深,所以我们需要使用并发.然而我们将一个Closure传递给了whereHas,所以我们需要使用小技巧来调用它自己的体内(事实上我们不调用它,而是将它传递$callback给whereHas方法,因为后者期望Closure为第二个param) - 这可能对那些不熟悉的匿名递归PHP函数很有用:
// save it to the variable and pass it by reference
$callback = function () use (&$callback) {
if (...) // call the $callback again
else // finish;
}
Run Code Online (Sandbox Code Playgroud)我们也通过$relations引用传递给闭包(现在作为一个数组),以便取消它的元素,当我们得到它们(意思是我们嵌套whereHas)时,我们最终把where子句放在另一个上whereHas,来搜索我们的$related模型.
终于让我们回来了 bool