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');

}


作者:linlancer
链接:https://www.jianshu.com/p/882aa5eec382
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值