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() {}
编辑器效果
Laravel CandyModel
根据以上的技巧,对Laravel Model进行了装饰,并且添加了一些方法糖,可供参考:
<?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); } }