Laravel 开发笔记

Laravel 笔记

前言

记录 Laravel 开发中的问题,及笔记。

用法

Validator 类的用法

用法如下:

    /**
     * 修改用户信息
     * @route   api/user/modify
     * @method  post
     * @param   Request $request
     * @return \Illuminate\Http\JsonResponse
     */
     
use Illuminate\Support\Facades\Validator;

    public function modifyUserInfo(Request $request)
    {
        //自定义验证错误信息
        $messages  = [
            'password.regex'       => '密码必须为6-25位',
            'avatar.url'           => '头像必须为有效的url地址',
            'birthday.date_format' => '生日必须为 YYYY-mm-dd 格式',
        ];
        
        //验证
        $validator = Validator::make($request->all(), [
            'password' => 'regex:/^.{6,25}$/', //正则验证 如有多条不能用| 必须是数组 ['required','regex:/^[a-zA-Z0-9]$/']
            'avatar'   => 'url',
            'birthday' => 'date_format:Y-m-d',
        ], $messages);

        //以上验证通过后 继续验证
        $validator->after(function ($validator) use ($request) { //use ($request) 后,在这个闭包里可以用 $request
                    $user = User::getUserByphone($request->mobile);
                    if (!$user) {
                        $validator->errors()->add('isUser', '此用户不存在');//添加错误信息
                    }
                });

        //如果验证不通过
        if ($validator->fails()) {
            return $this->error($validator->errors()->first());
        }

        $user           = User::find($user_id);
        $user->nickname = $request->nickname;
        $user->password = User::generatePassword($request->password);
        $user->avatar   = $request->avatar;
        $user->birthday = $request->birthday;

        try {
            $user->save();
            return $this->success("操作成功");
        } catch (\Exception $ex) {                  //\Exception 捕获所有异常
            return $this->error($ex->getMessage()); // getMessage() 异常信息
        }

    }

Faker 生成测试数据

打开 app/database/factories/ModelFactory.php 用法如下:

$factory->define(App\User::class, function (Faker\Generator $faker) {
    $faker = Faker\Factory::create('zh_CN'); //中文包
    return [
        'openid'       => str_random(10),
        'nickname'     => $faker->name,  //中文姓名
        'mobile'       => $faker->phoneNumber,
        'avatar'       => $faker->imageUrl(),     //图片URL地址
        'integral'     => $faker->randomNumber(3), //随机3位整型(0-999)
        'balance'      => $faker->randomFloat(2, 0, 10000), //随机浮点数,2位小数点,最小0,最大10000
        'birthday'     => $faker->date(), //日期
        'created_time' => $faker->unixTime(), //unix时间戳
        'password'     => App\User::generatePassword('haha123'), //可用模型方法生成数据
    ];
});

$factory->define(App\Product::class, function (Faker\Generator $faker) {
    $faker  = Faker\Factory::create('zh_CN');
    //用模型生成要关联随机的数组
    $seller = App\Seller::where('status', 1)->get()->toArray();
    foreach ($seller as $value) {
        $row[] = $value['id'];
    }
    return [
        'product_no'   => $faker->randomNumber(8),
        'name'         => '【测试商品】' . $faker->streetName,
        'cate_id'      => random_int(1, 6), //1-6随机int
        'seller_id'    => $faker->randomElement($row),//随机数组
        'mod_id'       => random_int(1, 10),
        'price'        => $faker->randomFloat(2, 1, 500),
        'weight'       => random_int(1, 100),
        'img'          => $faker->imageUrl('480','480'),//宽480 高480 的图片URL
        'thumb'        => $faker->imageUrl('480','480'),
        'content'      => '【测试商品内容】' . $faker->text(),
        'is_point'     => random_int(0, 1),
        'is_new'       => random_int(0, 1),
        'is_recommend' => random_int(0, 1),
        'is_sale'      => random_int(0, 1),
        'create_time'  => $faker->unixTime(),
    ];
});

$factory->define(App\Seller::class, function (Faker\Generator $faker) {
    $faker = Faker\Factory::create('zh_CN');
    $user  = App\User::all()->toArray();
    foreach ($user as $value) {
        $row[] = $value['id'];
    }
    return [
        'user_id'     => $faker->randomElement($row),
        'seller_name' => $faker->colorName,  //很有意境的中文色彩名
        'corporate'   => $faker->imageUrl(),
        'business'    => $faker->imageUrl(),
        'create_time' => $faker->unixTime(),
    ];
});

然后用 php artisan tinker 进入 laravel 命令行

factory(App\Product::class,50)->create(); //生成 50 条 存入数据库
factory(App\User::class,50)->make();      //生成 50 条 不存入数库

模型文件

用法如下:

class Seller extends Model
{
    protected $table = 'seller';    //定义表名
    protected $hidden = ['corporate', 'business', 'province', 'city', 'county', 'address'];    //all()方法不会被返回的字段
    protected $appends = ['nickname', 'mobile']; //额外添加的返回信息 配合getColumnAttribute()方法得到。注意命名,如 nick_name 就是getNickNameAttribute()
    protected $dates = ['create_time']; //需要被转换成日期的属性 Carbon 类
    public $timestamps = false;     //保存时不自动生成 created_at 与 updated_at 字段
    

    public function getNicknameAttribute()
    {
        return $this->hasOne('App\User', 'id', 'user_id')->value('nickname'); // hasOne 一对一关系 id 是 to 表 user_id 是 本表
    }

    public function getCreateTimeAttribute()
    {
        $value = $this->attributes['create_time'];
        return $value ? date('Y-m-d H:i:s', $value) : '';
    }

    public function getMobileAttribute()
    {
        return $this->hasOne('App\User', 'id', 'user_id')->value('mobile');
    }

}

中间件用法

注册中间件,打开 app/Http/Kernel.php 用法如下:

class Kernel extends HttpKernel
{
    /**
     * 全局中间件
     */
    protected $middleware = [
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        //\App\Http\Middleware\VerifyCsrfToken::class,
        \Lib\ClusterSession\Middleware\StartSession::class,
    ];

    /**
     * 路由中间件
     */
    protected $routeMiddleware = [
        'access_control' => \App\Http\Middleware\AccessControl::class,
        'api' => \App\Http\Middleware\Api::class,
        'auth' => \App\Http\Middleware\Authenticate::class, //别名
        'admin_auth' => \App\Http\Middleware\AdminAuthenticate::class,
        'server_auth' => \App\Http\Middleware\ServerAuthenticate::class,
        'CORS' => \App\Http\Middleware\CORS::class
    ];
}

创建 app/Http/Middleware/Authenticate.php 文件,如下:

class Authenticate
{
    public function handle($request, Closure $next)
    {
        $value = SessionManager::get('user_id', null);

        if(empty($value)){
            return response()->json(['error' => '999', 'message' => '请先登录']);
        }

        return $next($request); //如果通过,去下一个请求
    }


}

routes.php 中使用,如下:

// prefix 路由分组,middleware 中间件
Route::group(['prefix' => 'api', 'middleware' => ['access_control', 'api', 'CORS']], function () {
    Route::post('/user/info', ['uses' => 'Api\UserController@info', 'middleware' => ['auth']]);//用户中心
    Route::get('/user/address', ['uses' => 'Api\UserController@UserAddress', 'middleware' => ['auth']]);//个人收货地址列表
    Route::get('/user/address/info', ['uses' => 'Api\UserController@UserAddressInfo', 'middleware' => ['auth']]);//获取收货地址详情
    Route::post('/user/address/post', ['uses' => 'Api\UserController@UserAddressPost', 'middleware' => ['auth']]);//获取收货地址详情
    Route::post('/user/address/delete', ['uses' => 'Api\UserController@UserAddressDelete', 'middleware' => ['auth']]);//获取收货地址详情
    Route::post('/user/modify', ['uses' => 'Api\UserController@modifyUserInfo', 'middleware' => ['auth']]);//获取收货地址详情
        Route::post('/message/send', 'Api\SmsController@send');//发送短信
        Route::post('/upload/configure', 'Api\DefaultController@upload');//发送短信
    
        Route::post('/user/register', 'Api\UserController@register');//用户注册接口
        Route::post('/user/login', 'Api\UserController@login');//用户注册接口
        Route::post('/user/signout', 'Api\UserController@signout');//退出接口
}

事务用法

数据库引擎必须为 InnoDB 用法如下:

public function test(Request $request){    
    $car = new Car();
    $car->user_id        = $request->get('user_id');
    $car->product_id     = $request->get('product_id');
    $car->product_sku_id = $request->get('product_sku_id');
    $car->product_num    = $request->get('product_num');
        
        DB::beginTransaction();  //开始
        try
        {
            $car->save();
            $success = 1;
        }catch (\Exception $ex){
            DB::rollback();     //回滚
            $success = 0;
            
        }
        DB::commit();           //提交
return $success ? $this->success("操作成功") : $this->error("操作失败");
}

问题

paginate 分页

看文档以为最后的数据是 data ,其实是 items 方法,如下:

 public function showApi(Request $request)
    {

        $limit = $request->get('limit');
      //$page  = $request->get('page');
        $results = Seller::paginate($limit); //无须接收 $page ,laravel 自动接收
      //$results = Seller::forPage($page,$limit)->get();  或者用这种 
        return response()->json(['code' => 0, 'data' => $results->items(), 'count' => $results->total()]);
    }

临时显示隐藏属性

Laravel 5.1 中没有makeVisible 和 makeHidden 方法来临时显示或隐藏属性,打开 /vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php 文件。添加如下两个方法:

    public function makeVisible($attributes = null)
    {
        $attributes = is_array($attributes) ? $attributes : func_get_args(); //func_get_args() 把函数接收到的参数转为数组

        $arr = array_diff($this->hidden,$attributes);  //array_diff($arr1,$arr2) 计算数组差集 这里用作删除元素,如: 
        //$arr1 = ['0' =>'a','1'=> 'b','2'=>'c']; 
        //$arr2 = ['0' => 'b'];
        //return array_diff($arr1,$arr2);
        // ['0'=>'a','2'=>'c'];

        $this->hidden = $arr;

        return $this;  //由于最后return $this; 此方法在末尾调用有效
    }

    public function makeHidden($attributes = null)
    {
        $attributes = is_array($attributes) ? $attributes : func_get_args();

        $visible = array_diff($this->visible,$attributes);
        $appends = array_diff($this->appends,$attributes);
        $hidden = array_merge($this->hidden,$attributes);

        $this->visible = $visible;
        $this->appends = $appends;
        $this->hidden = $hidden;

        return $this;
    }

只能用于 find 方法,where 构造查询报错,我也很绝望啊。示例:

public function test(Request $request)
{
    $id = $request->get('id');
    
    $pro = Product::find($id)->makeHidden('seller_id');
    return response()->json($pro);
}

树状分类


public static function tree($data,$pid=0,$level=0){
        $results = array();
        foreach ($data as $value){
        // 递归点 如果当前记录的父 id 等于传入的父 id ,说明这个记录是传入父 id 的子级
            if($value['p_id'] == $pid){
                $value['level'] = $level;
                //递归调用,获得子级下的子级
                $value['children'] = self::tree($data,$value['id'],$level + 1);
                //push把以上结果赋给返回数据
                $results[] = $value;
            }
            //递归出口:遍历完成。
        }
        //返回结果集
        return $results;
    }
    

自增字段值

相当于 update table set column = column + :value where user_id = :user_id ,用法如下:


        $car = Car::where('user_id',$user_id)->where('product_id',$product_id)->where('product_sku_id',$product_sku_id)->first();
        if(empty($car)) {
            $car = new Car();
            $car->user_id        = $user_id;
            $car->product_id     = $product_id;
            $car->product_sku_id = $product_sku_id;
            $car->product_num    = $product_num;
        }else{
            $car->increment('product_num',$product_num); //自增字段值
        }

模型括号查询

相当于 select * from queue_second_sold where status=0 and (buy_user_id = 341 or (sell_user_id = 341 and buy_user_id != 0)) order by id desc,用法如下:

    /**
     * 交易大厅-定向交易
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function soldList(Request $request){
        $type = $request->get('type',0);    //交易大厅
        $limit = $request->get('limit',10);
        $user = User::getUserInfo();
        if($type == 1){                     //定向交易
            $results = QueueSecondSold::where('status',0)
            ->where(function($query) use ($user){
                $query->where('sell_user_id',$user->id)
                ->where('buy_user_id','!=',0);
            })->orWhere('buy_user_id',$user->id)
            ->orderBy('id','desc')->paginate($limit);

        }else{
            $results = QueueSecondSold::where('status',0)->where('buy_user_id',0)->orderBy('id','desc')->paginate($limit);
        }

        return $this->success(['result'=>$results->items(),'total'=>$results->total(),'page'=>$results->currentPage(),'pages'=>$results->lastPage(),'user_id'=>$user->id]);
    }

模型连接查询

相当于 select count(*) from user as a left join chunk as b on a.id=b.user_id where a.parent_id = 341

$chunk_count = User::leftJoin('chunk','user.id','=','chunk.user_id')->where('user.parent_id',$user->parent_id)->count();

列值查询

$search_user = User::where('mobile','like','%'.$mobile.'%')->get()->pluck('id');

ElasticSearch 问题及用法

出现 index.max_result_window 报错的解决办法

curl -XPUT "http://localhost:9200/my_index/_settings" -d '{ "index" : { "max_result_window" : 100000000 } }'

搜索封装

public static function SearchAccountLogEs($must = array(),$must_not = array(),$should = array(),$aggs = array(),$size = 10,$page = 1,$sort = array(),$debug = false){
        $index = Config::get('elasticsearch.index');
        $type = 'accountlog';
        $must = $must ?? array();
        $must_not = $must_not ?? array();
        $should = $should ?? array();
        $aggs = $aggs ?? array();
        $sort = $sort ?? array();
        $from = ($page - 1) * $size;
        $params = [
            'index'=>$index,
            'type' => $type,
            'body'=>[
                'query'=>[
                    'bool'=>[
                        'must'=>$must,
                        'must_not'=>$must_not,
//                        'should' => $should
                        ]
                    ]
//                'aggs'=>$aggs,
                ],
            'size' => $size,
            'from' => $from
        ];
        
        $client = ClientBuilder::create()
            ->setHosts( Config::get( 'elasticsearch.hosts' ) )
            ->setRetries( 2 )
            ->build();
        if(!empty($aggs)){
            $params['body']['aggs'] = $aggs;
        }
        if(!empty($should)){
            $params['body']['query']["bool"]["should"] = $should;
            $params['body']['query']["bool"]["minimum_should_match"] = 1;
        }
        if(!empty($sort)){
            $params['body']['sort'] = array($sort);
        }
        if($debug == true)
            return $params;
        $response = $client->search($params);
        $results = array(
          'total' => $response['hits']['total'],
//            key($aggs) => $response['aggregations'][key($aggs)]['value']
        );
        if (!empty($aggs)){
            $results[key($aggs)] = $response['aggregations'][key($aggs)]['value'];
        }
        $results['data'] = [];
        foreach ($response['hits']['hits'] as $key => $value){
            $results['data'][] = $value['_source'];
        }

        return $results;
    }

更新封装

public static function updateAccountLogEs($log)
    {
        $other = User::find($log->user_id);
        //更新ES索引
        $client = ClientBuilder::create()
            ->setHosts(Config::get('elasticsearch.hosts'))
            ->setRetries(2)
            ->build();
        $index = Config::get('elasticsearch.index');
        $type = 'accountlog';

        $params = [
            'index' => $index,
            'type'  => $type,
            'id'    => $log->id
        ];

        try {
            $client->delete($params);
        }catch (\Exception $ex){}

        $params = [
            'index' => $index,
            'type' => $type,
            'id' => $log->id,
            'body' => [
                'id' => $log->id,
                'user_id' => $log->user_id,
                'user_money' => $log->user_money,
                'user_money1' => $log->user_money1,
                'user_money3' => $log->user_money3,
                'frozen_money' => $log->frozen_money,
                'letter_of_credit' => $log->letter_of_credit,
                'shop_letter_credit' => $log->shop_letter_credit,
                'rank_points' => $log->rank_points,
                'pay_points' => $log->pay_points,
                'created_time' => $log->time,
                'info' => $log->info,
                'province_id' => $other->province_id,
                'city_id' => $other->city_id,
                'county_id' => $other->county_id,
                'industry_id' => $other->industry_id,
                'parent_id' => $other->parent_id,
                'type' => $log->type
            ]
        ];

        $client->index($params);
    }

Laravel-Excel 插件用法

安装

1.composer 安装

composer require "maatwebsite/excel:~2.1.0"

2.安装完成后,修改 config/app.phpproviders 数组内追加如下内容

Maatwebsite\Excel\ExcelServiceProvider::class,

3.同时在 aliases 数组内追加如下内容:

'Excel' => Maatwebsite\Excel\Facades\Excel::class,

4.生成配置文件 config/excel.php :

php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider"

用法

解析 Excel 文件

ini_set ('memory_limit', '1024M');
$data = Excel::load('excel.xlsx',function ($reader){
        },'UTF-8')->toArray();

将数据导成 Excel 文件

// 导出 Excel 并能直接在浏览器下载
# $export_file_name = 要生成的文件名
Excel::create($export_file_name, function ($excel) {
    $excel->sheet('Sheetname', function ($sheet) {
        $sheet->appendRow(['name', 'age']);
        $sheet->appendRow(['LiLei', '22']);
        $sheet->appendRow(['HanMeimei', '22']);
    });
})->download('xls');

// 导出 Excel 并存储到指定目录
Excel::create($export_file_name, function ($excel) {
    $excel->sheet('Sheetname', function ($sheet) {
        $sheet->appendRow(['name', 'age']);
        $sheet->appendRow(['LiLei', '22']);
        $sheet->appendRow(['HanMeimei', '22']);
    });
})->store('xls', $path);

你可能感兴趣的:(Laravel 开发笔记)