本教程是针对 laravel 5 来讲解的
####0.1、一个简单的示例
//文件:routes/web.php
<?php
Route::get('/','WelcomeController@index');
//文件:app/Http/Controllers/WelcomeController.php
<?php
namescpace app\Http\Controllers;
class WelcomeController{
public function index(){
return 'Hello, World!';
}
}
访问http://xxxxxxxxx.xxx/ 就可以看见“Hello,World!”。
实际上,这种写法等价于另一种更为简便的写法
//文件:routes/web.php
<?php
Route::get('/',function(){
return 'Hello, World!';
});
但是,为了保持与后面讲解内容的一致性和代码编写的一致性,最好使用第一种方法。第一种方法的第一个文件中定义了路由,当访问‘/’的路由的时候,就去找WelcomeController里面的index方法。第二个文件定义的就是WelcomeController控制器以及它的index方法。
####0.2、一个访问数据库数据的demo
//文件:routes/web.php
<?php
Route::get('/',function{
return Greeting::first()->body;
});
//文件:app/Greeting.php
//这个是模型文件
<?php
use Illuminate\Database\Eloquent\Model;
class Greeting extends Model{}
//文件:database/migrations/2018_06_03_123123_create_greetings_table.php
//这个是数据库迁移文件,后面会详细讲解
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateGreetingsTable extends Migration{
public function up(){
Schema::create('greetings',function(Blueprint $table){
$table->increments('id');
$table->string('body');
$table->timestamps();
});
}//创建数据库的文件,这些文件都可以使用artisan命令自动生成,内容自己填充
public function down(){
Schema::drop('greetings');
}//销毁数据库时的操作
}
如果在greetings数据库里面存入一条数据:“Hello, World!”。就可以在首页看到了。
下面开始正式学习laravel
####1、创建一个新的laravel项目
1.1、使用Laravel安装工具来安装Laravel
(1)、开发全局安装Composer
(2)、运行
composer global require “laravel/installer=~1.1”
安装laravel安装工具。启动一个全向的Laravel项目:
laravel new projectName
此命令会在当前目录下创建一个新的名为 projectName 的子目录,并在其中安装 一个全新的Laravel项目
1.2、使用Composer的create-project 来安装Laravel
(1)、输入以下命令:
composer create-project laravel/laravel projectName --prefer-dist
此命令会在当前目录下创建一个新的名为 projectName 的子目录,并在其中安装 一个全新的Laravel项目
1.3、创建好Laravel项目之后,生成的项目结构大致如下(因为版本不一样,可能稍有区别)
新安装的 Laravel 应用包含许多文件夹:
app目录包含了应用的核心代码;
bootstrap目录包含了少许文件用于框架的启动和自动载入配置,还有一个cache文件夹用于包含框架生成的启动文件以提高性能;
config目录包含了应用所有的配置文件;
database目录包含了数据迁移及填充文件,如果你喜欢的话还可以将其作为 SQLite 数据库存放目录;
public目录包含了前端控制器和资源文件(图片、JavaScript、CSS等);
resources目录包含了视图文件及原生资源文件(LESS、SASS、CoffeeScript),以及本地化文件;
storage目录包含了编译过的Blade模板、基于文件的session、文件缓存,以及其它由框架生成的文件,该文件夹被细分为成app、framework和logs子目录,app目录用于存放应用要使用的文件,framework目录用于存放框架生成的文件和缓存,最后,logs目录包含应用的日志文件;
tests目录包含自动化测试,其中已经提供了一个开箱即用的PHPUnit示例;
vendor目录包含Composer依赖;
App目录
应用的核心代码位于app目录下,默认情况下,该目录位于命名空间 App 下, 并且被 Composer 通过 PSR-4自动载入标准 自动加载。你可以通过Artisan命令app:name来修改该命名空间。
app目录下包含多个子目录,如Console、Http、Providers等。Console和Http目录提供了进入应用核心的API,HTTP协议和CLI是和应用进行交互的两种机制,但实际上并不包含应用逻辑。换句话说,它们只是两个向应用发布命令的方式。Console目录包含了所有的Artisan命令,Http目录包含了控制器、中间件和请求等。
Jobs目录是放置队列任务的地方,应用中的任务可以被队列化,也可以在当前请求生命周期内同步执行。
Events目录是放置事件类的地方,事件可以用于通知应用其它部分给定的动作已经发生,并提供灵活的解耦的处理。
Listeners目录包含事件的处理器类,处理器接收一个事件并提供对该事件发生后的响应逻辑,比如,UserRegistered事件可以被SendWelcomeEmail监听器处理。
Exceptions目录包含应用的异常处理器,同时还是处理应用抛出的任何异常的好地方。
注意:app目录中的很多类都可以通过Artisan命令生成,要查看所有有效的命令,可以在终端中运行php artisan list make命令。
####2、配置
内容包括数据库连接,队列以及邮件设置都放置在config文件夹中。这里的每一个文件都将返回一个数组,数组中的每个值都可以通过一个配置键进行访问,该配置键有文件名和后续的键组成,以点好(.)进行分隔。所以,可以在config/services.php中创建如下所示的信息。
// config/services.php
return [
'sparkpost' => [
'secret' => 'aaaaaa'
]
];
现在可以使用
config('services.sparkpost.secret)
访问配置好的变量了。
每个环境中的任何配置变量都应该放在.env文件中(而不是提交给源代码控制)。如果希望在每个环境使用不同的Bugsnag API密钥,可以将配置信息从.env中提取出来,如下所示:
//config/services.php
return [
'bugsnag' => [
'api_key' => env('BUGSNAG_API_KEY')
]
];
.env()这个函数可以从.env文件中提取出该键名所对应的值。现在可以将该键名对应的信息添加到.env(当前环境的设置)和.env.example(适用于所有环境的模板)文件中。
BUGSNAG_API_KEY = oinfp9813410942
####3、路由和控制器
在学习web框架时,定义好应用程序的路由是第一个也是最重要的一个环节。没有路由,就无法与终端用户进行交互。
在一个laravel应用程序中,一般是在routes/web.php中定义路由。如果是api的路由,则在api.php中定义路由。示例0.1就是一个路由定义的例子。
在详细介绍路由之前,先介绍几个概念:
闭包:闭包是php版本的匿名函数。闭包是一个函数,可以将它作为一个对象传递,并赋值给一个变量,将其作为参数传递给其他的函数和方法,甚至进行序列化。
中间件:laravel的请求和响应的过程包含很多封装起来的内容,包括所谓的中间件。仅仅定义路由闭包以及控制器方法,还不足以将输出发送给浏览器,所以这里采用返回内容的方式,这样返回的内筒可以继续在response stack以及中间件中运行(即继续在程序中处理该返回的内容),运行完成后再返回给浏览器共终端用户查看。
demo3.1
//简单的网站
Route::get('/',function(){
return view('welcome');
});
Route::get('about',function(){
return view('about');
});
Route::get('products',function(){
return view('products');
});
Route::get('services',function(){
return view('services');
});
上面的代码等价于
$router->get('/',function(){
return view('welcome');
});
$router->get('about',function(){
return view('about');
});
$router->get('products',function(){
return view('products');
});
$router->get('services',function(){
return view('services');
});
常用的HTTP方法有:GET/POST/PUT/DELETE/PATCH
进行替换就可以了。例如:
Route::get('/',function(){
return '123';
});
Route::post('/',function(){
return '456';
});
Route::put('/',function(){});
Route::delete('/',function(){});
Route::any('/',function(){});
Route::match(['get','post'],'/',function(){});
另一种方法是将控制器名称和方法作为字符串传递给闭包
Route::get('/','WelcomeController@index');
路由参数:如果定义的路由具有参数(可变的额URL地址段),那么可以在路由中定义它们,并将它们传递给闭包。
//路由参数示例
Route::get('users/{id}/friends',function(){
//
});
一般只有get方法这样写参数。
在录用参数({id})中使用相同的名称,以及将对应的名字添加到路由定义的方法参数中(function{$sid)是十分常见的。除非使用路由/模型绑定,否则定义的路由参数与哪个方法参数相匹配仅由它们的顺序(从左到右)决定,如以下代码所示。
Route::get('users'/{userId}/comments/{commentId}',function(
$thisIsActuallyTheRouteId,
$thisisReallyTheCommentId
){
//
});
也就是说,可以让它们使用不同的名称,也可以使用相同的名称。这里建议使它们的名称保持一致,以免未来开发人员在使用的时候可能因为不一致的命名而出现问题。
还可以用过在参数名称后添加一个问号(?)来实现路由参数的选择。
//可选路由参数
Route::get('users/{id?}',function($id = 'fallbackId'){
//
});
在这种情况下,应该为相应的路由变量设置好默认值。并且可以使用正则表达式来定义一个路由,这个时候,只有该参数满足特定的模式时才会匹配
//通过正则表达式来定义路由
Route::get(;users/{id}',function($id){
//
})->where('id','[0-9]+');
Route::get('users/{username}',function($username){
//
})->where('username','[A-Za-z]+');
Route::get('posts/{id}/{slug}',function($id,$slug){
//
})->where(['id'] => '[0-9]+',]slug' => '[A-Za-z]+');
路由名称
url()助手函数:写相对路径,可以自动补全站点全称
//在routes/web.php中定义具有名称的路由
Route::get('members/{id}','MembersController@show')->name('members.show');
//使用route()助手在视图中链接路由
<a href="<php echo route('members.show',['id' = 4]); ?>">
路由组
允许多个路由组合在一起,并且可以将任何共享的配置应用于整个组,从而避免配置信息的重复。
//定义一个路由组
Route::group([],function(){
Route::get('hello',function(){
return 'Hello';
});
Route::get('world',function(){
return ' World!';
});
});
传入的空数组允许传递各种配置信息,这些配置将对组内的所有路由都生效。
中间件
路由组最常见的功能就是将中间件应用于一组路由中,但是在其他方面,路由组也常常被应用在权限控制方面。
//将一组路由限制为只允许登录用户访问
Route::group(['middleware' => 'auth'],function(){
Route::get('aaa',function(){
return view('aaaa');
});
Route::get('bbb',function(){
return view('bbbb');
});
});
此时中间件auth对aaa和bbb这两者都会生效。在此示例中,表示用户必须登录后才能查看控制中心(aaa)或账户页面(bbb)。
中间件在控制器中的应用:
通常,在控制器中使用中间件比在路由中使用中间件更为清晰和直接。可以在控制器中调用middleware()方法来使用中间件。参数代表中间件的名称,可以使用modifier方法(only()和except())来确定将由哪些方式接收中间件
class DashboardController extends Controller{
public function __construct(){
$this->middleware('auth');
$this->middleware('admin-auth')->only('admin');
$this->middleware('team-member')->except('admin');
}
}
路径前缀
//为一组路由设置路径前缀
Route::group(['prefix' => 'api'],function(){
Route::get('/',function(){
//设置path /api
});
Route::get('users',function(){
//设置path /api/users
});
});
子域名路由
子域名路由的作用域是子域名,而不是路由前缀
//子域名路由
Route::group(['domain' => 'api.myapp.com'],function(){
Route::get('/',function(){
//
});
});
//参数化的子域名路由
Route::group(['domain'=> '{acount}.myapp.com'],function(){
Route::get('/',function($acount){
//
});
Route::get('users/{id}',function($acount,$id){
//
});
});