longdhdev/project_holaframework

一个简单的PHP框架

v1.0.9 2024-08-14 12:09 UTC

This package is auto-updated.

Last update: 2024-09-19 09:54:31 UTC


README

入门

composer create-project longdhdev/project_holaframework
composer install

版本v1.0.9的新功能

  • 添加依赖注入
  • 重构命名空间
  • 模型改进
  • 在模型中添加保存、软删除、分页、分页带计数功能
  • 添加应用程序类
  • 添加registerCommand和app()
  • 改进响应和队列
  • php版本 >= 8.0

列表

路由器

  • 在router/web.php中设置
  • 路由器将接收两个参数,第一个参数是url,第二个参数是包含控制器和控制器中函数的数组的数组
use Hola\Core\Router;
use App\Controllers\HomeController;

Router::get('/', [HomeController::class,'index']);
Router::get('/home', [HomeController::class,'index']);
  • 使用参数
use Hola\Core\Router;
use App\Controllers\HomeController;

// url {domain}/home/1
Router::get('/home/{id}', [HomeController::class,'index']); 

// url {domain}/home/detail/2
Router::get('/home/detail/{id}', [HomeController::class,'detail']); 
  • 使用带前缀的路由器
  Router::prefix('home')->group(function (){
      Router::get('/', [HomeController::class,'index']);
      Router::get('/detail', [HomeController::class,'detail']);
      Router::get('/list', [HomeController::class,'list']);
  }); 
  // The path will be 
  // https://domain.com/home
  // https://domain.com/home/detail
  // https://domain.com/home/list
  • 当你想创建另一个路由器文件时,你可以在router文件夹中创建它,然后在router/index.php中添加以下代码
  • add()函数将识别你的路径,而loadFile()函数将加载你刚刚创建的路由器文件
use Hola\Core\ConfigRouter;
$configRouter = new ConfigRouter();
$configRouter->add('api')->loadFile('api'); // https://domain.com/api
$configRouter->add('api_v2')->loadFile('api_v2'); // https://domain.com/api_2
// or 
$configRouter->add([
    'web' => 'web',
    'api_v2' => 'api'
])->work();
// https://domain.com/web
// https://domain.com/api_v2
  • 控制器中的参数
<?php
namespace App\Controllers;

class HomeController extends BaseController {
    public function index($id){
        echo $id;
    }
    public function detail($id){
        echo $id;
    }
}
  • 控制器中的请求和参数
<?php
namespace App\Controllers;
use Hola\Core\Request;

class HomeController extends BaseController {
    public function index(Request $request, $id){
        echo $id;
    }
    public function detail(Request $request, $id){
        echo $id;
    }
}

应用程序

  • 在app/Controllers文件夹中创建控制器
  • 在app/Models文件夹中创建模型
  • 在app/views文件夹中创建视图

使用控制器

  • 创建控制器
<?php
namespace App\Controllers;
use Hola\Core\BaseController;

class HomeController extends BaseController {
    public function __construct()
    {}

    public function index(){
        echo 'index';
    }
    public function store(){
        echo 'store';
    }
}
  • 如何在控制器中创建命名空间
File in folder app/Controllers -> namespace App\Controllers 
File in folder app/Controllers/{name_folder} -> namespace App\Controllers\{name_folder} 
  • 运行create controller命令
- php cli.php create:controller NameController
// or
- php cli.php create:controller folder/folder/NameController

使用模型

  • 创建模型
  • 在模型中创建函数时,将其设置为静态函数
  • 当你使用create()insert()insertLastId()函数时,将自动创建具有date_created列的日期,使用update()函数将创建具有date_updated列的日期。如果设置为false,可以关闭此功能。
  • 可以使用$date_create$date_update变量更改这两个默认日期列。
  • 如果你不使用它们,可能不需要声明这三个变量$times_auto$date_create$date_update
  • 运行create controller命令
- php cli.php create:model NameModel --table=name
<?php
namespace App\Models;
use Hola\Core\Model;

class Categories extends Model {
    protected static $tableName = 'categories';
//    protected static $times_auto = false;
//    protected static $date_create = "date_created";
//    protected static $date_update = "date_updated";
    protected static $field = [
        'id',
        'name'
    ];

    public static function index(){
        echo 'categories index';
    }
}
  • 在控制器中使用模型

=== 使用方法 1 ===

public function index(){
  $category = $this->model(Categories::class)::index();
}

=== 使用方法 2 ===

class Controller extends BaseController {
    public function __construct()
    {
        $this->model([
            Categories::class,
            Product::class
        ]);
    }
    public function listCategories(){
         $data = $this->Categories::instance()->get()->values();
         // or
         $data = $this->Categories->get()->values();
    }
    public function listProduct(){
         $data = $this->Product::instance()->get()->values();
         // or
         $data = $this->Product->get()->values();
         return $data;
    }
}

=== 使用方法 3 ===

class Controller extends BaseController {
    public function __construct()
    {}
    public function listCategories(){
         $data = Categories::instance()->get()->values();
    }
    public function listProduct(){
         $data = Product::instance()->get()->values();
         return $data;
    }
}

在模块中使用属性

  • 模型中的属性将包括set和get函数。例如,如果你想设置表中的列名,set和get函数的结构将是setAttribute{column_table}和getAttribute{column_table}
  • 以下示例代码
namespace App\Models;
use Hola\Core\Database;
use Hola\Core\Model;

class Categories extends Model {
    protected static $tableName = 'categories';
    protected static $times_auto = false;
    protected static $date_create = "date_created";
    protected static $date_update = "date_update";
    protected static $field = [
        'name',
        'view',
        'invalid'
    ];

    public function setAttributeName($value) {
        return json_encode($value);
    }

    public function getAttributeName($value) {
        return json_decode($value);
    }
}

使用视图

  • 在app/views文件夹中创建名为{name_file}.view.php的视图
  • 使用视图控制器
<?php
namespace App\Controllers;
use App\Models\Categories;
use Hola\Core\BaseController;
use Hola\Core\Request;
use Hola\Core\Response;

class HomeController extends BaseController {
    public function __construct()
    {}

    public function index(){
        return $this->render_view('name_file', ["title" => "Home"]);
    }
    // or
    public function index2(){
        return Response::view('name_file', ["title" => "Home"]);
    }
}
  • 在上面的示例视图中使用变量,在代码行中传递标题参数,可以声明如下
<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <!-- use -->
  <title><?=$title?></title>
  <!-- or use variable var -->
  <title><?=@var('title')?></title>
</head>
<body>

</body>
</html>
  • 运行create view命令
- php cli.php create:view name_view
// or
- php cli.php create:view folder/folder/name_view

使用请求

use Hola\Core\Request;
class Controller extends BaseController {
    public function __construct()
    {}
    public function index(Request $request){
         $name = $request->get('name');
         $name = $request->name; // or
         $name = $request->value('name');
         $file = $request->get_file('file');
         $set_file = $request->file('file'); // use set file
         $extension = $request->extension(); // get extension file
         $size = $request->size(); // get size file
         $type = $request->type(); // get type file
         $originName = $request->originName(); // get originName file
         $isFile = $request->isFile(); // check file
         $all = $request->all(); // get all data request
         $session = $request->session('name'); // get session 
         $cookie = $request->cookie('name'); // get cookie 
         $cookie = $request->headers('name'); // get headers 
         $has = $request->has('name'); // check key 
    }
}

使用验证请求

=== 方法 1 ===

       $validate = Validation::create(
            $request->all(),
            [
                'username' => [
                    'required',
                    'number',
                ],
                'password' => [
                    'required',
                    'number',
                    'max:6',
                    'min:6'
                ],
            ]
       );

=== 方法 2 ===

       $validate = Validation::create(
            [
                'username' => $request->username,
                'password' => $request->password
            ],
            [
                'username' => [
                    'required',
                    'number',
                ],
                'password' => [
                    'required',
                    'number',
                    'max:6',
                    'min:6'
                ],
            ]
       );

可以使用以下代码返回你的错误信息

       $validate = Validation::create(
            [
                'username' => $request->username,
                'password' => $request->password
            ],
            [
                'username' => [
                    'required' => 'Username is required',
                    'number' => 'username is number',
                ],
                'password' => [
                    'required',
                    'number',
                    'max:6',
                    'min:6'
                ],
            ]
       );

使用正则表达式

      Validation::create([
            'username' => 'long'
        ], [
            'username' => [
                'pattern:/([0-9]+)/'=> 'You must be a number',
            ]
      ]);

在控制器中使用validateRequest。如果存在编码者识别的字段,此validateRequest函数将返回错误。如果条件满足,validateRequest函数将返回用户提交的数据

<?php
namespace App\Controllers;
use Hola\Core\BaseController;
use Hola\Core\Request;
use Hola\Core\Response;
use Hola\Core\Validation;

class HomeController extends BaseController {
    public function __construct()
    {}

    public function index(Request $request){
        $validate = Validation::create(
            $request->all(),
            [
                'username' => [
                    'required'=>'Không để trống',
                    'number',
                ],
                'password' => [
                    'required',
                    'number',
                    'max:6' => 'Pass phải lớn hơn hoặc bằng {{password}}',
                    'min:6'
                ],
            ]
        );
        if(!empty($validate->errors())) { // show error
            return false;
        }
        $data = $validate->data(); // get data access
        
        return [
           'data_request' => $data
        ];
    }

}

使用表单请求

  • 运行create form request命令
 php cli.php create:request name
  • 运行命令时,它将在request文件夹中生成一个名为{name}的文件。在这个文件中,你可以验证它
<?php
namespace Request;
use Hola\Core\FormRequest;

class AuthRequest extends FormRequest
{
    public function __construct() {
        parent::__construct();
    }

    public function auth() {
        return true;
    }

    public function rules()
    {
        return [
            'username' => [
               'required'=>'Không để trống',
               'number',
            ],
            'password' => [
                'required',
                'number',
                'max:6' => 'Pass phải lớn hơn hoặc bằng {{password}}',
                'min:6'
            ],
        ];
    }

    /**
     * @return string
     * This function you can return view as you want, this function can be declared or not needed
     * If you want to use this function, you must declare the auth function first
     */
    public function view_auth() {
        return 'error.index';
    }

    /**
     * @return array
     * This function you can return data as you want, this function can be declared or not needed
     * If you want to use this function, you must declare the auth function first
     */
    public function data_auth() {
        return [
            'message' => 'unauthorized',
            'code' => 403
        ];
    }
}

可以使用规则

  • required // 检查是否为空
  • number // 检查数字
  • max // 检查最大值
  • min // 检查最小值
  • pattern// 使用正则表达式检查
  • boolean // 检查布尔值
  • array // 检查数组
  • date // 检查日期
  • not_pattern // 使用正则表达式检查

使用响应

use Hola\Core\Response;
class Controller extends BaseController {
    public function __construct()
    {}
    public function index(Request $request){
        $data = [];
        return Response::view('name_view', $data);
    }
    
    public function json(Request $request){
        $data = [];
        return Response::json($data, $status ?? 200);
    }
    public function redirectTo(Request $request){
        $data = [];
        return Response::redirectTo('/login');
    }
}
  • 在视图中使用变量
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title><?=$title ?? ''?></title> // get data
</head>

<body>
</body>
</html>

查询构建器

  • 在模型中获取一条记录
   Categories::instance()->first()->values();
  • 使用带有函数 where 的列获取一条记录
   Categories::instance()->where('id','=', 1)->first()->values(); // get by id
   Categories::instance()->where('name','=', 1)->first()->values(); // get by name
   Categories::instance()->where('name','like', '%value%')->first()->values(); // get by name
  • 在模型中获取所有记录
   Categories::instance()->get()->values();
  • 使用带有函数 where 的列获取所有记录

    get() 函数将返回一个对象。如果您想返回数组数据类型,可以使用 getArray() 函数。

   Categories::instance()->where('id','=', 1)->get()->values(); // get by id
   Categories::instance()->where('name','=', 1)->get()->values(); // get by name
   Categories::instance()->where('name','like', '%value%')->get()->values(); // get by name
       
   // return data type array
   Categories::instance()->where('id','=', 1)->getArray(); // get by id
   Categories::instance()->where('name','=', 1)->getArray(); // get by name
   Categories::instance()->where('name','like', '%value%')->getArray(); // get by name
   // version 1.0.6
   Categories::instance()->where('id','=', 1)->get()->toArray(); // get by id
   Categories::instance()->where('name','=', 1)->get()->toArray(); // get by name
   Categories::instance()->where('name','like', '%value%')->get()->toArray(); // get by name
    $data1 = Categories::instance()->select('*')->where(function (Database $q){
        $q->where('id',3)->orWhere('id',2);
    })->get()->toArray();
    
    $data2 = Categories::instance()->select('*')->where(function (Database $q){
        $q->where('id',3);
    })->orWhere(function (Database $q){
        $q->where('id',2);
    })->get()->toArray();
  • 使用 select()
   Categories::instance()->select('*')->get()->values();
   Categories::instance()->select(['*'])->get()->values();
   Categories::instance()->select(['id','name'])->get()->values();

   // with sum and count 
   Summary::instance()->select([
       'SUM(amount) as amount',
       'SUM(amount2) as amount2',
   ])->get()->values();
   Region::instance()->select([
       'COUNT(id) as number'
   ])->get()->values();
  • 使用 findById()
   Categories::instance()->findById(1); 
  • 使用 orWhere()
   Categories::instance()->where('id','=', 1)->orWhere('id','=',2)->get()->values(); 
  • 使用 whereLike()
   Categories::instance()->whereLike('name', '%long')->get()->values(); 
   Categories::instance()->whereLike('name', 'long%')->get()->values(); 
   Categories::instance()->whereLike('name', '%long%')->get()->values(); 
  • 使用 orWhereLike()
   Categories::instance()->orWhereLike('name', '%long')->get()->values(); 
   Categories::instance()->orWhereLike('name', 'long%')->get()->values(); 
   Categories::instance()->orWhereLike('name', '%long%')->get()->values(); 
  • 使用 whereIn()
   Categories::instance()->whereIn('id', [1,2])->get()->values(); 
  • 使用 orWhereIn()
   Categories::instance()->orWhereIn('id', [1,2])->get()->values(); 
  • 使用 whereNotIn()
   Categories::instance()->whereNotIn('id', [1,2])->get()->values(); 
  • 使用 orWhereNotIn()
   Categories::instance()->orWhereNotIn('name', [1,2])->get()->values(); 
  • 使用 whereBetween()
   Categories::instance()->whereBetween('date', ['2023-01-01 00:00:01','2023-12-31 23:59:59'])->get()->values(); 
  • 使用 whereRaw()
   Categories::instance()->whereRaw('id = 1 and age = 18')->get()->values(); 
  • 使用 orWhereRaw()
   Categories::instance()->where('id', 1)->orWhereRaw('id = 2')->get()->values(); 
  • 使用 join
   // way 1
   Blog::instance()->select('*')->join('categories', function ($q) {
      $q->on('categories.id','=','category_blogs.category_id');
   })->get()->values(); 
   // way 2
   Blog::instance()->select('*')->join('categories')->on('categories.id','=','category_blogs.category_id')->get()->values(); 
  • 使用 left join
   // way 1
   Blog::instance()->select('*')->leftJoin('categories', function ($q) {
      $q->on('categories.id','=','category_blogs.category_id');
   })->get()->values(); 
   // way 2
   Blog::instance()->select('*')->leftJoin('categories')->on('categories.id','=','category_blogs.category_id')->get()->values(); 
  • 使用 right join
   // way 1
   Blog::instance()->select('*')->rightJoin('categories', function ($q) {
      $q->on('categories.id','=','category_blogs.category_id');
   })->get()->values(); 
   // way 2
   Blog::instance()->select('*')->rightJoin('categories')->on('categories.id','=','category_blogs.category_id')->get()->values(); 
  • 使用 order by
   News::instance()->select('*')->orderBy('id', 'DESC')->get()->values(); // ASC, DESC
  • 使用 group by
   // way 1
   News::instance()->select('*')->groupBy('id')->get()->values(); 
   // way 2
   News::instance()->select('*')->groupBy(['field1','field2','field3'])->get()->values();
  • 使用 limit
   News::instance()->select('*')->limit(100)->get()->values();
  • 使用 limit 和 offset
   News::instance()->select('*')->page(0)->limit(100)->get()->values(); // offset 0 limit 100
   News::instance()->select('*')->page(1)->limit(100)->get()->values(); // offset 100 limit 100
   News::instance()->select('*')->page(2)->limit(100)->get()->values(); // offset 200 limit 100
  • 使用 insert
   News::instance()->insert([
       'name' => 'Test',
       'status' => 1
   ]);
       
   // returns id on successful insert
   News::instance()->insertLastId([
       'name' => 'Test',
       'status' => 1
   ]);
  • 使用 update
  • update 函数的第二个参数默认为 id
  • 如果您想使用其他列,请将其留为一个包含列键和值的数组
   News::instance()->update([
       'name' => 'New2',
       'status' => 1
   ], 1); // id

   // other key
   News::instance()->update ([
        'name' => 'New2',
        'status' => 1
   ], [
       'id' => 1,
       'name' => 'Test'
   ]); // id, name
  • 使用 update 或 insert
  • 此函数将检查数据是否存在。如果存在,则更新它;如果不存在,则插入它
  • updateOrInsert 函数的第二个参数默认为 id
  • 如果您想使用其他列,请将其留为一个包含列键和值的数组
   News::instance()->updateOrInsert([
       'name' => 'New2',
       'status' => 1
   ], 1); // id
// other key
   News::instance()->updateOrInsert([
        'name' => 'New2',
        'status' => 1
   ], [
       'id' => 1,
       'name' => 'Test'
   ]); // id, name
  • 此外,您还可以使用带有自定义函数的纯 SQL 语句
   News::instance()->query("SELECT * FROM news WHERE id = 1")->get()->values();
   News::instance()->query("SELECT * FROM news")->get()->values();
  • 或者您可以使用数据库类使用以下示例中的纯 SQL 语句
  $database = new Database();
  $database->query("SELECT * FROM categories")->fetch();
  $database->query("SELECT * FROM categories")->fetchAll();
  • 除了 insert 函数外,您还可以使用 create 函数将数据插入到表中
  • 请注意,create 函数将根据在模型内部声明的键插入列。如果您没有声明键,则在插入数据时使用 create 函数时,将忽略该列。
<?php
namespace App\Models;
use Hola\Core\Database;
use Hola\Core\Model;

class News extends Model {
    protected static $tableName = 'new';
    protected static $field = [
        'title',
        'name',
        'status',
        'date'
    ];

    public static function index(){
         News::instance()->create([
             'title' => 'title'
             'name' => 'new',
             'status' => 1,
             'date' => '2023-09-28'
        ]);
    }
}
  
  • 使用 pagination() 函数
  • 此函数将帮助缩短代码,而不是像以前那样必须使用 page() 和 limit() 函数。
  • 第一个参数将是限制,第二个参数将是页码
  • 如何使用
       News::instance()->pagination(10, 1);
  • 使用 paginationWithCount() 函数
  • 此函数将接受 2 个参数,然后页码将返回已根据设计格式化的数据表
  • 如何使用
     $result = News::instance()->paginationWithCount(10, 1);
     //  Return data
     [
         "total" => 50,
         "items" => [],
         "page" => 1,
         "limit" => $limit,
         "total_page" => 10,
     ]
  • 使用 save() 函数
  • 此函数将用于添加或更新一条记录
  • 如果对象具有已存在 id 数据,它将在数据库中更新,否则将添加一个新的对象
  • 如何使用
   $blog = new Blog();
   $blog->name = 'Hi';
   $blog->save();
  • 使用 Database 类中的 table
<?php
namespace App\Controllers;
use Hola\Core\BaseController;
use Hola\Core\Database;

class HomeController extends BaseController {
   
    public function index(){
        $all = Database::instance()->table('categories')->get()->values();
        $first = Database::instance()->table('categories')->where('id','=',1)->first()->values();
    }

}
  • 使用事务
<?php
namespace App\Controllers;
use Hola\Core\BaseController;
use Hola\Core\Database;
use App\Models\Categories;

class HomeController extends BaseController {
    public function __construct()
    {
        $this->model([Categories::class]);
    } 
   
    public function index(){
       Database::beginTransaction();
       try {
          Categories::instance()->insert(['name' => 'name1']);
          Database::commit();
       }catch (\Exception $e) {
          Database::rollBack();
       } 
    }
}
  • 使用 Database 记录 SQL
<?php
namespace App\Controllers;
use Hola\Core\BaseController;
use Hola\Core\Database;
use App\Models\Categories;

class HomeController extends BaseController {
    public function __construct()
    {
        $this->model([Categories::class]);
    } 
   
    public function index(){
       Database::enableQueryLog();
       Categories::instance()->get()->values();
       log_debug(Database::getQueryLog());
    }
}
  • 使用模型类记录 SQL
<?php
namespace App\Controllers;
use Hola\Core\BaseController;
use Hola\Core\Database;
use App\Models\Categories;

class HomeController extends BaseController {
    public function __construct()
    {
        $this->model([Categories::class]);
    } 
   
    public function index(){
       log_debug(Categories::instance()->where('id','=',1)->toSqlRaw());
    }
}
  • 使用 union
    Categories::instance()->union_all(Categories::clone())->get()->values();
    /*
     * SELECT * FROM categories 
     * UNION ALL
     * SELECT * FROM categories
     * */
    Categories::instance()->union(Categories::clone())->get()->values();
    /*
     * SELECT * FROM categories 
     * UNION 
     * SELECT * FROM categories
     */
  • 使用 subQuery
    Categories::instance()->subQuery(Categories::clone(), 'sub')->get()->values();
    /*
     * SELECT * FROM (SELECT * FROM categories) as sub 
     */
    Categories::instance()->subQuery(Categories::select('id')->clone(), 'sub')->get()->values();
     /*
     * SELECT * FROM (SELECT id FROM categories) as sub 
     */
  • 使用 collection
  • 使用 collections,您可以使用 toArraytoObjectvaluesvaluecountmapfilterpushaddchunk 等函数来操作查询构建器
    Categories::instance()->get()->values(); // get all value
    Categories::instance()->get()->toArray(); // get all value type array
    Categories::instance()->get()->toObject(); // get all value type object
    Categories::instance()->get()->value(); // get first value, use with map and filter functions
    Categories::instance()->get()->count(); // Count the amount of data
    Categories::instance()->get()->map(function ($item) {
       return $item->id;
    })->values(); // Map the data
    Categories::get()->filter(function ($item) {
       return $item->id === 1;
    })->values(); // filter data

    Categories::get()->map(function ($item) {
       return $item->id;
    })->value(); // Map the data and get one
    Categories::get()->filter(function ($item) {
       return $item->id === 1;
    })->value(); // filter data and get one
    
    // use chunk
    Categories::get()->chunk(3, function ($items) {
         foreach ($items as $item) {
            echo $item;
         }
    });

使用 relation

  • 不同类型的关联

    • 一对一
    • 一对多
    • 多对多
  • 请注意,当您使用关联时,您将始终必须声明 Relations trait。** 让我们从一对一关系开始 **

  • 一对一关系是一个非常基本的关系。例如,用户可以关联 1 个电子邮件。为了定义这种关系,我们在 User 模型上放置一个 email 方法。email 方法应该返回 hasOne 方法的结果

  • hasOne 函数将接受参数。例如,第一个参数是要调用的模型或您想连接的表的名称。第二个参数是表的外键。第三个参数将是您想与外键映射的主键。

<?php
namespace App\Models;
use Hola\Core\Model;
use Hola\Traits\Relations;

class User extends Model {
    use Relations;
    /**
     * Get the phone record associated with the user.
     */
    public function email()
    {
        return $this->hasOne(Phone::class, 'user_id', 'id');
    }
}
  • 一旦您成功使用 hasOne 创建了关联,您就可以像下面的代码一样调用它
   $email = User::instance()->with('email')->find(1)->email; // or
   $email = (new User())->email()->find(1)->email;
  • 现在,我们将定义一个在Email模型上的关系,以便我们可以访问User模型。我们使用hasOne的反向belongsTo方法
<?php
namespace App\Models;
use Hola\Core\Model;
use Hola\Traits\Relations;

class Email extends Model {
    use Relations;
    /**
     * Get the user that owns the email.
     */
    public function user()
    {
        return $this->belongsTo(User::class, 'id', 'user_id');
    }
}

** 一对多 **

  • 一对多关系用于在一种模型拥有另一种模型多个实例时定义关系。例如,一篇博客文章有许多评论。像许多其他Eloquent关系一样,一对多通过放置在模型上的函数来定义
<?php
namespace App\Models;
use Hola\Core\Model;
use Hola\Traits\Relations;

class Blog extends Model {
    use Relations;
     /**
     * Get the comments for the blog post.
     */
    public function comments()
    {
        return $this->hasMany(Comment::class, 'blog_id', 'id');
    }
}
  • 定义关系后,我们可以通过以下方式访问comments属性来获取评论集合
$comments = Blog::with('comments')->find(1)->comments; // or
$comments = (new Blog())->comments()->find(1)->comments; 
  • 现在我们可以访问所有评论,让我们定义一个关系,允许从帖子中访问评论。为了确定hasMany关系的反向,我们使用belongsTo方法
<?php
namespace App\Models;
use Hola\Core\Model;
use Hola\Traits\Relations;

class Comment extends Model {
    use Relations;
     /**
     * Get the post that owns the comment.
     */
    public function blog()
    {
        return $this->belongsTo(Blog::class, 'id', 'blog_id');
    }
}
  • 定义关系后,我们可以通过访问blog来获取Comment对应的Post模型
$blog = Comment::instance()->with('blog')->find(1)->blog; // or
$blog = (new Comment())->blog()->find(1)->blog; 

** 多对多 **

  • 多对多,比hasOne和hasMany稍微复杂一点的关系。这种关系的例子是,一个用户可以有多个角色,一个角色也属于多个用户。为了定义这种关系,需要有三个表:users、roles和user_role。user_role表将包含两个列user_id和role_id。
  • 多对多关系通过调用belongsToMany或manyToMany方法来定义。例如,让我们在User模型上定义roles方法。
<?php
namespace App\Models;
use Hola\Core\Model;
use Hola\Traits\Relations;

class User extends Model {
    use Relations;
     /**
     * The roles that belong to the user.
     */
    public function role()
    {
        return $this->belongsToMany(Role::class, 'user_role', 'user_id', 'role_id', 'id');
    }
    // way two
    public function role()
    {
        return $this->manyToMany(Role::class, 'user_role', 'user_id', 'role_id', 'id');
    }
}
  • 例如
$roles = User::with('role')->find(1)->role; // or
$roles = (new User())->role()->find(1)->role; 
  • 此外,您可以在with函数内部使用查询构建器,如下面的示例所示
  • 下面的语法将获取博客文章的id和title,这些文章在类别6中,并且浏览量大于0
<?php
  $query = Categories::with(['blog' => function ($query) {
      return $query->select('id, title')->where('view','>',0);
  }])->find(6)->value(); 
  • 默认情况下,关系将遵循一个查询的whereIn条件。如果您想更改是否进行n + 1查询,您可以像下面的代码行一样更改。
  • 将with函数的第二个参数设置为true会导致进行n + 1查询
<?php
  $query = Categories::with(['blog'], true)->find(6)->value(); 
  • 使用count和sum
$sum = Categories::sum('view')->values();
$count = Categories::count('id')->values();
  • 使用数组与collection
    $array = [
       ["id" => 1, "name" => "Name 1"],
       ["id" => 2, "name" => "Name 2"],
    ];
    $data = new \Hola\Core\Collection($array);
    $data->values(); // get all value
    $data->toArray(); // get all value type array
    $data->toObject(); // get all value type object
    $data->value(); // get first value, use with map and filter functions
    $data->count(); // Count the amount of data
    $data->map(function ($item) {
       return $item->id;
    })->values(); // Map the data and get all
    $data->filter(function ($item) {
       return $item->id === 1;
    })->values(); // filter data and get all
    $data->map(function ($item) {
       return $item->id;
    })->value(); // Map the data and get one
    $data->filter(function ($item) {
       return $item->id === 1;
    })->value(); // filter data and get one
    // use chunk
    $data->chunk(3, function ($items) {
         foreach ($items as $item) {
            echo $item;
         }
    });

使用中间件

  • 中间件将是检查请求是否前进进行处理的场所。它通常用于验证用户和许多其他事情,具体取决于您在中间件中编写的代码。
  • 要创建中间件,您将在中间件文件夹中创建它
  • 文件夹 middleware/{name}Middleware.php
  • 运行命令 create middleware
php cli.php create:middleware NameMiddleware

=== 方法 1 ===

<?php
namespace Hola\Middleware;

use Hola\Core\Response;
use Hola\Core\Session;
use Hola\Core\Request;

class Auth {
    // return with key error code in function
     public function handle(Request $request){
         if(!$request->session('auth')){
            return $request->close('Login does not exit');
         }
         return $request->next();
     }
}

=== 方法 2 ===

<?php
namespace Hola\Middleware;

use Hola\Core\Response;
use Hola\Core\Session;
use Hola\Core\Request;

class Auth {
    // return with key error code in function
     public function handle(Request $request){
         if(!$request->session('auth')){
            return [
               "error_code" => 1,
               "msg" => "Login does not exit"
            ];
         }
         return [
               "error_code" => 0
         ];
     }
}

=== 第3种方式 ===

<?php
namespace Hola\Middleware;

use Hola\Core\Response;
use Hola\Core\Session;
use Hola\Core\Request;

class Auth {
    // return boolean in function
     public function handle(Request $request){
         if(!$request->session('auth')){
            return false;
         }
         return true;
     }
}
  • 在中间件文件夹中位于Kernel.php文件中声明中间件名称
<?php
namespace Hola\Middleware;
class Kernel {
    public $routerMiddleware = [
        "auth" => \Hola\Middleware\Auth::class,
    ];
}
  • 在路由器中使用middleware
Router::middleware(['auth'])->group(function (){ // use many middleware
    Router::get('home', [HomeController::class,'index']);
});
// or
Router::middleware('auth')->group(function (){ // use one middleware
    Router::get('home', [HomeController::class,'index']);
});

使用函数

  • 使用 convert_to_array
  • convert_to_array函数将对象数据转换为数组
<?php 
     $data = new stdClass();
     $data->name = 'Long';
     $data->age = '22';
     $data = convert_to_array($data);   
      /* return
       * Array
        (
            [name] => Long
            [age] => 22
        )
       * */
?>
  • 使用 convert_to_object
  • convert_to_object函数将数组数据转换为对象
<?php 
      $data = array();
      $data['name'] = 'Long';
      $data['age'] = '22';
      $data = convert_to_object($data);
      /* return
       * stdClass Object
        (
            [name] => Long
            [age] => 22
        )
       * */
?>

使用翻译

  • 当您想创建翻译时,您可以在语言文件夹中创建一个文件,并在文件中写下语言转换键,如下所示。
  • 创建文件 vi.php
  • 您可以在config/constant.php文件中更改语言
define('LANGUAGE', 'vi');
<?php

return [
    "home" => "Trang chủ",
    "login" => "Đăng nhập"
];
  • 创建文件 ja.php
<?php

return [
    "home" => "",
    "login" => "サインイン"
];
  • 创建并添加文件中的键后,您可以根据键使用函数__()translate()来转换语言
<?php
echo __('home');
echo translate('home');
  • 您可以通过在__()translate()函数的第三个参数中更改语言
<?php
echo __('home', [], 'vi'); // print Trang chủ
echo __('home', [], 'ja'); // print 家
echo translate('home', [], 'vi'); // print Trang chủ
echo translate('home', [], 'ja'); // print 家
  • 标识翻译文件中的键
<?php

return [
    "number" => "Total: {{value}}"
];
<?php

echo __('number', ['value' => 10]); // print Total: 10

队列

  • 使用redis或数据库的队列
  • 在config/constant.php中更改队列连接
define('QUEUE_WORK', 'redis'); // use database or redis
  • 要使用队列,在队列文件夹中创建一个文件,并声明如下
  • 创建文件 Job1.php
<?php
namespace Queue;
class Job1 {
   public $params1 = 0;
   public $params2 = 0;
   public function __construct($params1, $params2)
   {
       $this->params1 = $params1;
       $this->params2 = $params2;
   }
   public function handle(){
       // code 
   }
}
  • 使用命令创建队列作业
php cli.php create:jobs SendEmail
  • 在控制器中使用
<?php
namespace App\Controllers;
use Hola\Core\BaseController;
use Hola\Core\Request;
use Hola\Core\Response;
use Hola\Queue\CreateQueue;
use Hola\Queue\Job1;

class HomeController extends BaseController {
    public function __construct()
    {}

    public function index(Request $request){
        (new CreateQueue())->enQueue(new Job1(5,6));
        return Response::view('welcome');
    }

}
  • 您可以通过连接函数更改连接,请参阅下面的代码
<?php
namespace App\Controllers;
use Hola\Core\BaseController;
use Hola\Core\Request;
use Hola\Core\Response;
use Hola\Queue\CreateQueue;
use Hola\Queue\Job1;

class HomeController extends BaseController {
    public function __construct()
    {}

    public function index(Request $request){
        (new CreateQueue())->connection('redis')->enQueue(new Job1(5,6));
        (new CreateQueue())->connection('database')->enQueue(new Job1(5,6));
        return Response::view('welcome');
    }

}
// run queue connection
 - php cli.php queue:run redis
 - php cli.php queue:run database
  • 我们已将队列名称默认为jobs。如果您想更改它,可以使用setQueue函数
 (new CreateQueue())->setQueue('name_queue1')->enQueue(new Job1(5,6));
 (new CreateQueue())->setQueue('name_queue2')->enQueue(new Job1(5,6));
 // run Queue name
 - php cli.php queue:run --queue=name_queue1
 - php cli.php queue:run --queue=name_queue2
  • 目前作业的运行时间约为10分钟,您还可以在constants.php文件中更改QUEUE_TIMEOUT常量
  • 此外,如果您不想为每个作业设置独立的时间,可以使用setTimeOut函数
    (new CreateQueue())->setTimeOut(100)->enQueue(new Job1(5,6));
  • 运行作业队列
 - php cli.php queue:run
  • 存在可能存在错误的任务,您可以使用以下命令重新运行它们
 - php cli.php queue:run --queue=rollback_failed_job
  • 使用数据库队列,您将创建以下两个表
  • 表 failed_jobs
-- ----------------------------
-- Table structure for failed_jobs
-- ----------------------------
DROP TABLE IF EXISTS `failed_jobs`;
CREATE TABLE `failed_jobs`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
  `queue` varchar(255) DEFAULT 'jobs',
  `exception` text DEFAULT NULL,
  `created_at` datetime NULL DEFAULT NULL,
  `updated_at` datetime NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC;
  • 表 jobs
-- ----------------------------
-- Table structure for jobs
-- ----------------------------
DROP TABLE IF EXISTS `jobs`;
CREATE TABLE `jobs`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
  `queue` varchar(255) DEFAULT 'jobs',
  `created_at` datetime NULL DEFAULT NULL,
  `updated_at` datetime NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC;

邮件

  • 通过集成 phpmailer/phpmailer 包到项目中实现邮件发送
  • 在 config/constant.php 文件中配置邮件
define('MAIL_CONNECTION', 'smtp');
define('MAIL_HOST', 'smtp.gmail.com');
define('MAIL_PORT', 465);
define('MAIL_USERNAME', 'username@gmail.com');
define('MAIL_PASSWORD', 'password');
define('MAIL_ENCRYPTION', 'ssl');
define('MAIL_DEBUG', 0);
  • 您可以通过 Email 类发送邮件,例如以下代码
<?php
namespace App\Controllers;
use Hola\Core\BaseController;
use Hola\Core\Mail;

class HomeController extends BaseController {
    public function __construct()
    {}

    public function sendMail()
    {
        $content = <<<HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
             <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
                         <meta http-equiv="X-UA-Compatible" content="ie=edge">
             <title>Title</title>
</head>
<body>
    This is the email content you want to write
</body>
</html>
HTML;
        $mail = new Mail();
        $mail->getMail()->SMTPDebug = 1; // debug mail
        $mail->from('youremail@gmail.com') // email sent
            ->withHTML() // Send email with html
            ->to('yourremail@gmail.com') // email you want to send to
            ->withData([
                'title' => 'tilte', // email title
                'content' => $content, // email content,
                'cc' => ['emailcc1@gmail.com'], // You want to cc an email
                'cc' => [
                    ['email' => 'emailcc1@gmail.com', 'name' => ''],
                    ['email' => 'emailcc2@gmail.com', 'name' => '']
                ], // cc multiple emails, name can be left empty or added
                'bcc' => ['emailbcc1@gmail.com'], // You want to bcc an email
                'bcc' => [
                    ['email' => 'emailbcc1@gmail.com', 'name' => ''],
                    ['email' => 'emailbcc2@gmail.com', 'name' => '']
                ], // bcc multiple emails, name can be left empty or added
                'attachment' => ['file'], // file attached
                'attachment' => [
                    ['name'=> 'file1'],
                    ['name'=> 'file2'],
                ] // file attached
            ])
            ->work(); // received email
    }

}
  • 使用 phpmailer/phpmailer 包的函数
<?php
namespace App\Controllers;
use Hola\Core\BaseController;
use Hola\Core\Mail;
class HomeController extends BaseController {
    public function __construct()
    {}

    public function sendMail()
    {
        $mail = new Mail();
        $mail = $mail->getMail(); // clone phpmailer
        try {
            //Server settings
            $mail->SMTPDebug = SMTP::DEBUG_SERVER;                      //Enable verbose debug output
            $mail->isSMTP();                                            //Send using SMTP
            //Recipients
            $mail->setFrom('from@example.com', 'Mailer');
            $mail->addAddress('joe@example.net', 'Joe User');     //Add a recipient
            $mail->addAddress('ellen@example.com');               //Name is optional
            $mail->addReplyTo('info@example.com', 'Information');
            $mail->addCC('cc@example.com');
            $mail->addBCC('bcc@example.com');

            //Attachments
            $mail->addAttachment('/var/tmp/file.tar.gz');         //Add attachments
            $mail->addAttachment('/tmp/image.jpg', 'new.jpg');    //Optional name

            //Content
            $mail->isHTML(true);                                  //Set email format to HTML
            $mail->Subject = 'Here is the subject';
            $mail->Body    = 'This is the HTML message body <b>in bold!</b>';
            $mail->AltBody = 'This is the body in plain text for non-HTML mail clients';

            $mail->send();
            echo 'Message has been sent';
        } catch (Exception $e) {
            echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
        }
    }

}
  • 在版本 v1.0.7 中,您可以使用以下命令创建一个用于发送独立邮件的类
php cli.php create:mail name_mail_class
  • 文件结构将如下所示
<?php
namespace Mails;
use Hola\Core\Mail;
class DefaultMail extends Mail {
    protected $useQueue = false;
    
    public function __construct()
    {
        parent::__construct();
    }
   
    public function handle()
    {
         echo "send mail";
    }

}
  • 如果变量 $useQueue 为 false,则在调用邮件类时将立即执行。如果 $useQueue 为 true,则将其推入队列。
  • 请注意,在使用产品时,您将使用以下代码
(new CreateQueue())->enQueue(new DefaultMail()); // use queue
(new DefaultMail()); // not use queue

命令

  • 要开始使用,请运行以下命令以创建一个命令
  • 例如,这里我将创建一个名为 Test1 的命令
  • php cli.php create:command Test1
  • 变量 $command 是您将要运行的命令,例如 php cli.php run:command_test
  • 变量 $command_description 是命令的标题
  • $arguments 变量是要传递的参数,例如 php cli.php run:command_test name
  • $options 变量是选项,例如 php cli.php run:command_test name --options1=1 --options2=234
<?php
namespace Commands;
use Hola\Core\Command;

class Test2Command extends Command {
    public function __construct()
    {
        parent::__construct();
    }
    protected $command = 'run:command_test';
    protected $command_description = 'A command to run';
    protected $arguments = ['username'];
    protected $options = ['options1', 'options2];

    public function handle()
    {
        $groups = [1,2,3,4,5];
        $progressBar = $this->createProgressBar(count($groups));
        echo $this->getArgument('username');
        $progressBar->start();
        foreach ($groups as $group)
        {
            sleep(2);
            $progressBar->advance();
        }
        $progressBar->finish();
        $this->output()->text('success');
    }
}
  • 默认情况下,$arguments 是必需的。如果您不希望它是必需的,可以声明如下
  protected $arguments = ['?username','?password'];
  • 默认情况下,$options 是必需的。如果您不希望它是必需的,可以声明如下
  protected $options = ['?group1','?group2'];
  • 如果您不希望使用参数和选项,可能不需要在命令中声明它们,例如
<?php
namespace Commands;
use Hola\Core\Command;

class Test2Command extends Command {
    public function __construct()
    {
        parent::__construct();
    }
    protected $command = 'run:command_test';
    protected $command_description = 'A command to run';

    public function handle()
    {
        $this->output()->text('success');
    }
}
  • 命令 clear cache router and config
   php cli.php clear:cache