laravel_laravel面试题 - CSDN
laravel 订阅
Laravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。在Laravel中已经具有了一套高级的PHP ActiveRecord实现 -- Eloquent ORM。它能方便的将“约束(constraints)”应用到关系的双方,这样你就具有了对数据的完全控制,而且享受到ActiveRecord的所有便利。Eloquent原生支持Fluent中查询构造器(query-builder)的所有方法。 展开全文
Laravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。在Laravel中已经具有了一套高级的PHP ActiveRecord实现 -- Eloquent ORM。它能方便的将“约束(constraints)”应用到关系的双方,这样你就具有了对数据的完全控制,而且享受到ActiveRecord的所有便利。Eloquent原生支持Fluent中查询构造器(query-builder)的所有方法。
信息
定    义
简洁、优雅的PHP Web开发框架
特    点
简洁、富于表达力
当前版本分支
为5.x
外文名
Laravel
作    者
泰勒.奥特威尔(taylor otwell)
Laravel功能特点
1、语法更富有表现力你知道下面这行代码里 “true” 代表什么意思么?$uri = Url::create(‘some/uri’, array(), array(), true); 另外,你知道其他参数在这里的意思么(除了第一个)?当然你不知道。因为这行代码没有表现力。再看看这段代码:$url = URL::to_secure(‘some/uri’);这个表达式使用HTTPS协议创建了一条URL链接, 事实上,上面两种写法都在做同样的事情,但哪一个更一目了然,更富有表现力呢?2、高质量的文档Laravel 有一个非常棒的的社区支持。Laravel代码本身的表现力和良好的文档使PHP程序编写令人愉快。3、丰富的扩展包Bundle是Laravel中对扩展包的称呼。它可以是任何东西 -- 大到完整的ORM,小到除错(debug)工具,仅仅复制&粘贴就能安装任何扩展包!Laravel的扩展包由世界各地的开发者贡献,而且还在不断增加中。4、开源、托管在GITHUB上Laravel是完全开源的。所有代码都可以从Github上获取,并且欢迎你贡献出自己的力量。
收起全文
精华内容
参与话题
  • Laravel框架基础到项目实战 完整版

    万人学习 2019-05-22 18:55:35
    Laravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码...laravel框架功能较多,但是语法相对简单,在学习中API相对比较复杂,丰富的第三方组件是laravel框架学习的一个难点。
  • PHP+Laravel实战博客项目

    千人学习 2019-11-07 16:16:12
    1.项目的需求分析和程序详细设计 2.Git服务器搭建和项目版本管理应用 3.登录、注册、前后面模板开发 4.... 5.... 6.... 7.... PHP基本应用,接口技术、Composer和Laravel5.5
  • laravel入门教程(一)

    万次阅读 2018-06-03 13:20:05
    laravel入门教程(一) 本教程是针对 laravel 5 来讲解的 0.1、一个简单的示例 //文件:routes/web.php <?php Route::get('/','WelcomeController@index'); //文件:app/...

    laravel入门教程(一)

    本教程是针对 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){
            //
        });
    });
    展开全文
  • Laravel的核心概念

    万次阅读 多人点赞 2020-03-27 10:26:01
    确实如此,这篇文章读完你可能并不能从无到有写出一个博客,但知道Laravel的核心概念之后,当你再次写起Laravel时,会变得一目了然胸有成竹。PHP的生命周期万物皆有他的生命周期。熟悉Android的同学一定熟悉Android...

    工欲善其事,必先利其器。在开发Xblog的过程中,稍微领悟了一点Laravel的思想。确实如此,这篇文章读完你可能并不能从无到有写出一个博客,但知道Laravel的核心概念之后,当你再次写起Laravel时,会变得一目了然胸有成竹。

    PHP的生命周期

    万物皆有他的生命周期。熟悉Android的同学一定熟悉Android最经典的Activity的生命周期,Laravel 也不例外,Laravel应用程序也有自己的生命周期。Laravel是什么?一个PHP框架。所以要想真正说清Laravel的生命周期,必须说清PHP的生命周期。原文参考这里,这里做个总结。
    PHP有两种运行模式,WEB模式和CLI(命令行)模式。当我们在终端敲入php这个命令的时候,使用的是CLI模式;当使用Nginx或者别web服务器作为宿主处理一个到来的请求时,会调用PHP运行,此时使用的是WEB模式。当我们请求一个PHP文件时,比如Laravel 的public\index.php文件时,PHP为了完成这次请求,会发生5个阶段的生命周期切换:

    1. 模块初始化(MINIT),即调用php.ini中指明的扩展的初始化函数进行初始化工作,如mysql扩展。
    2. 请求初始化(RINIT),即初始化为执行本次脚本所需要的变量名称和变量值内容的符号表,如$_SESSION变量。
    3. 执行该PHP脚本。
    4. 请求处理完成(Request Shutdown),按顺序调用各个模块的RSHUTDOWN方法,对每个变量调用unset函数,如unset $_SESSION变量。
    5. 关闭模块(Module Shutdown) , PHP调用每个扩展的MSHUTDOWN方法,这是各个模块最后一次释放内存的机会。这意味着没有下一个请求了。

    WEB模式和CLI(命令行)模式很相似,区别是:CLI 模式会在每次脚本执行经历完整的5个周期,因为你脚本执行完不会有下一个请求;而WEB模式为了应对并发,可能采用多线程,因此生命周期15有可能只执行一次,下次请求到来时重复2-4的生命周期,这样就节省了系统模块初始化所带来的开销。

    可以看到,PHP生命周期是很对称的。说了这么多,就是为了定位Laravel运行在哪里,没错,Laravel仅仅运行再第三个阶段:
    这里写图片描述

    知道这些有什么用?你可以优化你的Laravel代码,可以更加深入的了解Larave的singleton(单例)。至少你知道了,每一次请求结束,Php的变量都会unset,Laravel的singleton只是在某一次请求过程中的singleton;你在Laravel 中的静态变量也不能在多个请求之间共享,因为每一次请求结束都会unset。理解这些概念,是写高质量代码的第一步,也是最关键的一步。因此记住,PHP是一种脚本语言,所有的变量只会在这一次请求中生效,下次请求之时已被重置,而不像Java静态变量拥有全局作用。

    好了,开始Laravel的生命周期。

    Laravel的生命周期

    概述

    Laravel 的生命周期从public\index.php开始,从public\index.php结束。
    这里写图片描述

    注意:以下几图箭头均代表Request流向

    这么说有点草率,但事实确实如此。下面是public\index.php的全部源码(Laravel源码的注释是最好的Laravel文档),更具体来说可以分为四步:

    1. require __DIR__.'/../bootstrap/autoload.php';
    
    2. $app = require_once __DIR__.'/../bootstrap/app.php';
       $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
    
    3. $response = $kernel->handle(
        $request = Illuminate\Http\Request::capture()
       );
       $response->send();
    
    4. $kernel->terminate($request, $response);
    

    这四步详细的解释是:

    1.注册加载composer自动生成的class loader,包括所有你composer require的依赖(对应代码1).
    2.生成容器Container,Application实例,并向容器注册核心组件(HttpKernelConsoleKernelExceptionHandler)(对应代码2,容器很重要,后面详细讲解)。
    3.处理请求,生成并发送响应(对应代码3,毫不夸张的说,你99%的代码都运行在这个小小的handle方法里面)。
    4.请求结束,进行回调(对应代码4,还记得可终止中间件吗?没错,就是在这里回调的)。

    这里写图片描述

    启动Laravel基础服务

    我们不妨再详细一点:
    第一步注册加载composer自动生成的class loader就是加载初始化第三方依赖,不属于Laravel核心,到此为止。
    第二步生成容器Container,并向容器注册核心组件,这里牵涉到了容器Container和合同Contracts,这是Laravel的重点,下面将详细讲解。
    重点是第三步处理请求,生成并发送响应。
    首先Laravel框架捕获到用户发到public\index.php的请求,生成Illuminate\Http\Request实例,传递给这个小小的handle方法。在方法内部,将该$request实例绑定到第二步生成的$app容器上。让后在该请求真正处理之前,调用bootstrap方法,进行必要的加载和注册,如检测环境,加载配置,注册Facades(假象),注册服务提供者,启动服务提供者等等。这是一个启动数组,具体在Illuminate\Foundation\Http\Kernel中,包括:

    protected $bootstrappers = [
        'Illuminate\Foundation\Bootstrap\DetectEnvironment',
        'Illuminate\Foundation\Bootstrap\LoadConfiguration',
        'Illuminate\Foundation\Bootstrap\ConfigureLogging',
        'Illuminate\Foundation\Bootstrap\HandleExceptions',
        'Illuminate\Foundation\Bootstrap\RegisterFacades',
        'Illuminate\Foundation\Bootstrap\RegisterProviders',
        'Illuminate\Foundation\Bootstrap\BootProviders',
    ];
    

    看类名知意,Laravel是按顺序遍历执行注册这些基础服务的,注意顺序:Facades先于ServiceProvidersFacades也是重点,后面说,这里简单提一下,注册Facades就是注册config\app.php中的aliases 数组,你使用的很多类,如AuthCache,DB等等都是Facades;而ServiceProviders的register方法永远先于boot方法执行,以免产生boot方法依赖某个实例而该实例还未注册的现象。

    所以,你可以在ServiceProviders的register方法中使用任何Facades,在ServiceProvidersboot方法中使用任何register方法中注册的实例或者Facades,这样绝不会产生依赖某个类而未注册的现象。

    将请求传递给路由

    注意到目前为止,Laravel 还没有执行到你所写的主要代码(ServiceProviders中的除外),因为还没有将请求传递给路由。

    在Laravel基础的服务启动之后,就要把请求传递给路由了。传递给路由是通过Pipeline(另开篇章讲解)来传递的,但是Pipeline有一堵墙,在传递给路由之前所有请求都要经过,这堵墙定义在app\Http\Kernel.php中的$middleware数组中,没错就是中间件,默认只有一个CheckForMaintenanceMode中间件,用来检测你的网站是否暂时关闭。这是一个全局中间件,所有请求都要经过,你也可以添加自己的全局中间件。

    然后遍历所有注册的路由,找到最先符合的第一个路由,经过它的路由中间件,进入到控制器或者闭包函数,执行你的具体逻辑代码。

    所以,在请求到达你写的代码之前,Laravel已经做了大量工作,请求也经过了千难万险,那些不符合或者恶意的的请求已被Laravel隔离在外。
    这里写图片描述

    服务容器

    服务容器就是一个普通的容器,用来装类的实例,然后在需要的时候再取出来。用更专业的术语来说是服务容器实现了控制反转(Inversion of Control,缩写为IoC),意思是正常情况下类A需要一个类B的时候,我们需要自己去new类B,意味着我们必须知道类B的更多细节,比如构造函数,随着项目的复杂性增大,这种依赖是毁灭性的。控制反转的意思就是,将类A主动获取类B的过程颠倒过来变成被动,类A只需要声明它需要什么,然后由容器提供。
    这里写图片描述

    这样做的好处是,类A不依赖于类B的实现,这样在一定程度上解决了耦合问题。

    在Laravel的服务容器中,为了实现控制反转,可以有以下两种:

    1. 依赖注入(Dependency Injection)。
    2. 绑定。

    依赖注入

    依赖注入是一种类型提示,举官网的例子:

    class UserController extends Controller
    {
        /**
         * The user repository implementation.
         *
         * @var UserRepository
         */
        protected $users;
    
        /**
         * Create a new controller instance.
         *
         * @param  UserRepository  $users
         * @return void
         */
        public function __construct(UserRepository $users)
        {
            $this->users = $users;
        }
    
        /**
         * Show the profile for the given user.
         *
         * @param  int  $id
         * @return Response
         */
        public function show($id)
        {
            $user = $this->users->find($id);
    
            return view('user.profile', ['user' => $user]);
        }
    }
    

    这里UserController需要一个UserRepository实例,我们只需在构造方法中声明我们需要的类型,容器在实例化UserController时会自动生成UserRepository的实例(或者实现类,因为UserRepository可以为接口),而不用主动去获取UserRepository的实例,这样也就避免了了解UserRepository的更多细节,也不用解决UserRepository所产生的依赖,我们所做的仅仅是声明我们所需要的类型,所有的依赖问题都交给容器去解决。(Xblog使用了Repository的是设计模式,大家可以参考)

    绑定

    绑定操作一般在ServiceProviders中的register方法中,最基本的绑定是容器的bind方法,它接受一个类的别名或者全名和一个闭包来获取实例:

    $this->app->bind('XblogConfig', function ($app) {
        return new MapRepository();
    });
    

    还有一个singleton方法,和bind写法没什么区别。你也可以绑定一个已经存在的对象到容器中,上文中提到的request实例就是通过这种方法绑定到容器的:$this->app->instance('request', $request);。绑定之后,我们可以通过一下几种方式来获取绑定实例:

    1.  app('XblogConfig');
    
    2.  app()->make('XblogConfig');
    
    3.  app()['XblogConfig'];
    
    4.  resolve('XblogConfig');
    

    以上四种方法均会返回获得MapRepository的实例,唯一的区别是,在一次请求的生命周期中bind方法的闭包会在每一次调用以上四种方法时执行,singleton方法的闭包只会执行一次。在使用中,如果每一个类要获的不同的实例,或者需要“个性化”的实例时,这时我们需要用bind方法以免这次的使用对下次的使用造成影响;如果实例化一个类比较耗时或者类的方法不依赖该生成的上下文,那么我们可以使用singleton方法绑定。singleton方法绑定的好处就是,如果在一次请求中我们多次使用某个类,那么只生成该类的一个实例将节省时间和空间。

    你也可以绑定接口与实现,例如:

    $app->singleton(
        Illuminate\Contracts\Http\Kernel::class,
        App\Http\Kernel::class
    );
    

    上文讲述的Laravel的生命周期的第二步,Laravel默认(在bootstrap\app.php文件中)绑定了Illuminate\Contracts\Http\KernelIlluminate\Contracts\Console\KernelIlluminate\Contracts\Debug\ExceptionHandler接口的实现类,这些是实现类框架的默认自带的。但是你仍然可以自己去实现。

    还有一种上下文绑定,就是相同的接口,在不同的类中可以自动获取不同的实现,例如:

    $this->app->when(PhotoController::class)
              ->needs(Filesystem::class)
              ->give(function () {
                  return Storage::disk('local');
              });
    
    $this->app->when(VideoController::class)
              ->needs(Filesystem::class)
              ->give(function () {
                  return Storage::disk('s3');
              });
    

    上述表明,同样的接口Filesystem,使用依赖注入时,在PhotoController中获取的是local存储而在VideoController中获取的是s3存储。

    Contracts & Facades(契约&门面)

    Laravel 还有一个强大之处是,比如你只需在配置文件中指明你需要的缓存驱动(redismemcachedfile…),Laravel 就自动办你切换到这种驱动,而不需要你针对某种驱动更改逻辑和代码。Why? 很简单,Laravel定义了一系列Contracts(翻译:契约),本质上是一系列PHP接口,一系列的标准,用来解耦具体需求对实现的依赖关系。其实真正强大的公司是制定标准的公司,程序也是如此,好的标准(接口)尤为重要。当程序变得越来大,这种通过合同或者接口来解耦所带来的可扩展性和可维护性是无可比拟的。
    这里写图片描述

    上图不使用Contracts的情况下,对于一种逻辑,我们只能得到一种结果(方块),如果变更需求,意味着我们必须重构代码和逻辑。但是在使用Contracts的情况下,我们只需要按照接口写好逻辑,然后提供不同的实现,就可以在不改动代码逻辑的情况下获得更加多态的结果。

    这么说有点抽象,举一个真实的例子。在完成Xblog的初期,我使用了缓存,所以导致Repository中充满了和cache相关的方法:rememberflushforget等等。后来国外网友反映,简单的博客并不一定需要缓存。所以我决定把它变成可选,但因为代码中充满和cache相关的方法,实现起来并不是很容易。于是想起Laravel的重要概念Contracts。于是,我把与缓存有关的方法抽象出来形成一个Contracts:XblogCache,实际操作只与Contracts有关,这样问题就得到了解决,而几乎没有改变原有的逻辑。XblogCache的代码如下(源码点击这里):

    namespace App\Contracts;
    use Closure;
    interface XblogCache
    {
        public function setTag($tag);
        public function setTime($time_in_minute);
        public function remember($key, Closure $entity, $tag = null);
        public function forget($key, $tag = null);
        public function clearCache($tag = null);
        public function clearAllCache();
    }
    

    然后,我又完成了两个实现类:CacheableNoCache

    1. 实现具体缓存。
    class Cacheable implements XblogCache
    {
    	public $tag;
    	public $cacheTime;
    	public function setTag($tag)
    	{
    		$this->tag = $tag;
    	}
    	public function remember($key, Closure $entity, $tag = null)
    	{
    		return cache()->tags($tag == null ? $this->tag : $tag)->remember($key, $this->cacheTime, $entity);
    	}
    	public function forget($key, $tag = null)
    	{
    		cache()->tags($tag == null ? $this->tag : $tag)->forget($key);
    	}
    	public function clearCache($tag = null)
    	{
    		cache()->tags($tag == null ? $this->tag : $tag)->flush();
    	}
    	public function clearAllCache()
    	{
    		cache()->flush();
    	}
    	public function setTime($time_in_minute)
    	{
    		$this->cacheTime = $time_in_minute;
    	}
    }
    
    1. 不缓存。
    class NoCache implements XblogCache
    {
    	public function setTag($tag)
    	{
        // Do Nothing
    	}
    	public function setTime($time_in_minute)
    	{
        // Do Nothing
    	}
    	public function remember($key, Closure $entity, $tag = null)
    	{
    	    /**
    	     * directly return
    	     */
    	    return $entity();
    	}
    	public function forget($key, $tag = null)
    	{
    	    // Do Nothing
    	}
    	public function clearCache($tag = null)
    	{
    	    // Do Nothing
    	}
    	public function clearAllCache()
    	{
    	    // Do Nothing
    	}
    }
    

    然后再利用容器的绑定,根据不同的配置,返回不同的实现(源码):

    public function register()
    {
    	$this->app->bind('XblogCache', function ($app) {
    		if (config('cache.enable') == 'true') {
    			return new Cacheable();
    		} else {
    			return new NoCache();
    		}
    	});
    }
    

    这样,就实现了缓存的切换而不需要更改你的具体逻辑代码。当然依靠接口而不依靠具体实现的好处不仅仅这些。实际上,Laravel所有的核心服务都是实现了某个Contracts接口(都在Illuminate\Contracts\文件夹下面),而不是依赖具体的实现,所以完全可以在不改动框架的前提下,使用自己的代码改变Laravel框架核心服务的实现方式。

    说一说Facades。在我们学习了容器的概念后,Facades就变得十分简单了。在我们把类的实例绑定到容器的时候相当于给类起了个别名,然后覆盖Facade的静态方法getFacadeAccessor并返回你的别名,然后你就可以使用你自己的Facade的静态方法来调用你绑定类的动态方法了。其实Facade类利用了__callStatic() 这个魔术方法来延迟调用容器中的对象的方法,这里不过多讲解,你只需要知道Facade实现了将对它调用的静态方法映射到绑定类的动态方法上,这样你就可以使用简单类名调用而不需要记住长长的类名。这也是Facades的中文翻译为假象的原因。

    总结

    Laravel强大之处不仅仅在于它给你提供了一系列脚手架,比如超级好用的ORM,基于Carbon的时间处理,以及文件存储等等功能。但是Laravel的核心非常非常简单:利用容器抽象解耦,实现高扩展性。容器和抽象是所有大型框架必须解决的问题,像Java的Spring,Android的Dagger2等等都是围绕这几个问题的。所以本质上讲,Laravel之所以强大出名,是因为它的设计,思想,可扩展性。而Laravel的好用功能只是官方基于这些核心提供的脚手架,你同样也可以很轻松的添加自己的脚手架。

    所以不要觉得Laravel强大是因为他提供的很多功能,而是它的设计模式和思想。

    1. 理解Laravel生命周期和请求的生命周期概念。
    2. 所有的静态变量和单例,在下一个请求到来时都会重新初始化。
    3. 将耗时的类或者频繁使用的类用singleton绑定。
    4. 将变化选项的抽象为Contracts,依赖接口不依赖具体实现。
    展开全文
  • Laravel--使用介绍

    千次阅读 2018-08-02 16:18:24
    Laravel--使用介绍   1、简介 Laravel 应用默认的目录结构试图为不管是大型应用还是小型应用提供一个好的起点,当然,你可以自己按照喜好重新组织应用目录结构,Laravel 对类在何处被加载没有任何限制——只要 ...

                                         Laravel--使用介绍

     

    1、简介

    Laravel 应用默认的目录结构试图为不管是大型应用还是小型应用提供一个好的起点,当然,你可以自己按照喜好重新组织应用目录结构,Laravel 对类在何处被加载没有任何限制——只要 Composer 可以自动载入它们即可。

    Models目录在哪里?

    许多初学者都会困惑Laravel为什么没有models目录,我可以负责任的告诉大家,这是故意的。因为models这个词对不同人而言有不同的含义,容易造成歧义,有些开发者认为应用的模型指的是业务逻辑,另外一些人则认为模型指的是与关联数据库的交互。

    正是因为这个原因,我们默认将Eloquent的模型直接放置到app目录下,从而允许开发者自行选择放置的位置,关注我的博客,larave详解,会告诉你的;

    2、根目录

    App目录

    app目录包含了应用的核心代码,此外你为应用编写的代码绝大多数也会放到这里;

    Bootstrap目录

    bootstrap目录包含了少许文件,用于框架的启动和自动载入配置,还有一个cache文件夹用于包含框架为提升性能所生成的文件,如路由和服务缓存文件;

    Config目录

    config目录包含了应用所有的配置文件,建议通读一遍这些配置文件以便熟悉所有配置项;

    Database目录

    database目录包含了数据迁移及填充文件,如果你喜欢的话还可以将其作为 SQLite 数据库存放目录;

    Public目录

    public目录包含了入口文件index.php和前端资源文件(图片、JavaScript、CSS等);

    Resources目录

    resources目录包含了视图文件及原生资源文件(LESS、SASS、CoffeeScript),以及本地化文件;

    Routes目录

    routes 目录包含了应用的所有路由定义。Laravel默认提供了三个路由文件:web.phpapi.phpconsole.php

    web.php文件包含的路由都会应用web中间件组,具备Session、CSRF防护以及Cookie加密功能,如果应用无需提供无状态的、RESTful风格的API,所有路由都会定义在web.php文件。

    api.php 文件包含的路由应用了api中间件组,具备频率限制功能,这些路由是无状态的,所以请求通过这些路由进入应用需要通过token进行认证并且不能访问Session状态。

    console.php 文件用于定义所有基于闭包的控制台命令,每个闭包都被绑定到一个控制台命令并且允许与命令行IO方法进行交互,尽管这个文件并不定义HTTP路由,但是它定义了基于控制台的应用入口(路由)。

    Storage目录

    storage目录包含了编译过的Blade模板、基于文件的session、文件缓存,以及其它由框架生成的文件,该目录被细分为成appframeworklogs子母录,app目录用于存放应用要使用的文件,framework目录用于存放框架生成的文件和缓存,最后,logs目录包含应用的日志文件;

    storage/app/public 目录用于存储用户生成的文件,比如可以被公开访问的用户头像,要达到被访问的目的,你还需要在public目录下生成一个软连接storage 指向这个目录。你可以通过php artisan storage:link 命令生成这个软链接。

    Tests目录

    tests目录包含自动化测试,其中已经提供了一个开箱即用的PHPUnit示例;每一个测试类都要以 Test 开头,你可以通过phpunitphp vendor/bin/phpunit 命令来运行测试。

    Vendor目录

    vendor目录包含Composer依赖。

    3、App目录

    应用的核心代码位于app目录下,默认情况下,该目录位于命名空间 App 下,  并且被 Composer 通过 PSR-4自动载入标准 自动加载。

    app目录下包含多个子目录,如ConsoleHttpProviders等。ConsoleHttp目录提供了进入应用核心的API,HTTP协议和CLI是和应用进行交互的两种机制,但实际上并不包含应用逻辑。换句话说,它们只是两个向应用发布命令的方式。Console目录包含了所有的Artisan命令,Http目录包含了控制器、中间件和请求等。

    其他目录将会在你通过Artisan命令make生成相应类的时候生成到app目录下。例如,app/Jobs目录直到你执行make:job 命令生成任务类时才会出现在app目录下。

    注意:app目录中的很多类都可以通过Artisan命令生成,要查看所有有效的命令,可以在终端中运行php artisan list make命令。

    Console目录

    Console目录包含应用所有自定义的Artisan命令,这些命令类可以使用make:command命令生成。该目录下还有console核心类,在这里可以注册自定义的Artisan命令以及定义调度任务。

    Events目录

    这个目录默认不存在,但是可以通过 event:generate make:event 命令创建。该目录用于存放事件类。事件类用于告知应用其他部分某个事件发生并提供灵活的、解耦的处理机制。

    Exceptions目录

    Exceptions目录包含应用的异常处理器,同时还是处理应用抛出的任何异常的好地方。如果你想要自定义异常如何记录异常或渲染,需要修改 Handler 类。

    Http目录

    Http 目录包含了控制器、中间件以及表单请求等,几乎所有进入应用的请求处理都在这里进行。

    Jobs目录

    该目录默认不存在,可以通过执行 make:job 命令生成,Jobs目录用于存放队列任务,应用中的任务可以被队列化,也可以在当前请求生命周期内同步执行。同步执行的任务有时也被看作命令,因为它们实现了命令模式。

    Listeners目录

    这个目录默认不存在,可以通过执行 event:generate make:listener 命令创建。Listeners目录包含处理事件的类(事件监听器),事件监听器接收一个事件并提供对该事件发生后的响应逻辑,例如,UserRegistered事件可以被SendWelcomeEmail监听器处理。

    Mail目录

    这个目录默认不存在,但是可以通过执行 make:mail 命令生成,Mail目录包含邮件发送类,邮件对象允许你在一个地方封装构建邮件所需的所有业务逻辑,然后使用Mail::send 方法发送邮件。

    Notifications目录

    这个目录默认不存在,你可以通过执行 make:notification 命令创建,Notifications 目录包含应用发送的所有通知,比如事件发生通知。Laravel的通知功能将通知发送和通知驱动解耦,你可以通过邮件,也可以通过Slack、短信或者数据库发送通知。

    Policies目录

    这个目录默认不存在,你可以通过执行 make:policy 命令来创建,Policies 目录包含了所有的授权策略类,策略用于判断某个用户是否有权限去访问指定资源。更多详情,请查看授权文档

    Providers目录

    Providers 目录包含应用的所有服务提供者。服务提供者在启动应用过程中绑定服务到容器、注册事件以及执行其他任务以为即将到来的请求处理做准备。

    在新安装的Laravel应用中,该目录已经包含了一些服务提供者,你可以按需添加自己的服务提供者到该目录。

    技术特点

    1、Bundle是Laravel的扩展包组织形式或称呼。Laravel的扩展包仓库已经相当成熟了,可以很容易的帮你把扩展包(bundle)安装到你的应用中。你可以选择下载一个扩展包(bundle)然后拷贝到bundles目录,或者通过命令行工具“Artisan”自动安装。

     

    2、在Laravel中已经具有了一套高级的PHP ActiveRecord实现 -- Eloquent ORM。它能方便的将“约束(constraints)”应用到关系的双方,这样你就具有了对数据的完全控制,而且享受到ActiveRecord的所有便利。Eloquent原生支持Fluent中查询构造器(query-builder)的所有方法。

     

    3、应用逻辑(Application Logic)可以在控制器(controllers)中实现,也可以直接集成到路由(route)声明中,并且语法和Sinatra框架类似。Laravel的设计理念是:给开发者以最大的灵活性,既能创建非常小的网站也能构建大型的企业应用。

     

    4、反向路由(Reverse Routing)赋予你通过路由(routes)名称创建链接(URI)的能力。只需使用路由名称(route name),Laravel就会自动帮你创建正确的URI。这样你就可以随时改变你的路由(routes),Laravel会帮你自动更新所有相关的链接。

     

    5、Restful控制器(Restful Controllers)是一项区分GET和POST请求逻辑的可选方式。比如在一个用户登陆逻辑中,你声明了一个get_login()的动作(action)来处理获取登陆页面的服务;同时也声明了一个post_login()动作(action)来校验表单POST过来的数据,并且在验证之后,做出重新转向(redirect)到登陆页面还是转向控制台的决定。

     

    6、自动加载类(Class Auto-loading)简化了类(class)的加载工作,以后就可以不用去维护自动加载配置表和非必须的组件加载工作了。当你想加载任何库(library)或模型(model)时,立即使用就行了,Laravel会自动帮你加载需要的文件。

     

    7、视图组装器(View Composers)本质上就是一段代码,这段代码在视图(View)加载时会自动执行。最好的例子就是博客中的侧边随机文章推荐,“视图组装器”中包含了加载随机文章推荐的逻辑,这样,你只需要加载内容区域的视图(view)就行了,其它的事情Laravel会帮你自动完成。

     

    8、反向控制容器(IoC container)提供了生成新对象、随时实例化对象、访问单例(singleton)对象的便捷方式。反向控制(IoC)意味着你几乎不需要特意去加载外部的库(libraries),就可以在代码中的任意位置访问这些对象,并且不需要忍受繁杂、冗余的代码结构。

     

    9、迁移(Migrations)就像是版本控制(version control)工具,不过,它管理的是数据库范式,并且直接集成在了Laravel中。你可以使用“Artisan”命令行工具生成、执行“迁移”指令。当你的小组成员改变了数据库范式的时候,你就可以轻松的通过版本控制工具更新当前工程,然后执行“迁移"指令即可,好了,你的数据库已经是最新的了!

     

    10、单元测试(Unit-Testing)是Laravel中很重要的部分。Laravel自身就包含数以百计的测试用例,以保障任何一处的修改不会影响其它部分的功能,这就是为什么在业内Laravel被认为是最稳版本的原因之一。Laravel也提供了方便的功能,让你自己的代码容易的进行单元测试。通过Artisan命令行工具就可以运行所有的测试用例。

     

    11、自动分页(Automatic Pagination)功能避免了在你的业务逻辑中混入大量无关分页配置代码。方便的是不需要记住当前页,只要从数据库中获取总的条目数量,然后使用limit/offset获取选定的数据,最后调用‘paginate’方法,让Laravel将各页链接输出到指定的视图(View)中即可,Laravel会替你自动完成所有工作。Laravel的自动分页系统被设计为容易实现、易于修改。虽然Laravel可以自动处理这些工作,但是不要忘了调用相应方法和手动配置分页系统哦
     

    配置即一切

    一切皆于需求,后台从0开始搭建,但是写了一两个页面后发现太多的是对单表的增删改查操作,于是就想到了,能不能做一个快速搭建的后台。想到一句话,配置即一切。如果一个CURD后台能只进行配置就自动生成,该是多么美妙的事情,那么就开始搭建这么个结构。

     

    首先配置文件应该怎么设计

    起初想到将配置文件放到config目录下,但是想想还是放弃了这个想法,那样子可能会导致有一个“万能”文件,又臭又长。那么,其次,这个功能只针对单表,所以,是不是可以将配置文件放置在Model中,后来也觉得这个想法不大好,这个配置文件是承担页面展示的功能的,如果放在Model中就算是入侵了Model层了。所以最后决定放在了Controller中。

     

    最后的效果大概是什么样子的?

    后台大概会有几个页面:

    列表页:

    列表页中有查询操作,编辑,删除按钮,新建按钮。

    新建页面:

     

    编辑页面:

     

    好了,对应这几个页面,我们可以设置配置项了。

     

    基本想法是搭建一个FormController,所有以后需要配置生成后台的controller就继承这个FormController就好了。在FormController中定义属性:

    复制代码

    class FormController extends BaseController {
     
         // 对应的模型
         protected $model;
     
         // 所有的字段
         protected $fields_all;
     
         // 列表页显示的字段
         protected $fields_show;
     
         // 编辑页面显示的字段
         protected $fields_edit;
     
         // 创建页面显示的字段
         protected $fields_create;
    }

    复制代码

    定义了Model,来表示这个Controller是对那个Model进行单表操作的。

    定义了fields_all属性,来将所有的字段来进行一个说明和定义。这个定义和说明就包括字段显示名字,字段是否要进行搜索,字段类型是什么。

    对于列表页,不是所有属性都显示出来,所以定义一个fieldsshow,这个数组存放的是

    fields_all中的一些字段,用来显示的字段。

    对于编辑页面,要显示的字段就放在$field_edit中

    对于创建页面,要显示的字段就放在$field_create中

     

    好了,现在继承FormController的类就只需要这么配置就好;

    复制代码

    <?php
     
    // 账号管理系统
    class BadminController extends FormController
    {
     
         public function __construct()
         {
              $this->model = '\Badmin';
              $this->fields_all = [
                   'id' => [
                        'show' => '序号',
                   ],
                   'nickname' => [
                        'show' => '昵称',
                        'search' => "nickname like CONCAT('%', ?, '%')"
                   ],
                   'username' => [
                        'show' => '用户名',
                   ],
                   'email' => [
                        'show' => '邮箱',
                   ],
                   'password' => [
                        'show' => '密码',
                   ],
                   'created_at' => [
                        'show' => '创建时间',
                   ],
                   'updated_at' => [
                        'show' => '更新时间',
                   ],
              ];
     
              $this->fields_show = ['id' ,'nickname', 'username', 'email', 'created_at'];
              $this->fields_edit = ['nickname', 'username'];
              $this->fields_create = ['nickname', 'username', 'email', 'password'];
              parent::__construct();
         }
    } 

    复制代码

    在构造函数中定义model,fieldsall,

    fields_show, fieldsedit,

    fields_create。

    对于fields_all,key为数据库对应的字段名,value为一个数组,show是显示名,如果你在列表页希望这个字段能进行搜索,就设置下search属性。

     

    路由

    下面是路由,laravel中路由基本有三种:

    Route::get('order/{id}',['as'=>'order.detail','uses'=>'OrderController@show']);
    Route::controller('preview', 'PreviewController');
    Route::resource('badmin', 'BadminController');

     

    第三种已经完全定义好了增删改查操作,看起来能省我不少的事情,好吧,我就使用这个resource来做了。

     

    所以在route.php中我只需要定义这么一条就ok了

     

    // 管理员账号管理
    Route::resource('badmin', 'BadminController');

     

    Controller 

    下面写FromController中的resource方法

     

    按照laravel的resource定义的,需要填充的方法有:

     

    我习惯在构造函数中把一些诸如Input,全局定义的东西都share到模版中,代码如下:

    复制代码

         public function __construct()
         {
     
              // TODO:做一些基础的判断,如果没有的话就抛出异常
             
              $route = Route::currentRouteAction();
              list($this->controller, $action) = explode('@', $route);
              View::share('controller', $this->controller);
     
              $fields_show = array();
              foreach ($this->fields_show as $field) {
                   $fields_show[$field] = $this->fields_all[$field];
              }
              View::share('fields_show', $fields_show);
     
              $fields_edit = array();
              foreach ($this->fields_edit as $field) {
                   $fields_edit[$field] = $this->fields_all[$field];
              }
              View::share('fields_edit', $fields_edit);
     
              $fields_create = array();
              foreach ($this->fields_create as $field) {
                   $fields_create[$field] = $this->fields_all[$field];
              }
              View::share('fields_create', $fields_create);
     
              View::share('input', Input::all());
         }

    复制代码

     

    这里把controller放到外面是为了在view中可以使用诸如:

    action(controller.′@destroy′,

    model->id),

    的路径定义

     

    index函数:

     

    复制代码

     
         public function index()
         {
              $model = new $this->model;
              $builder = $model->orderBy('id', 'desc');
     
              $input = Input::all();
              foreach ($input as $field => $value) {
                   if (empty($value)) {
                        continue;
                   }
                   if (!isset($this->fields_all[$field])) {
                        continue;
                   }
                   $search = $this->fields_all[$field];
                   $builder->whereRaw($search['search'], [$value]);
              }
              $models = $builder->paginate(20);
     
              return View::make('form.index', [
                   'models' => $models,
              ]);
         }
     

    复制代码

    $builder在laravel中真是太TMD好用了,对于这里的搜索,我使用whereRaw进行prepare查询。这里还有一个点,之前在fields_all设计的时候,我定义的直接是一个 'search' => "nickname like CONCAT('%', ?, '%')"  这里定义搜索字段的时候其实有很多种设计方法,比如定义为

    ‘search’ => [
         'type' => 'like',
         'value' => '%?%'
    ]

     

     

    但是考虑到使用这个FromController的都是程序员,所以这里的search直接使用预处理的语句,然后在index中直接使用whereRaw,这样使得配置文件的易读性增加了。

     

    下面是

    create函数:

         public function create()
         {
              return View::make('form.create', []);
         }
     

     

    store函数:

    复制代码

         public function store()
         {
              $model = new $this->model;
              $model->fill(Input::all());
              $model->save();
              return Redirect::to(action($this->controller . '@index'));
         }
     

    复制代码

     

    这里的model的fill是不是很简单,爽到爆。当然model中还是需要定义fillable字段

     

    edit,update,destory函数

    如法炮制就好

     

    复制代码

         public function edit($id)
         {
              $model = new $this->model;
              $model = $model->find($id);
              return View::make('form.edit', compact('model'));
         }
     
         public function update($id)
         {
              $model = new $this->model;
              $model = $model->find($id);
              $model->fill(Input::all());
              $model->save();
     
              return Redirect::to(action($this->controller . '@index'));
         }
     
         public function destroy($id)
         {
              $model = new $this->model;
              $model->destroy($id);
             
              return Redirect::to(action($this->controller . '@index'));
         }
     

    复制代码

     

     View

    下面就是view的编写。

    view大概就只要三个页面,列表页面,编辑页面,创建页面

     

    列表页面注意事项:

    1 使用laravel自带分页,注意记得带上本页的输入参数,这个时候,构造函数中share的Input就很有用了

    {{models−>appends(

    input)->links()}}

     

    2 可以使用laravel自带的from操作,比如删除操作由于需要调用HTTP的DELETE 方法,可以这么写

    复制代码

                     {{ Form::open(array(
                      'id' => "delete_{$model->id}",
                      'url' => action($controller . '@destroy', $model->id),
                      'class' => 'dropdown-toggle')) }}
                        {{ Form::hidden('_method', 'DELETE') }}
                      {{ Form::close() }}

    复制代码

     

     

    其实自己写DELETE也行,就是在From表单中多传递一个_method隐藏域

     

    3 搜索直接使用一个form就可以搞定了

    复制代码

         <form class="form-inline" role="form" action="{{action($controller . '@index')}}">
              @foreach ($fields_show as $field => $field_info)
                @if (isset($field_info['search']))
                <div class="form-group">
                  <label class="col-sm-3 control-label">{{$field_info['show']}}</label>
                  <div class="col-md-3">
                    <input name="{{$field}}" type="input" class="form-control" placeholder="" value="@if (isset($input[$field])){{$input[$field]}}@endif">
                  </div>
                </div>
                @endif
              @endforeach
              <input type="submit" class="btn btn-success" value="查询" />
            </form>

    复制代码

     

    编辑页面和创建页面

    简单到只需要一个form就能搞定了

     

    复制代码

      <form class="form-horizontal"
              role="form"
              action="{{action($controller . "@update", $model->id)}}" method='POST'>
              <input type="hidden" name="_method" value="PUT">
                @foreach ($fields_edit as $field => $field_info)
                <div class="form-group">
                  <label class="col-sm-2 control-label">{{$field_info['show']}}</label>
                  <div class="col-sm-10">
                    <input name="{{$field}}" type="text" class="form-control" placeholder="" value="{{$model->$field}}">
                  </div>
                </div>
                <div class="line line-dashed line-lg pull-in"></div>
                @endforeach
                <div class="col-sm-4 col-sm-offset-2">
                  <button type="submit" class="btn btn-primary">提交</button>
                </div>
              </form>

    复制代码

     

     

    记得resource中更新的操作是要使用PUT方式,删除的操作要使用DELETE方式。

    至于view的模版,我这里使用的是一款叫notebook的模版,它是基于bootstrap的,你也可以使用其他更好看的模版来写。

     

    好了,至此这么个快速搭建CURD的结构就完成了。现在可以在运营人员给需求的时候,很牛逼地说,等我一分钟,我就给你一个世界~~

    laravel改变搜索的对象变数组

    路径  App/http/config/database.php

    找到:  'fetch' => PDO::FETCH_CLASS,
    改成:  'fetch' => PDO::FETCH_ASSOC,

    后记

    其实回想下,这整个结构不算复杂。配置即一切的思想能解决很多问题。但是依赖配置的路子最怕的是几个事情:

    1 配置文件过于复杂。(如果你的配置文件过于复杂,已经超过了敲代码本身需要了解的东西,那么这个配置项的学习成本就太太太高了)

    2 配置字段语意不清。(配置的字段名字和意思不对,字段名和变量名一样重要!)

     

    当然这个就是个初步,改进的几个点还有

    1 所有字段都使用input标签,需要在配置中加入其它标签类型

    2 是不是考虑view中所有的东西都使用laravel自带的form对应字段?

     

    展开全文
  • Laravel的两种搭建方法

    千次阅读 2017-12-17 15:53:30
    1.laravel一键安装包,快速安装法 下载地址:http://laravelacademy.org/resources-download 步骤: 第一步:管理员运行cmd 查看php版本:php -v 第二步 进入laravel的文件 cd c:/laravel-v5.5 执行...

    1.laravel一键安装包,快速安装法
    下载地址:http://laravelacademy.org/resources-download
    步骤:
    第一步:管理员运行cmd 查看php版本:php -v
    第二步 进入laravel的文件 cd c:/laravel-v5.5
    执行php artisan serve开启服务,就可以查看网页了,网页地址:localhost:8000
    查看路由的命令行:php artisan route:list

    2.composer安装法
    首先要先安装composer
    第一步:安装laravel
    composer安装使用命令如下:
    composer create-project –prefer-dist laravel/laravel yourproject
    它会给你创建一个叫做yourproject的项目

    文件位置

    文件目录
    对比发现,和一键安装包的内容是相同的

    第二步:安装laravel-admin及相关配置
    a.使用composer安装,命令如下:
    composer require encore/laravel-admin “1.4.*”
    不同版本的详情:
    Laravel 5.1(已经不维护了)
    composer require encore/laravel-admin “1.1.*”

    Laravel 5.2
    composer require encore/laravel-admin “1.2.*”

    Laravel 5.3
    composer require encore/laravel-admin “1.3.*”

    Laravel 5.4
    composer require encore/laravel-admin “1.4.*”

    b.添加相关服务
    在config/app.php文件中添加ServiceProvider: 服务
    Encore\Admin\Providers\AdminServiceProvider::class;

    c.发布admin.php配置文件和相关assets
    php artisan vendor:publish –tag=laravel-admin

    d.生成配置文件admin.php,完成安装
    php artisan admin:install
    注意在运行该步骤命令之前,确保laravel中.env中数据库连接配置正确

    安装完成后,打开浏览器访问http://localhost/admin,输入用户名和密码登录
    用户名:admin 密码:admin

    安装laravel-admin插件的三个步骤:
    composer require encore/laravel-admin “1.5.*”

    // 发布资源:
    php artisan vendor:publish –provider=”Encore\Admin\AdminServiceProvider”

    // 安装
    php artisan admin:install

    展开全文
  • laravel

    2020-10-16 19:41:20
    laravel 注意事项 切换到root用户下,更换阿里源 自己想在的文件目录是/home/fuyingqian/laravel/blog 下载composer 打开命令行并依次执行下列命令安装最新版本的 Composer: php -r "copy('...
  • 热烈庆祝 Laravel 5.5 LTS 发布! 实际上 Laravel 上一个 LTS 选择 5.1 是非常不明智的,因为 5.2 增加了许许多多优秀的特性。现在好了,大家都用最新的长期支持版本 5.5 吧! Laravel 5.5 中文文档:...
  • 优化PHP程序

    2011-10-10 22:03:58
    优化PHP程序 转载:http://zhaoqi7577.blog.163.com/blog/static/90154965200872812238412/ 网上很多文章介绍优化php程序,是通过安装Zend Optimizer之类的加速软件实现的,但这种加速是有限的。本
  • A.队列的使用 1.队列配置文件存储在 config/queue.php 根据自己的情况进行配置 2..env文件 QUEUE_DRIVER=database(根据个人情况配置,redis等) 3.创建jobs表(不用数据库的可以不用建表) ...
  • laravel使用redis报错

    千次阅读 2019-07-21 21:37:43
    当你使用redis时,也许会报这个错误: (1/1) ConnectionException ...����Ŀ����������ܾ����޷����ӡ� [tcp://127.0.0.1:6379] ...at AbstractConnecti...
  • laravel 生成app_key

    万次阅读 2017-01-12 09:21:04
    php artisan key:generate
  • laravel route传递参数

    万次阅读 2017-11-20 16:46:16
    laravel route传递参数,laravel传递参数,laravel接收参数
  • https://laravel-china.org/topics/2566/an-implementation-of-laravel-real-time-application
  • laravel 实现批量插入数据

    万次阅读 2018-11-16 14:53:05
    在写项目的时候,写关于订单的店铺备注以及后续一系列操作的时候,foreach的循环orm create()让我比较蛋疼, 于是找了找文档,找到了方法实现批量插入,
  • laravel部署在nginx 总是出现 nginx 403 forbidden 如果不是权限问题,也不是索引文件的问题。那就是,laravel的主目录指定错了。原来不能指定再laravel程序的根目录。要指定在public目录。
  • laravel 多个orderBy排序

    万次阅读 2018-03-29 16:51:51
    laravel中需要用到多字段排序时,写在前面的优先级高,写在后面的优先级低,每个排序order都写上倒叙还是升序
  • Laravel框架开发调试工具Laravel Debugbar使用 引入package包:composer require barryvdh/laravel-debugbar,在config/app.php的providers中添加一行注册Barryvdh\Debugbar\ServiceProvider::class
  • Laravel SQL查询中first、pluck、lists方法的使用
  • Laravel 清空配置缓存

    万次阅读 2017-02-24 11:36:38
    配置文件缓存 php artisan config:cache php artisan cache:clear php artisan config:clear
1 2 3 4 5 ... 20
收藏数 82,179
精华内容 32,871
关键字:

laravel