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