PHP 之 Laravel 框架

一. 入门指南

1. 安装和配置

在创建 Laravel 项目之前,要先在本地机器上安装 PHPComposer。Composer 是用来管理 PHP 依赖关系的工具,相当于 Node.js 的 npm 。
安装 PHP 和 Composer 后,可以通过 create-project 命令创建一个新的 Laravel 项目:

composer create-project laravel/laravel example-app

当应用程序创建完成后,可以通过 Artisan CLI 的 serve 命令来启动 Laravel 的本地服务:

cd example-app
	
php artisan serve

Laravel 的配置选项值在 .env 文件中定义,可以使用 env() 函数来获取配置值。

2. 目录结构

  • app:应用程序的核心代码
    • Console:自定义 Artisan 命令,通过php artisan make:command命令创建
    • Http
      • Controllers:控制器,处理进入应用程序的请求的逻辑 php artisan make:controller
      • Middleware:中间件 php artisan make:middleware
    • Models:所有 Eloquent 模型类, 每个数据库表都有一个相应的模型,用于与该表进行交互。 php artisan make:model
  • config:应用程序的配置信息
    • app.php:全局配置(aliases:类别名映射,为常用类提供简化的访问方式)
    • database.php:配置数据库连接信息
  • public
    • index.php:所有进入应用程序请求的入口文件
  • resources
    • views:前端页面的视图文件
  • storage
    • logs:运行日志
  • routes:路由

二. 后端开发

1. 路由

<?php

use Illuminate\Support\Facades\Route;

// prefix:路由前缀
// namespace:该路由所属控制器的命名空间
// middleware:中间件,要求以下接口登录后才能请求
// group:路由组
Route::prefix('app')->namespace('App')->middleware('login')->group(function () {
	Route::get('/', 'HomeController@index');
	Route::prefix('book')->group(function () {
		Route::get('/list', 'BookController@list');
		Route::get('/{id}', 'BookController@show')->where('id', '[0-9]+');		// 对路由参数进行正则表达式约束
	});
	Route::post('/user/login', 'UserController@login');
});

2. 中间件

Laravel 通过中间件来检查和过滤进入应用程序的 HTTP 请求。如中间件 login,用于验证用户是否已经登录。如果用户未登录,中间件会将用户重定向到登录页面,如果用户已登录,中间件才允许请求进一步进入应用程序。

<?php

namespace App\Http\Middleware;
use Closure;

class CheckUserLogin
{
	// 在应用程序处理请求之前执行
    public function handle($request, Closure $next)
    {
    	if ($request->isLogin == 0) {
			return redirect('login');
		}
        return $next($request);
    }
}

可以使用 make:middleware CheckUserLoginArtisan 命令在 app/Http/Middleware 目录中创建新的中间件。在 Kernel.php 中的 $routeMiddleware 中配置中间件的别名 'login' => \App\Http\Middleware\CheckUserLogin::class,

3. 控制器

使用make:controller BookController命令在 app/Http/Controllers 目录下新建 controller,用来处理应用程序请求和响应的逻辑。

<?php

namespace App\Http\Controllers\App;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;		// 封装了当前请求的所有相关数据
use Illuminate\Http\JsonResponse;	// Laravel中用于生成JSON格式的HTTP响应的类

class BookController extends Controller
{
	public function show(Request $request, $bid): JsonResponse
    {
		// ...
		return response()->json($data);		// 返回json
	}

	public function list(Request $request)
	{
		// ...
		return view('books', $data);	// 返回视图
	}
}

Request 类的常用方法

  • $request->isMethod('post')检查当前请求是否为指定的 HTTP 方法,返回 bool 值。
  • $request->get('age', 18);获取请求参数中指定键的值,可设置默认值。
  • $request->validate([]);表单验证,验证的规则主要有字段必填(required)、字段类型(string / numeric / email / url )、字段的值必须在给定的列表中(in:1,2)、字段的值于另一字段的值一致(same:password 验证再次输入密码)
$validatedData = $request->validate([
  'name' => 'required|string|max:255',
  'email' => 'required|email|unique:users',
  'password' => 'required|min:8',
  'age' => '',
]);
  • $request->file('photo')->isValid()检查上传文件是否有效。

三. Blade 模板

Blade 模板文件使用 .blade.php 作为文件扩展名,被存放在 resources/views 目录。
Blade 视图使用全局 view() 函数从控制器返回。

1. 模板继承

Blade 通过 @yield 和 @session 命令来继承布局。
首先定义一个主页面布局,@yield 指令用来显示指定部分的内容:

<!-- 位于 resources/views/layouts/app.blade.php -->
<html>
  <head>
    <title>App Name - @yield('title')</title>
  </head>
  <body>
    <header>
      <!-- 头部内容 -->
    </header>

    <main>
      @yield('content')
    </main>

    <footer>
      <!-- 底部内容 -->
    </footer>
  </body>
</html>

然后定义一个继承此布局的子页面,@extends 指令指定子页面要继承的视图,使用 @section 指令向布局片段注入内容:

<!-- 位于 resources/views/child.blade.php -->

@extends('layouts.app')

@section('title', 'Page Title')

@section('content')
    <p>This is my body content.</p>
@endsection

2. 数据显示

  • 将变量放在花括号{{ $name }}中在视图中展示数据
  • 如果变量中包含 HTML 标签,要想被解释为相应元素而不是输出为字符串,可以使用{{!! $name !!}}语法。
  • 要想在视图中显示 JavaScript 变量,可以将 HTML 嵌入到 @verbatim 指令中。
@verbatim
<div>{{ name }}</div>
@endverbatim

3. 控制结构

  • if 判断
    @if ... @elseif ... @else ... @endif
  • 循环
    @foreach($items as $item) ... @endforeach,循环内部可以使用 @loop 变量来获取当前循环的迭代信息。
  • 注释
    {{-- 注释内容不会返回到 HTML --}}
  • 包含子视图:可以将重复部分的视图抽出来形成子视图,然后通过 @include 在需要的地方引入
    @include('header')

4. 组件

三. 数据库

Laravel 中,可以使用原生 SQL,查询构造器,以及 Eloquent ORM 等方式与数据库交互。
Laravel 数据库服务的配置位于 config/database.php 配置文件中。

1.原生 SQL

在 Laravel 中,可以通过 DB Facade 来执行原生 SQL,DB Facade 为每种类型的操作都提供了对应的方法,如:insert、select、update、delete 等。

use Illuminate\Support\Facades\DB;

$users = DB::select('select * from users where id = ?', [1]);

除了使用 ?表示参数绑定外,你还可以使用命名绑定的形式来执行一个查询:

$users = DB::select('select * from users where id = :id', ['id' => 1]);

select 方法将始终返回一个包含查询结果的数组。数组中的每个结果都对应一个数据库记录的 stdClass 对象:

foreach ($users as $user) {
    echo $user->name;
}

2. 查询构造器

Laravel 可以使用 DB facade 里的 table 方法来开始查询。table 方法为给定的表返回一个查询构造器实例,允许在查询上链式调用更多的约束,最后使用 get 方法获取结果。

$users = DB::table('users')->where('id', 1)->get();
foreach ($users as $user) {
  echo $user->name;
}

get 方法返回一个包含 Illuminate\Support\Collection 的结果,其中每个结果都是 PHP StdClass 对象的一个实例。
如果只需要从数据表中获取一行数据,你可以使用 first 方法。该方法返回一个 StdClass 对象:

$users = DB::table('users')->where('id', 1)->first();
echo $user->name;

Collection 集合

  • 在 Laravel 中, Collection 类是一个强大且灵活的工具,主要用来处理和操作数组数据,它提供了许多便捷的方法来对数组进行过滤、排序、映射等操作。
  • 集合提供了一种 链式操作 的方式,允许在一个语句中依次应用多个操作。而集合的方法通常返回一个新的集合,这意味着原始集合不会被修改。这种 不可变性 可以确保在链式操作中不改变原始数据,并且方便进行多次重复操作。
  • Collection 常用方法
    • groupBy()
    • pluck(): 返回集合中指定键对应的所有值
    • sortBy()、sortByDesc()
    • where()、whereIn() / whereNotIn()、whereBetween() / whereNotBetween()、whereNull() / whereNotNull()
    • whereDate()

查询构造器具体查询的语法可以和 Sql 语句对比学习:

use Illuminate\Support\Facades\DB;

$users = DB::table('users')
	->select(['users.id', 'users.name', 'orders.order_number'])
    ->join('orders', 'users.id', '=', 'orders.user_id')		// join(inner join) / leftJoin
    ->where('users.status', 'active')
    ->orWhere('users.status', 'pending')
    ->groupBy(['users.id'])
    ->having('user_count', '>', 5)
    ->whereBetween('orders.total_amount', [1000, 5000])
    ->orderBy('users.created_at', 'desc')	// 也可以使用 orderByDesc('users.created_at')
    ->offset(5)		
    ->limit(10)		// 也可以使用 ->skip(5)->take(10)
    ->get();
SELECT users.id, users.name, orders.order_number
FROM users
	JOIN orders ON users.id = orders.user_id
WHERE (users.status = 'active'
		OR users.status = 'pending')
	AND orders.total_amount BETWEEN 1000 AND 5000
GROUP BY users.id
HAVING user_count > 5
ORDER BY users.created_at DESC
LIMIT 5, 10;

3. 分页

查询构造器可以通过 paginate 方法对结果进行分页。
控制器逻辑:

$users = User::paginate(10); // 每页显示10条记录

return view('users.index', compact('users'));	// compact('users') 相当于 ['users' => $users]

视图文件:

<table>
  <tr>
      <th>ID</th>
      <th>Name</th>
      <th>Email</th>
  </tr>
  @foreach ($users as $user)
      <tr>
          <td>{{ $user->id }}</td>
          <td>{{ $user->name }}</td>
          <td>{{ $user->email }}</td>
      </tr>
  @endforeach
</table>

{{ $users->links() }} 		<!-- 显示分页链接 -->

4. Redis

在 laravel 中,可以通过调用 Redis facade 上的各种方法来与 Redis 进行交互。

use Illuminate\Support\Facades\Redis;

if(Redis::exists($key)){
	$result = Redis::get($key);
} else {
	Redis::setex($key, 300, $data);
}

四. Eloquent ORM

Laravel 的 Eloquent 模块,是一个对象关系映射 (ORM:Object-Relational Mapping)。在使用 Eloquent 时,数据库中每张表都有一个相对应的” 模型” 用于操作这张表。

1. 增删改查

1)模型类

通过 php artisan make:model User命令生成模型类,生成的模型会被放置在 app/Models 目录下。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;	

class User extends Model
{
   protected $table = 'users';	// 数据表名
   protected $primaryKey = 'id';	// 主键,默认为id是可以不设置
   public $timestamps = false;	// 是否自动维护时间戳,true时创建或更新数据会自动维护created_at和updated_at字段
   public $fillable = [			// 只有在该数组中列出的字段才能通过 create() 或 fill() 方法进行批量赋值
		'name',
		'age',
	];
   // ...

	use SoftDeletes;	// 启用软删除,在数据表中添加deleted_at字段
}

2)查询

一旦你创建了一个模型和 其关联的数据库表,可以将每个 Eloquent 模型视为一个强大的查询构建器。所以说查询构造器中的方法,在 Eloquent 中是通用的,只需要将 DB::table('users')替换为User即可。

3)新增

  • create()
use App\Models\User;

$user = User::create([
    'name' => 'Alice',
]);
  • save()
use App\Models\User;

$user = new User;
$user->name = 'Alice';
$user->save();
  • insert():批量插入
use App\Models\User;

$data = [
  [ 'name' => 'Alice','age' => 18], 
  [ 'name' => 'John', 'age' => 20],
];
User::insert($data);

4)更新

  • save()
use App\Models\User;

$user = User::where('id', 1);
$user->age = 18;
$user->save();
  • update():批量更新
use App\Models\User;

User::where('age', '>', 0)
	->update(['sex' => 1]);

5)删除

  • delete()
use App\Models\User;

User::where('name', 'Alice')->delete();
  • 软删除:不会删除记录,而是设置 deleted_at 属性
    要想启用软删除,需要在模型类中引用 Illuminate\Database\Eloquent\SoftDeletes,在数据表中增加 deleted_at 字段。
    软删除模型将自动从查询结果中排除,可以通过在查询上调用 withTrashed 方法来强制将软删除模型包含在查询结果中。

6)其他常用方法

  • DB::raw():在 Laravel 中使用原生 SQL
use Illuminate\Support\Facades\DB;

$result = User::query()
    ->select([DB::raw('count(*) as user_count')])
    ->where('status', 1)
    ->get();
  • increment() / decrement():列数据递增 / 递减
    User::where('id', $id)->decrement('money', n); n 没有传入时默认为1
  • count():计数
    User::where('age', 18)->count();

2. 模型关联

https://learnku.com/docs/laravel/10.x/eloquent-relationships/14889#e05dce

数据表之间通常相互关联,除了查询构造器使用 JOIN 关联数据表之外,Eloquent 还提供了多种关联类型,使关联的管理和使用更加简单。

默认情况下,Eloquent 会自动按照约定为模型类设置外键和主键。

  • 默认主键字段名为 id
  • 在一对多或多对一的从属关系中,默认外键为关联模型的小写加上 _id,如 Post 模型的外键为 user_id
  • 在多对多的关系中,在关联的两个模型之间创建中间表时,默认情况下会使用两个模型的单数形式按字母顺序拼接而成的表名,并且会分别使用这两个模型的单数形式拼接而成的 _id 作为外键。如 User 模型和 Role 模型,中间表为 role_user,分别默认外键为 role_id 和 user_id。

1)一对一

例如:一个 User 模型可能与一个 Phone 模型相关联

首先,在 User 模型中定义一个 phone 方法,在 phone 方法中调用 hasOne方法并返回结果:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasOne;

class User extends Model
{
    /**
     * 获取与用户相关的电话记录
     */
    public function phone(): HasOne
    {
        return $this->hasOne(Phone::class, 'user_id', 'id');	
        // 后两个参数分别为关联模型 Phone 模型的外键,和父模型 User 模型的主键,和默认情况一致时可以省略
    }
}

一旦定义了模型关联,就可以通过 $phone = User::find(1)->phone;来获取相关数据。

目前已经能从 User 模型访问到 Phone 模型了,要想从 Phone 模型访问到 User 模型,需要在 Phone 模型中调用 belongsTo方法来定义反向关联。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Phone extends Model
{
    /**
     * 获取与用户相关的电话记录
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id', 'id');	
        // 后两个参数分别为关联模型 Phone 模型的外键,和父模型 User 模型的主键,和默认情况一致时可以省略
    }
}

2)一对多

例如,一篇博客(Post 模型)可以有很多条评论(Comment 模型)

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Post extends Model
{
    /**
     * 获取这篇博客的所有评论
     */
    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class, 'post_id', 'id');
    }
}

在 Post 中定义 comments 方法,调用 hasMany 来获取评论集合

use App\Models\Post;

$comments = Post::find(1)->comments;

foreach ($comments as $comment) {
    // ...
}

同样,也可以在 Comment 模型中定义 post 方法,调用 belongsTo 方法来反向获取评论对应的博客信息。

3)多对多

例如,一个用户可以有多个角色,同时这些角色也可以分配给其他用户。

要定义这个关联,需要三个数据表:users、roles、role_user。其中,role_user 包括 user_id 和 role_id 字段,用来链接 users 和 roles 表。

在 User 模型中定义 roles 方法,调用 belongsToMany 方法获取用户所有的角色:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class User extends Model
{
    /**
     * 用户所拥有的角色
     */
    public function roles(): BelongsToMany
    {
        return $this->belongsToMany(
        	Role::class,
        	'role_user',	// 中间表名
        	'user_id',		// 定义此关联的模型(User)在中间表的外键名
        	'role_id'		// 另一模型(Role)在中间表的外键名
        );
    }
}

同样,也可以在 Role 模型中调用 belongsToMany 方法获取某个角色的全部用户。

由于处理多对多关系需要一个中间表,Eloquent 也提供了方法和中间表进行交互。例如,通过模型关联获取的每个 Role 模型对象,都会被自动赋予 pivot属性,它代表中间表的一个模型对象,并且可以像其他的 Eloquent 模型一样使用。

use App\Models\User;

$user = User::find(1);

foreach ($user->roles as $role) {
    echo $role->pivot->created_at;	// 这里的created_at是中间表role_user的字段
}
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值