laravel中 使用自定符号从一个字段中读取多个关联

在数据库设计中,常常会有用到以逗号隔开存储信息的场景

在我们的业务场景中,就会设计到很多 比如针对订单或者用户的标签记录,用户和标签一对多的关系 如果使用单表来维护标签关系 而实际业务场景不是特别复杂的时候,这样做显得有点多余,这时候经常会采用一个字段以特殊字符隔开记录标签或其他信息;

在laravel框架里,这个场景下,数据的回显如果采用join或者一对多关联的写法,并不适应数据的查询和回显及数据排重,如果有针对单字段,以特殊字符隔开的特殊关联就好了

下面我们给出针对单字段,根据特殊分隔字符,加载关联的代码实现

定义一个类 HasManyFromStr.php

use Illuminate\Database\Eloquent\Builder;
 
use Illuminate\Database\Eloquent\Collection;
 
use Illuminate\Database\Eloquent\Model;
 
use Illuminate\Database\Eloquent\Relations\HasOneOrMany;
 
class HasManyFromStr extends HasOneOrMany
 
{
 
    protected $separator = ',';
 
    public function __construct(Builder $query, Model $parent, string $foreignKey, string $localKey, $separator)
 
    {
 
            parent::__construct($query, $parent, $foreignKey, $localKey);
 
            $this->separator = $separator;
 
        }
 
    /**
        * Get the results of the relationship.
        *
         * @return mixed
    */
 
    public function getResults()
 
    {
 
            return ! is_null($this->getParentKey())
 
               ? $this->query->get()
 
                : $this->related->newCollection();
 
        }
 
    /**
* Initialize the relation on a set of models.
*
    * @param  array  $models
    * @param  string  $relation
    * @return array
*/
 
    public function initRelation(array $models, $relation)
 
{
 
        foreach ($models as $model) {
 
            $model->setRelation($relation, $this->related->newCollection());
 
        }
 
        return $models;
 
    }
 
    /**
    * 重写匹配方法
    * @param array      $models
    * @param Collection $results
    * @param string    $relation
    * @return array
*/
 
    public function match(array $models, Collection $results, $relation)
 
{
 
        $dictionary = $this->buildDictionary($results);
 
        // Once we have the dictionary we can simply spin through the parent models to
 
// link them up with their children using the keyed dictionary to make the
 
// matching very convenient and easy work. Then we'll just return them.
 
        foreach ($models as $model) {
 
            $keys = $model->getAttribute($this->localKey);
 
            $keys = explode($this->separator, $keys);
 
            $keys = array_unique(array_filter($keys));
 
            $type = 'one';
 
            $relationResults = [];
 
            foreach ($keys as $key) {
 
                if (isset($dictionary[$key])) {
 
                    $temp = $this->getRelationValue($dictionary, $key, $type);
 
                    $relationResults[] = $temp;
 
                }
 
}
 
            $model->setRelation(
 
                $relation, collect($relationResults)
 
            );
 
        }
 
        return $models;
 
    }
 
    /**
* Get all of the primary keys for an array of models.
*
    * @param  array  $models
    * @param  string  $key
    * @return array
*/
 
    protected function getKeys(array $models, $key = null)
 
{
 
        $keysArr = [];
 
        collect($models)->map(function ($value) use ($key, &$keysArr) {
 
            $result = $key ? $value->getAttribute($key) : $value->getKey();
 
            $keysArr = array_merge($keysArr, explode(',', $result));
 
        });
 
        return collect($keysArr)->values()->filter()->unique()->sort()->all();
 
    }
 
}

在基类的模型里,继承lavarel模型类, 实现以下方法 baseModel.php

/**
* Define a one-to-many relationship From a field with comma or other separator.
*
* @param        $related
* @param null  $foreignKey
* @param null  $localKey
* @param string $separator
* @return HasManyFromStr
*/
 
public function hasManyFromStr($related, $foreignKey = null, $localKey = null, $separator = ',')
 
{
 
    $instance = $this->newRelatedInstance($related);
 
    $foreignKey = $foreignKey ?: $this->getForeignKey();
 
    $localKey = $localKey ?: $this->getKeyName();
 
    return $this->newHasManyFromStr(
 
        $instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey, $separator
 
    );
 
}
 
/**
* Instantiate a new HasManyFromStr relationship.
*
* @param Builder $query
* @param Model  $parent
* @param        $foreignKey
* @param        $localKey
* @param string  $separator
* @return HasManyFromStr
*/
 
protected function newHasManyFromStr(Builder $query, Model $parent, $foreignKey, $localKey, $separator = ',')
 
{
 
    return new HasManyFromStr($query, $parent, $foreignKey, $localKey, $separator);
 
}

实际的模型类(继承上面的模型基类)中 的关联定义如下:

public function tagList()
 
{
 
    return $this->hasManyFromStr(ErpTagModel::class, 'id', 'tag_id');
 
}

码上有钱的博客
请先登录后发表评论
  • latest comments
  • 总共0条评论