php laravel 魔术方法,未声明属性,数组的注释 - 帮助ide跳转,提高可读性

本人使用vscode编辑器。其他编辑器未测试。

前言

用laravel开发了一段时间,最麻烦的一点就是许多时候编辑器无法智能提示和辅助跳转。

有一款ide-helper的插件,感觉不是很好用,经常会跳转到纯声明的文件中去,有时还会跳出两个选项。就想着自己写注释实现。

注释实现

魔术方法

魔术方法(以laravel orm中query,scope等方法跳转举例)- 其中query返回,静态关键字写在类型前面

/**
 * @method static self query()
 * @method self find()
 * 
 * @method self active()
 */
class Order extends Model
{
    //此处写return,无法被编辑器正确识别
    public function scopeActive($query)
    {}

}

未声明的属性

未声明的属性(以laravel orm中字段举例) - 这个关键词找了好久

/**
 * @property int $id
 */
class Order extends Model
{}

声明的属性和方法

属性: @var,比如对可以存在多种可能的属性,或帮助编辑器确认子类

/** @var \App\Models\Student */
$student = $user->role;
$student->study(); // 这会是可跳转和悬浮查看Student类中study()方法的

方法: @return,比如对ORM产生的结果集

/**
 * @return \Illuminate\Support\Collection
 */
function getDbData()
{
    return DB::get();
}
$result = getDbData();
$result->pluck('id'); // 这会是可跳转和悬浮查看Collection的pluck()方法的

数组

参考PHPDoc文档,需梯子: https://dev.to/suckup_de/modern-phpdoc-annotations-11d4

/**
 * @param array<int|string,Order>
 * @param array<int|string,mixed> 关联数组
 * @param array<int,array<int,string>> 
 * @param array<int,string[]> 二维数组
 * @param array{output:string,debug:string} 对象数组
 * @param array<int,array{output:string,debug:string}>
 * 
 * @param list<array{output:string,debug:string}>
 * 
 */
public function f()
{}

编辑器效果

image

Laravel CandyModel

根据以上的技巧,对Laravel Model进行了装饰,并且添加了一些方法糖,可供参考:

git地址

<?php

namespace Cyamz\LaravelCandy;

use DB;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Schema;

/**
 * Jump Helper
 * @method static $this|Builder query()
 * @method $this|Builder union($models)
 * @method $this|Builder unionAll($models)
 * @method $this|Builder with(...$models)
 * @method $this|Builder where($field_name, $operation, $value)
 * @method $this|Builder where($field_name, $value)
 * @method $this|Builder where($function)
 * @method $this|Builder orWhere($field_name, $operation, $value)
 * @method $this|Builder orWhere($field_name, $value)
 * @method $this|Builder orWhere($function)
 * @method $this|Builder whereRaw($raw)
 * @method $this|Builder whereHas($field_name, $function = null)
 * @method $this|Builder whereDoesntHave($field_name, $function = null)
 * @method $this|Builder whereIn($field_name, $array)
 * @method $this|Builder whereNotIn($field_name, $array)
 * @method $this|Builder whereNull($field_name)
 * @method $this|Builder whereNotNull($field_name)
 * @method $this|Builder whereBetween($field_name, $array)
 * @method $this|Builder lock()
 * @method $this|Builder lockForUpdate()
 * @method $this|Builder groupBy($field_name)
 * @method $this|Builder orderBy($field_name, $sort_type = 'ASC')
 * @method $this|Builder orderByDesc($field_name)
 * @method $this|Builder inRandomOrder()
 * @method $this|Builder select(...$fields)
 * @method $this|Builder selectRaw($raw)
 * @method $this|Builder distinct($field_name)
 * @method $this|Builder take(int $num)
 * @method $this|Builder latest(string $field = 'created_at')
 * @method $this[]|Collection get()
 * @method $this[]|Collection paginate($num)
 * @method $this|null find($id)
 * @method $this|null first()
 * @method $this firstOrNew($array)
 * @method $this firstOrCreate($array)
 * @method $this firstOrFail($array|null)
 *
 * Candy Scope Methods
 * @method $this|Builder dateBetween($field_name, $start_date = null, $end_date = null) auto add H:i:s
 * @method $this|Builder timeBetween($field_name, $start_date = null, $end_date = null) use first-hand data
 * @method $this|Builder dateGt($field_name, $date) gt date
 * @method $this|Builder dateLt($field_name, $date) lt date
 * @method $this|Builder orDateGt($field_name, $date) or gt date
 * @method $this|Builder orDateLt($field_name, $date) or lt date
 * 
 * @method $this|Builder bothLike($field_name, $value) left & right %
 * @method $this|Builder leftLike($field_name, $value) $value . '%'
 * @method $this|Builder rightLike($field_name, $value) '%' . $value
 * @method $this|Builder orBothLike($field_name, $value) or left & right %
 * @method $this|Builder orLeftLike($field_name, $value) or $value . '%'
 * @method $this|Builder orRightLike($field_name, $value) or '%' . $value
 * 
 * @method $this|Builder equalParams($request_or_array, array $equal_params) add where
 * @method $this|Builder equalExistParams($request_or_array) add where with filter
 * 
 * Candy Methods
 * @method static bool addAll($insert_data, $chunk_num = 2000) insert all(without events & timestamps)
 * @method static $this|Builder createExistAttributes($data, $fill_fields = []) create without casts event & with filter
 * @method $this|Builder fillExistAttributes($data, $fill_fields = []) fill without save event & with filter
 * 
 */
class CandyModel extends Model
{
    public $timestamps = true;
    const CREATED_AT = 'created_at';
    const UPDATED_AT = 'updated_at';

    protected $guarded = [];

    /**
     * date format
     *
     * @param \DateTimeInterface $date
     * @return string
     */
    protected function serializeDate(\DateTimeInterface $date)
    {
        return $date->format('Y-m-d H:i:s');
    }

    /** like scopes */
    public function scopeBothLike($query, $field_name, $value)
    {
        return $query->where($field_name, 'like', '%' . $value . '%');
    }
    public function scopeLeftLike($query, $field_name, $value)
    {
        return $query->where($field_name, 'like', $value . '%');
    }
    public function scopeRightLike($query, $field_name, $value)
    {
        return $query->where($field_name, 'like', '%' . $value);
    }
    public function scopeOrBothLike($query, $field_name, $value)
    {
        return $query->orWhere($field_name, 'like', '%' . $value . '%');
    }
    public function scopeOrLeftLike($query, $field_name, $value)
    {
        return $query->orWhere($field_name, 'like', $value . '%');
    }
    public function scopeOrRightLike($query, $field_name, $value)
    {
        return $query->orWhere($field_name, 'like', '%' . $value);
    }

    /** time scopes */
    public function scopeDateBetween($query, $field_name, $start_date = null, $end_date = null)
    {
        if (!empty($start_date)) {
            $query->where($field_name, '>=', $start_date . ' 00:00:00');
        }

        if (!empty($end_date)) {
            $query->where($field_name, '<=', $end_date . ' 23:59:59');
        }

        return $query;
    }
    public function scopeTimeBetween($query, $field_name, $start_time = null, $end_time = null)
    {
        if (!empty($start_time)) {
            $query->where($field_name, '>=', $start_time);
        }

        if (!empty($end_time)) {
            $query->where($field_name, '<=', $end_time);
        }

        return $query;
    }
    public function scopeDateGt($query, $field_name, $date)
    {
        return $query->where($field_name, '>=', $date . ' 00:00:00');
    }
    public function scopeDateLt($query, $field_name, $date)
    {
        return $query->where($field_name, '<=', $date . ' 23:59:59');
    }
    public function scopeOrDateGt($query, $field_name, $date)
    {
        return $query->orWhere($field_name, '>=', $date . ' 00:00:00');
    }
    public function scopeOrDateLt($query, $field_name, $date)
    {
        return $query->orWhere($field_name, '<=', $date . ' 23:59:59');
    }

    /** where scopes */
    public function scopeEqualParams($query, $data, $equal_params)
    {
        if (!is_array($data)) {
            $data = $data->toArray();
        }

        foreach ($equal_params as $param_name) {
            if (isset($data[$param_name])) {
                $query->where($param_name, $data[$param_name]);
            }
        }

        return $query;
    }
    public function scopeEqualExistParams($query, $data)
    {
        if (!is_array($data)) {
            $data = $data->toArray();
        }

        $params = Schema::getColumnListing($this->getTable());
        foreach ($params as $param_name) {
            if (isset($data[$param_name])) {
                $query->where($param_name, $data[$param_name]);
            }
        }

        return $query;
    }

    /**
     * insert all(without events & timestamps)
     *
     * @param array $insert_data
     * @return bool
     */
    public static function addAll($insert_data, $chunk_num = 2000)
    {
        if ($insert_data) {
            $arr = array_chunk($insert_data, $chunk_num);

            DB::beginTransaction();
            foreach ($arr as $insert_group) {
                $flag = DB::table(self::getModel()->getTable())->insert($insert_group);
                if (!$flag) {
                    DB::rollBack();
                    return false;
                }
            }
            DB::commit();
        }

        return true;
    }

    /**
     * fill without save event & with filter
     *
     * @param array|Model $data
     * @return $this
     */
    public function fillExistAttributes($data, $fill_fields = [])
    {
        if (!is_array($data)) {
            $data = $data->toArray();
        }

        $columns = Schema::getColumnListing($this->getTable());
        unset($columns[0]); //id

        if ($fill_fields) {
            $columns = array_intersect($columns, $fill_fields);
            $columns = array_unique($columns);
        }

        foreach ($columns as $column) {
            if (in_array($column, ['created_at', 'updated_at'])) {
                continue;
            }
            if (isset($data[$column])) {
                $this->{$column} = $data[$column];
            }
        }
        return $this;
    }

    /**
     * create without casts event & with filter
     *
     * @param array|model $data
     * @return \Illuminate\Database\Eloquent\Model|$this
     */
    public static function createExistAttributes($data, $fill_fields = [])
    {
        if (!is_array($data)) {
            $data = $data->toArray();
        }

        $columns = Schema::getColumnListing(self::getModel()->getTable());
        unset($columns[0]); //id

        if ($fill_fields) {
            $columns = array_intersect($columns, $fill_fields);
            $columns = array_unique($columns);
        }

        $create_data = [];
        foreach ($columns as $column) {
            if (in_array($column, ['created_at', 'updated_at'])) {
                continue;
            }
            if (isset($data[$column])) {
                $create_data[$column] = $data[$column];
            }
        }

        return self::query()->create($create_data);
    }

}
posted @ 2022-03-16 08:15  cy_b  阅读(540)  评论(0编辑  收藏  举报