安装
先检查下PHP的扩展有没有开全:
- openssl
- fileinfo
## 两种安装方式:
首先确定安装了php 和 composer。安装的时候注意下使用的PHP版本。如果版本太小可能安装不成功。
第一种方式:
新建项目并安装:
d:\a> composer create-project --prefer-dist laravel/laravel blog
在a目录下新建blog目录,并安装laravel框架。
第二种方式:
1.新建目录,进入目录后在命令行下执行:
d:> cd c:\a
d:\a> composer require laravel/installer -- 只安装laravel的new模块命令
2.使用new命令新建项目:
d:\a> vendor\bin\laravel.bat new blog -- 新建目录为blog的项目,建立目录框架
d:\a> vendor\bin\laravel.bat new -- 当前目录做为项目,建立目录框架(建议使用这种方式,因为每个项目使用的Laravel框架的版本可能不同)
3.安装框架:
d:\a> composer require laravel/laravel -- 安装laravel的完整框架
## 框架安装完后的配置:
安装完后复制环境文件:
.env.example 复制为 .env
.evn文件中除了APP和LOG开头的变量全部删除。使用config目录中的php文件进行配置。
创建应用程序key,运行:
d:\a> php artisan key:generate
最后运行laravel自带的开发时的web服务器,可以看到框架的默认页
d:\a> php artisan serve
d:\a> php artisan serve --port=9867 # 指定端口启动
.env参数
APP_ENV
开发: local
测试: testing
预上线: staging
正式环境: production
引入自定义包
"repositories": {
"packagist": {
"type": "composer",
"url": "https://mirrors.aliyun.com/composer/"
}
"包名":{
"type": "vcs",
"url": "https://gitee.com/txFramework/xxx.git"
}
}
Illuminate\Support\Facades\Http
post表单
Http::withHeaders($headers)
->contentType($this->contentType)
->post($url, $data);
post原始字符串
Http::withHeaders($headers)
->contentType($this->contentType)
->send($this->method, $url, ['body'=>$data]);
postJson
Http::withHeaders($headers)
->asJson()
->contentType($this->contentType) // asJson方法会设置为contentType=application/json造成签名失败,重新设置下contentType
->post($url, $data);
参考:PHP Guzzle HTTP 请求库使用方法快速入门 - 可以替代 WP HTTP API 使用 _WordPress智库
文件上传请求
use Illuminate\Support\Facades\Http;
use GuzzleHttp\Client;
$url = 'http://localhost:9999/a.php';
$filename = 'D:\tmp\2.jpg';
方式一:
// 使用门面
$response = Http::attach('upfile', fopen($filename, 'r'), '5.jpg')->post($url, ['foo'=>'bar']);
return $response->body();
方式二:
$response = Http::asMultipart()->post($url, [
[
'name'=>'file_name',
'filename'=>'4.jpg',
'contents'=>fopen($filename, 'r')
],
[
'name'=>'link',
'contents'=>'aaaaaaaaa'
]
]);
return $response->body();
方式三:
$client = new Client();
$response = $client->request('POST', $url, [
'multipart' => [
[
'name' => 'file_name',
'filename'=>$filename,
'contents' => fopen($filename, 'r')
],
[
'name' => 'id_link',
'contents' => 'aaa'
],
]
]);
return $response->getBody();
SSL 证书问题:
SSL certificate problem: unable to get local issuer certificate
2种处理方法
1。如果内容不敏感,一个快捷的方法是使用curl_exec()之前跳过ssl检查项。
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// use Illuminate\Support\Facades\Http;
$response = Http::withoutVerifying()->withHeaders(['Referer' => $referer])->get($url);
2。下载证书
地址:https://curl.se/ca/cacert.pem
配置php.ini,搜索‘curl.cainfo’,修改如下:
curl.cainfo = "D:\phpstudy\Extensions\php\php7.3.4nts\cacert.pem"
重启服务。
Illuminate\Http\Request
上传文件
$file = $request->file('file');
$filename = $file->getClientOriginalName();
$mimeType = $file->getMimeType();
$realPath = $file->getRealPath();
获取请求原始内容
$content = $request->getContent();
获取全部json
$data = $request->json()->all();
修改视图加载路径:
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\View;
use Illuminate\View\FileViewFinder;
View::addExtension('html','blade');
$finder = new FileViewFinder(App::make ('files'), [public_path()]);
View::setFinder($finder);
return view('page.a.index');
快速复制一条记录:
$resource = Resource::find($id)->replicate();
$resource->name .= ' copy';
$resource->state = '';
$resource->current_page = 0;
$resource->save();
admin_toastr('复制成功', 'success');
Laravel 解决接口数据带T Z格式问题
model中增加方法:
protected function serializeDate(DateTimeInterface $date)
{
return $date->format($this->dateFormat ?: 'Y-m-d H:i:s');
}
参考:Laravel 解决接口数据带T Z格式问题 - 非你网
数据库结构
依赖包:composer require doctrine/dbal
参考:https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/schema-manager.html#schema-manager
$databases = DB::connection()->getDoctrineSchemaManager()->listDatabases();
$tables = DB::connection()->getDoctrineSchemaManager()->listTableNames();
$tables = DB::connection()->getDoctrineSchemaManager()->listTables();
问题:
Unknown database type enum requested, Doctrine\DBAL\Platforms\MySQL57Platform may not support it.
解决:
DB::getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
查询
$query = Order::where('orders.id', '>', 0);
$query1 = Status::where('current', 1)->groupBy('statusable_id')->select(['statusable_id']);
// 子查询
$query->leftjoinSub($query1, 's', 's.statusable_id', 'orders.id');
// morpMany加条件
$orders = $query->get()->each(function($value, $key){
$value->load(['status'=>function($query){
$query->where('current', 1);
}]);
});
dd($orders->toArray());
添加数据库自动更新时间字段
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddTime extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('file', function (Blueprint $table) {
$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->useCurrent()->useCurrentOnUpdate();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('file', function (Blueprint $table) {
$table->dropTimestamps();
});
}
}
在Provider中注册全局中间件
public function register()
{
$kernel = $this->app[\Illuminate\Contracts\Http\Kernel::class];
$kernel->pushMiddleware(OperationLog::class);
}
参考:https://segmentfault.com/q/1010000020301323
路由参数
echo Route::currentRouteName(); // room.index
echo Route::currentRouteAction(); // Http\Controllers\RoomController@index
以编程方式执行命令行
Artisan::call('iseed', ['tables'=>$table, '--force'=>true]);
或传整个命令字符串
Artisan::call('mail:send 1 --queue=default');
参考:
https://learnku.com/docs/laravel/8.5/artisan/10381#programmatically-executing-commands
Laravel-admin 初始安装的文件
php artisan admin:install
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (39.43ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (32.03ms)
Migrating: 2016_01_04_173148_create_admin_tables
Migrated: 2016_01_04_173148_create_admin_tables (236.58ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (19.11ms)
Database seeding completed successfully.
Admin directory was created: \app\Admin
HomeController file was created: \app\Admin/Controllers/HomeController.php
AuthController file was created: \app\Admin/Controllers/AuthController.php
ExampleController file was created: \app\Admin/Controllers/ExampleController.php
Bootstrap file was created: \app\Admin/bootstrap.php
Routes file was created: \app\Admin/routes.php
Laravel-admin 配置
.env文件
ADMIN_ROUTE_PREFIX=blog # 修改访问路径由/admin改为/blog
Laravel-admin表单保存前的操作 $form->saveing
$form->text('title', '标题');
$form->text('test', '测试');
$form->file('upfile', '上传文件')->rules('required');
$form->ignore(['test', 'upfile']); // 忽略掉不保存的字段
$form->saving(function (Form $form) {
$file = request('upfile'); // 获取被忽略掉的字段
$filename = $file->getClientOriginalName();
$extension = $file->getClientOriginalExtension();
$realpath = $file->getRealPath();
$dst_path = storage_path('app/upload/'.$extension.'/'.date('Ymd').'/');
$newname = md5($filename.time().rand(1, 1000)).'.'.$extension;
$realname = $file->move($dst_path, $newname);
// 添加整理过的字段
$form->model()->filename = $filename;
$form->model()->realname = $realname;
$form->model()->filetype = $extension;
$form->title = 'new title'; // form中的字段只能通过这种方式改,model方式无效
if ($form->isCreating()) { // 判断正在创建
$form->model()->param = '{}';
}
if ($form->isEditing()) { // 判断正在修改
$form->model()->param = '{"a":"a1"}';
}
// 报错,阻止表单保存
$error = new MessageBag([
'title' => 'title...',
'message' => 'message....',
]);
return back()->with(compact('error'));
// 成功,阻止表单保存
$success = new MessageBag([
'title' => 'title...',
'message' => 'message....',
]);
return back()->with(compact('success'));
});
$form->saved(function (Form $form) {
$newId = $form->model()->id;
// 保存完毕提示
$success = new MessageBag([
'title' => 'title...',
'message' => 'message....',
]);
return back()->with(compact('success'));
});
laravel-admin 给action传递自定义参数
use Encore\Admin\Actions\RowAction;
class MyAction extends HandleRowAction
{
public $name = '名称';
// 修改按钮样式
public function getElementClass()
{
return 'btn btn-warning '.parent::getElementClass();
}
// 增加额外的参数
public function parameters()
{
return ['key'=>$this->row->getAttribute('key')];
}
public function handle($request)
{
$key = $request->post('key'); // 额外传递的参数
return $this->response()->success('成功')->refresh();
}
public function dialog()
{
$this->confirm('确定?');
}
}
Laravel-admin 模型打印SQL
$grid->model()->getQueryBuilder()->getQuery()->dump();
$grid->model()->getQueryBuilder()->getQuery()->dd();
给URL添加参数(页码),替换掉参数原值
{{request()->fullUrlWithQuery(['page'=>1])}}
.env文件中使用JSON
# .env 配置
JSON_TEST='{"a":1, "b":2, "c":"c3"}'
<?php
$data = json_decode(env('JSON_TEST'), true);
var_dump($data);
模型(Model)主键使用字符串类型
class User extends Model
{
protected $primaryKey = 'key'; // 字符串类型字段
public $incrementing = false;
}
模型取关联表的字段值
class User extends Model
{
use SoftDeletes;
public function userType()
{
return $this->hasOne(UserType::class, 'id', 'user_type_id');
}
}
// 使用
$user = User::find(1);
$typeName = $user->userType->title;
关联关系
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Order extends Model
{
use HasFactory;
use SoftDeletes;
public function status()
{
/**
* @param string $related 子表名
* @param string $name 子表用于关联的字段的前缀($type和$id变量的前缀,单独指定$type、$id的值时$name不起作用)
* @param string|null $type 子表的类型字段名
* @param string|null $id 子表的对应主表的ID字段名
* @param string|null $localKey 主表ID字段名
*/
return $this->morphMany(Status::class, 'statusable', 'statusable_type', 'statusable_id', 'id');
}
public function user()
{
return $this->hasOne(User::class, 'id', 'user_id');
}
}
class Status extends Model
{
use HasFactory;
use SoftDeletes;
protected $table = 'status';
public function user(){
return $this->hasOne(User::class, 'id', 'user_id');
}
}
class User extends Authenticatable
{
use HasFactory, Notifiable;
}
// 查询
private function whereHasTest(){
$query = Order::whereHas((new Status)->getTable(), function($query){
$query->where('current', 1) // 主表 exists(子表)
->whereHas('user', function($query){
$query->where('id', '>', 0); // 子表exists(子子表)
});
});
// $query = Order::with(['status'=>function($query){
// $query->where('current', 1); // 子表in(主表IDs)
// }]);
$items = $query->get();
foreach($items as $item){
print_r($item->toArray());
foreach ($item->status as $state) {
print_r($state->toArray());
print_r($state->user->toArray());
}
}
}
查询条件
$query->whereRaw('FIND_IN_SET("1",type)');
跨域包
Fruitcake\Cors
配置文件:config/cors
supports_credentials = true // 要求验证
参考:laravel fruitcake/laravel-cors 实现前后端分离 api 跨域 – 翻了车的老司机
内置服务器
php artisan serve
Laravel 队列使用
添加redis依赖
composer require predis/predis
修改.env文件
QUEUE_CONNECTION=redis # 默认值是sync(调用job时会立即执行)
REDIS_CLIENT=predis # 指定使用predis,如果不添加这行会去换phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
创建job
php artisan make:job TestQueue
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class JobTest implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $id; // 消息参数
/**
* 创建job对象,参数会被存入队列
*
* @return void
*/
public function __construct($id)
{
$this->id = $id;
Log::debug('入队时间: '.date('Y-m-d H:i:s'));
}
/**
* job被执行时调用的方法
*
* @return void
*/
public function handle()
{
Log::debug('执行时间: '.date('Y-m-d H:i:s'));
echo 'queue --> '.$this->id, PHP_EOL;
Log::debug('ID: '.$this->id);
}
}
创建一个Command往队列中添加Job
php artisan make:command TestQueue
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Jobs\JobTest;
class TestQueue extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'command:TestQueue';
/**
* The console command description.
*
* @var string
*/
protected $description = '测试队列的运行';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
JobTest::dispatch(1)->delay(3); // 队列延时3秒执行
echo 'TestQueue...';
}
}
把command添加到\app\Console\Kernel.php
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
\App\Console\Commands\TestQueue::class
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')->hourly();
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
执行命令监听队列
php artisan queue:listen
执行命令添加队列,并查看监听队列
php artisan command:TestQueue