pfinal / leaf
leaf
Requires
- php: >=5.4
- monolog/monolog: ^1.0
- pfinal/blade: ^1.0
- pfinal/database: ^1.0
- pfinal/routing: ^1.8
- pfinal/session: ^1.0
- psr/log: ^1.0
- symfony/console: ^2.0
- symfony/http-foundation: ^2.0
- twig/extensions: ^1.0
Requires (Dev)
- filp/whoops: ^2.1
- mtdowling/cron-expression: ^1.2
- nesbot/carbon: ^1.0
- phpmyadmin/sql-parser: ^4.2
- robmorgan/phinx: ^0.9
- symfony/process: ^2.0
- symfony/var-dumper: ^3.0
- dev-master
- v2.6.12
- v2.6.11
- v2.6.10
- v2.6.9
- v2.6.8
- v2.6.7
- v2.6.6
- v2.6.5
- v2.6.4
- v2.6.3
- v2.6.2
- v2.6.1
- v2.6.0
- v2.5.46
- v2.5.44
- v2.5.43
- v2.5.42
- v2.5.41
- v2.5.40
- v2.5.39
- v2.5.38
- v2.5.37
- v2.5.36
- v2.5.35
- v2.5.34
- v2.5.33
- v2.5.32
- v2.5.31
- v2.5.30
- v2.5.29
- v2.5.28
- v2.5.27
- v2.5.26
- v2.5.23
- v2.5.22
- v2.5.21
- v2.5.20
- v2.5.18
- v2.5.17
- v2.5.16
- v2.5.15
- v2.5.14
- v2.5.13
- v2.5.12
- v2.5.11
- v2.5.10
- v2.5.9
- v2.5.8
- v2.5.7
- v2.5.6
- v2.5.5
- v2.5.4
- v2.5.3
- v2.5.2
- v2.5.1
- v2.5.0
- v2.4.21
- v2.4.20
- v2.4.19
- v2.4.18
- v2.4.17
- v2.4.16
- v2.4.15
- v2.4.14
- v2.4.13
- v2.4.12
- v2.4.11
- v2.4.10
- v2.4.9
- v2.4.8
- v2.4.7
- v2.4.6
- v2.4.5
- v2.4.4
- v2.4.3
- v2.4.2
- v2.4.1
- v2.3.2
- v2.3.1
- v2.3.0
- v2.2.16
- v2.2.15
- v2.2.14
- v2.2.13
- v2.2.12
- v2.2.11
- v2.2.10
- v2.2.9
This package is auto-updated.
Last update: 2024-11-08 03:10:38 UTC
README
安装
composer create-project pfinal/leafphp demo
交流QQ群
17778706
编码规范
- 遵循PSR-1、PSR-2、PSR3、PSR-4、PSR-16 等标准
- PHP代码文件必须以
<?php
标签开始,不写PHP结束标记:?>
- PHP代码文件必须使用 不带BOM的 UTF-8 编码
- 命名空间与目录对应,文件名采用"类名.php"格式,目录大小写与命令空间相同,类名大小写与文件名相同(PSR-4规范)
- 类的命名必须遵循大写开头的驼峰命名规范(例如
UserController
) - 方法名称如果是多个单词,必须遵循小写开头的驼峰命名规范(例如
createOrder
) - 类中的常量所有字母都必须大写,多个单词间用下划线分隔
- 普通目录全小写格式,多个单词之间用中杠分隔(例如
views/member-profile
)
基本概念约定
- 项目 project
- 应用 application
- 模块 bundle
- 控制器 controller
- 动用 action
- 路由 route
目录结构
- config 配置文件目录
- app.php 应用配置文件
- routes.php 路由
- runtime 运行时目录,存放缓存、日志、调式信息等,需要写权限
- .gitignore 版本管理工具git忽略清单,请勿删除此文件
- views 视图文件目录
- document 文档
- src PHP源代码
- tests 测试
- vendor 第三方代码 composer管理,请勿手动修改该目录内容
- web 项目发布的根目录
- static 第三方静态资源目录
- themes 主题目录,项目的css、js、img等存放在此目录
- index.php 前端控制器(MVC模式的入口文件)
- assets 框架自动管理的资源文件,请勿手动修改该目录内容
- temp 临时文件目录,需要写权限
- uploads 文件上传目录,需要写权限
- .gitignore 版本管理工具git忽略清单
- console 命令行入口文件
- phpunit 单元测试入口文件
开启调式模式
nginx配置
# ... server{ # ... root /wwwroot/project/web/; location / { index index.html index.php; try_files $uri @rewrite; } location @rewrite { rewrite ^/(.*)$ /index.php/$1 last; } location ~ \.php(/|$) { fastcgi_pass 127.0.0.1:9000; fastcgi_split_path_info ^(.+\.php)(.*)$; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
路由
下面以demo项目为例
在 config/routes.php
中定义路由
基本 GET 路由,浏览器访问 http://localhost/demo/web
use Leaf\Route; Route::get('/', function(){ return 'Hello Leafphp!'; });
只允许POST请求的路由,以POST方法访问 http://localhost/demo/web/foo
Route::post('foo', function(){ return 'post only'; });
注册路由响应任意方式的HTTP请求,不对请求方法进行限制,post或get均可,浏览器访问 http://localhost/demo/web/bar
Route::any('bar', function(){ return 'any'; });
基础路由参数 浏览器访问 http://localhost/demo/web/user/1
Route::get('user/:id', function($id){ return 'user id: ' . $id; });
方法注入,框架将自动注入Leaf\Request
实例,浏览器访问 http://localhost/demo/web/foo?name=leaf
use Leaf\Request; Route::any('foo', function(Request $request){ $name = $request->get('name'); return $name; // leaf });
支持注入的对象
Leaf\Request Leaf\Application
生成URL
use Leaf\Url; $url = Url::to('foo'); /demo/web/foo $url = Url::to('foo', ['id' => 1]); /demo/web/foo?id=1 $url = Url::to('foo', true); http://localhost/demo/web/foo
如果访问时url中没有隐藏入口文件index.php
,则生成的url也会自动包含index.php
请求与响应
Request
use Leaf\Request; Route::any('test', function (Request $request) { //GET POST PUT DELETE HEAD ... $method = $request->getMethod(); $bool = $request->isMethod('post') // post request $bool = $request->isXmlHttpRequest() // ajax request $id = $request->get('id'); // $_POST['id'] or $_GET['id'] $arr = $request->all(); // $_POST + $_GET });
Response
use Leaf\View; use Leaf\Response; use Leaf\Json; Route::any('/', function(){ //string return 'Hello Leaf!'; return new Response('Hello Leaf!'); //view return View::render('home.twig'); // 输出views/home.twig模板中内容 //json return Json::render(['status' => true, 'data' => 'SUCCESS']); return Json::renderWithTrue('SUCCESS'); return Json::renderWithTrue('ERROR'); });
重定向
use Leaf\Redirect; return Redirect::to('foo'); // 跳转到 Url::to('foo') return Redirect::to('/'); // 项目的根目录 return Redirect::to('http://www.example.com'); // 外部链接
中间件
编写中间件类 src/Middleware/TestMiddleware.php
<?php namespace Middleware; use Leaf\Request; class TestMiddleware { public function handle(Request $request, \Closure $next) { $id = $request->get('age'); if ($id < 18) { return 'age error'; } return $next($request); } }
注册一个名为test
的中间件
$app['test'] = 'Middleware\TestMiddleware';
为路由绑定这个test
中间件
use Leaf\Request; Route::any('info', function (Request $request) { return $request->get('age'); }, 'test');
浏览器访问
`http://localhost/demo/web/info?age=17` 被中间件拦截
`http://localhost/demo/web/info?age=18` 请求将被通过
为一组路由绑定中间件 (绑定多个中间件,传入数组即可)
use Leaf\Request; Route::group(['middleware' => 'test'], function () { Route::any('info', function (Request $request) { return $request->get('age'); }); //other route });
如果希望中间件,在执行之后生效,可以使用下面的方式,
$next()
返回值可能是Request\Response
对象或string
use Leaf\Request; public function handle(Request $request, \Closure $next) { $response = $next($request); // your code ... return $response; }
控制器
控制器类通常以Controller作为后缀,例如 src/Controller/SiteController.php
任何PHP类均可作为控制器
<?php namespace Controller; class SiteController { public function home() { return 'Hello Leafphp!'; } }
路由指向控制器中的方法
Route::get('home','Controller\SiteController@home');
浏览器访问 http://localhost/demo/web/home
如果需要包含多个字词,建议在 URI 中使用中杠
来分隔,例如user-profile
使用注解语法注册路由,自动注册路由。class上的Middleware
,将对整个控制器生效
<?php // src/Controller/UserController.php /** * @Middleware auth */ class UserController { /** * @Route user/info * @Method get */ public function info() { // your code ... } }
添加注解路由 Route::annotation('Controller\UserController');
视图
支持twig和blade模板引擎,跟据后缀自动识别。
twig http://twig.sensiolabs.org
blade http://laravel.com/docs/5.1/blade
use Leaf\View; // views/index.twig return View::render('home.twig', [ 'name' => 'Leaf', ]); // views/index.blade.php return View::render('home', [ 'name' => 'Leaf', ]);
将变量共享给所有模板
\Leaf\View::share('url', 'http://example.com');
扩展twig模板 增加一个count函数,用于在模板中统计数组成员数量(twig提供了length过滤器)
$app->extend('twig', function ($twig, $app) { /** @var $twig \Twig_Environment */ $twig->addFunction(new \Twig_SimpleFunction('count', function ($arr) use ($app) { return count($arr); })); return $twig; });
twig中使用自定义的count函数
{{ count([1, 3, 5]) }} 或 {{ count({"id":1, "name":"Ethan"}) }}
Bundle
Bundle可以更好的组织功能模块
目录结构
src/ FooBundle/ Bundle总目录 FooBundle.php Bundle类文件 Controller/ 控制器 resources/ 资源目录 routes.php 路由文件 views/ 视图目录
Bundle类,继承自Leaf\Bundle
类即可,主要用于定位Bundle所在目录
// src/FooBundle/FooBundle.php class FooBundle extends \Leaf\Bundle { }
注册Bundle
$app->registerBundle(new \FooBundle\FooBundle());
加载视图
Bundle的视图文件位于Bundle的resources/views目录中
return View::render('@FooBundle/home.twig');
顶级views目录中,与Bundle同名目录下的视图文件,将优先使用。
例如/views/FooBundle/home.twig
,将替换src/FooBundle/resources/views/home.twig
文件。
加载路由
Bundle注册后,Bundle的路由文件会自动加载,例如FooBundle/resources/routes.php
。
自动生成Bundle
php console make:bundle
数据库
基本用法
$conn = DB::getConnection(); $conn->execute() // 执行SQL(INSERT、UPDATE、DELETE) $conn->query() // 执行SQL(SELECT) $conn->queryScalar() // 执行SQL,查询单一的值(SELECT COUNT) $conn->getLastInsertId() // 返回自增id $conn->beginTransaction() // 开启事务 $conn->commit() // 提交事务 $conn->rollBack() // 回滚事务 $conn->getLastSql() // 最近执行的SQL
查询构造器
$query = DB::table() // DBQuery返回数据的方法: $query->findOne() $query->findByPk() $query->findOneBySql() $query->findAll() $query->findAllBySql() $query->count() $query->paginate($pageSize) //DBQuery连惯操作方法,返回DBQuery对象: $query->where() $query->whereIn() $query->limit() $query->offset() $query->orderBy() $query->asEntity() $query->lockForUpdate() $query->lockInShareMode() //分块操作 $query->chunk() $query->chunkById()
手动分页
$query = DB::select('user')->where($condition, $params); $page = new Pagination(); $queryCount = clone $query; $page->itemCount = $queryCount->count(); $query->limit($page->limit)->findAll();
系统服务
会话,调用Session相关方法时,会自动开启Session
use Leaf\Session; //设置Session Session::set('username', 'Jack'); //获取Session $username = Session::get('username'); //删除Session Session::remove('username'); //获取Session,如果不存在,使用`guest`作为默认值 $username = Session::get('username', 'guest'); //设置闪存数据 Session::setFlash('message', 'success'); //是否有闪存数据 $bool = Session::hasFlash('message'); //获取闪存数据,闪存数据获取后将自动删除 $message = Session::getFlash('message');
表单验证
$data = [ 'username' => 'jack', 'email' => 'jack@b.c', 'age' => '18', 'info' => 'abc', ]; $rules = [ [['username', 'email'], 'required'], [['username'], 'match', 'pattern' => '/\w{3,15}/'], [['info'], 'string', 'length' => [3, 10]], [['email'], 'email'], [['age'], 'compare', 'type' => 'number', 'operator' => '>=', 'compareValue' => 0], [['age'], 'compare', 'type' => 'number', 'operator' => '<=', 'compareValue' => 150], ]; $labels = [ 'username' => '用户名', ]; if (!Validator::validate($data, $rules, $labels)) { var_dump(Validator::getFirstError()); var_dump(Validator::getErrors()); }
错误
use Leaf\Exception\HttpException; throw new HttpException(400, '您访问的页面不存在'); throw new HttpException(500, '服务器内部错误');
日志
use Leaf\Log; Log::debug("日志内容"); Log::info("日志内容"); Log::warning("日志内容"); Log::error("日志内容");
验证码
//注册 $app->register(new \Leaf\Provider\CaptchaProvider()); //生成验证码图片 \Leaf\Route::get('captcha', function (\Leaf\Application $app) { return $app['captcha']->create(); }); //表单中使用验证码 \Leaf\Route::any('show', function () { $html = <<<TAG <form method="post" action="{{ url('validate') }}"> <img src="{{ url('captcha') }}" onclick="this.src='{{ url('captcha') }}?refresh='+Math.random()" style="cursor:pointer" alt="captcha"> <input name="code"> <button type="submit">提交</button> </form> TAG; return View::renderText($html); }); //提交表单时验证输入是否正确 \Leaf\Route::post('validate', function (\Leaf\Application $app, \Leaf\Request $request) { if ($app['captcha']->validate($request->get('code'))) { // 'success'; } else { // 'Verification code is invalid.'; } }); // 显示指定内容验证码图片 $obj = new \Leaf\Provider\CaptchaProvider(); return $obj->create('1234');
文件上传
use Leaf\UploadedFile; $up = new UploadedFile($config); if ($up->doUpload($name)) { //上传后的文件信息 $file = $up->getFile(); }
认证
use Service\Auth Auth::onceUsingId($userId); Auth::loginUsingId($userId); Auth::getUser() Auth::getId()
权限
$app->register(new \Leaf\Auth\GateProvider(), ['gate.config' => ['authClass' => 'Service\Auth']]); $app['gate'] = $app->extend('gate', function ($gate, $app) { /** @var $app \Leaf\Application */ /** @var $gate \Leaf\Auth\Gate */ //用户是否有执行某个task的权限 $gate->define('task', function (\Entity\User $user, $taskCode) { // 判断权限 if (xxx){ return true; }else{ return false; } }); return $gate; }); // 判断是否有权限 $bool = Auth::user()->can('task', $taskCode);
自定义分页样式
$app['Leaf\Pagination'] = function () { $page = new \Leaf\Pagination(); $page->pageSize = 15; $page->prevPageLabel = '<span class="glyphicon glyphicon-chevron-left"></span>'; $page->nextPageLabel = '<span class="glyphicon glyphicon-chevron-right"></span>'; return $page; };
命令行
php console down # 维护模式 php console up # 退出维护模式 php console make:bundle # 创建bundle php console make:entity # 创建实体类 php console make:curd # 创建增删改查控制器和视图 php console make:api # 创建Api控制器 php console migrate # 执行数据迁移 php console migrate:create # 创建数据迁移文件 php console migrate:rollback # 回滚数据迁移
更多扩展