Laravel 5.1 on SAE环境开发教程【附项目demo源码】

5年以前  |  阅读数:495 次  |  编程语言:PHP 

本文实例讲述了Laravel 5.1 on SAE环境开发方法。分享给大家供大家参考,具体如下:

Laravel-简洁、优雅的PHP开发框架,为 WEB 艺术家创造的 PHP 框架,如今正式移植到SAE环境。

由于Laravel 5.1相比于Laravel 4有很多的改动,不仅以目录结构更加清晰,而且功能也更丰富。但是Laravel官方还是没有原生支持SAE环境(估计永远不会支持),所以我就做了一个移植版本,可以很优雅的切换本地和SAE环境。

由于SAE的特殊性,那么这几个核心问题就必须要解决

1 putenv()函数禁用

2 模板编译

3 缓存类

4 日志处理

5 Session类

6 服务提供者缓存

#1 putenv()函数禁用

Laravel 5.1使用了这个putenv()函数来向当前的环境中动态添加变量,但是很遗憾的是SAE的PHPRuntime禁用了该函数,所以只能使用折中的方法来实现。当初本来想Hook掉该实现,后来觉得没必要,这个函数在Laravel 5.1中主要是为了使用.env配置文件来统一团队的配置。所以我是直接禁用了该功能,在vendor/vlucas/phpdotenv/src/Dotenv.php的86行左右,直接注释掉该函数,然后把所有的配置信息都写到config文件夹的相应配置文件中。虽然解决了该函数被禁用的问题,但是实现的不够优雅,希望有大神可以给出更加优雅的实现。

#2 模板编译

该问题主要还是因为SAE的本地环境写入被禁止,所以我使用了Wrapper来把编译后的模板文件写入到Storage。本来是打算写到KVDB中,但是会出现一些奇奇怪怪问题,原因不明。

在config\view.php文件中修改:


    $compiled = [
     'paths' => [
     realpath(base_path('resources/views')),
     ],
     'compiled' => realpath(storage_path('framework/views')),
    ];
    if(SAE){
     $compiled['compiled'] = 'saestor://'.SAE_STORAGE.'/compiled';
    }
    return $compiled;

注意要在相应的Storage中建立compiled文件夹。

#3 缓存类

Laravel 5.1没有直接提供SAE可用的Memcache缓存驱动,这个解决比较简单,直接写一个服务提供者注册到app.php即可,然后在config\cache.php中注册,具体实现看项目源码

#4 日志处理

这也是一个比较棘手的问题,由于Laravel 5.1的日志处理已经不是和4一样使用服务提供者,而且直接注入到启动器中,这就使得我们只能覆写原生ConfigureLogging启动类,而官方也没有给出如何覆写和在哪里覆写,所以我这边的解决方案是判断当前环境为SAE后直接重写Http内核中的一个启动器属性,核心代码:


    namespace Illuminate\Cloud\SAE;
    use App\Http\Kernel as DefaultKernel;
    class Kernel extends DefaultKernel{
     /**
     * The bootstrap classes for the application.
     *
     * @var array
     */
     protected $bootstrappers = [
     'Illuminate\Foundation\Bootstrap\DetectEnvironment',
     'Illuminate\Foundation\Bootstrap\LoadConfiguration',
     'Illuminate\Cloud\SAE\Log\ConfigureLogging',
     'Illuminate\Foundation\Bootstrap\HandleExceptions',
     'Illuminate\Foundation\Bootstrap\RegisterFacades',
     'Illuminate\Foundation\Bootstrap\RegisterProviders',
     'Illuminate\Foundation\Bootstrap\BootProviders',
     ];
    }

这样还不行,还必须重写日志的部分实现


    class Writer extends IlluminateLogWriter {
     protected function useSaeLog($level = 'debug'){
     $level = $this->parseLevel($level);
     $this->monolog->pushHandler($handler = new SaeLogHandler($level));
     $handler->setFormatter($this->getDefaultFormatter());
     }
     public function useFiles($path, $level = 'debug'){
     if (SAE) {
     return $this->useSaeLog($level);
     }
     parent::useFiles($path, $level);
     }
     public function useDailyFiles($path, $days = 0, $level = 'debug'){
     if (SAE) {
     return $this->useSaeLog($level);
     }
     parent::useDailyFiles($path, $days, $level);
     }
    }

#5 Session类

Laravel5.1的session依旧是本地写的问题,参考了Laravel4的移植,使用了memcache作为session的实现,具体可以结合缓存部分来处理

#6 服务提供者缓存

在应用程序的启动过程中,laravel会在bootstrap/cache/services.json生成服务提供者的缓存,为了加快下次访问的速度,依旧是本地写的问题,解决方案很简单,使用Storage的Wrapper即可
以上这些问题解决后,差不多就算成功了。最后修改下bootstrap\app.php来实现本地与SAE环境的优雅切换,主要是判断环境然后生成SAE专有应用实例和注入相应的Http内核。


    /*
    |--------------------------------------------------------------------------
    | Create The Application
    |--------------------------------------------------------------------------
    |
    | The first thing we will do is create a new Laravel application instance
    | which serves as the "glue" for all the components of Laravel, and is
    | the IoC container for the system binding all of the various parts.
    |
    */
    define('SAE',true);
    define('SAE_STORAGE', 'laravel');
    if(SAE){
     $app = new Illuminate\Cloud\SAE\Application(
     realpath(__DIR__.'/../')
     );
     $app->singleton(
     Illuminate\Contracts\Http\Kernel::class,
     Illuminate\Cloud\SAE\Kernel::class
     );
    }else{
     $app = new Illuminate\Foundation\Application(
     realpath(__DIR__.'/../')
     ); 
     $app->singleton(
     Illuminate\Contracts\Http\Kernel::class,
     App\Http\Kernel::class
     );
    }
    /*
    |--------------------------------------------------------------------------
    | Bind Important Interfaces
    |--------------------------------------------------------------------------
    |
    | Next, we need to bind some important interfaces into the container so
    | we will be able to resolve them when needed. The kernels serve the
    | incoming requests to this application from both the web and CLI.
    |
    */
    $app->singleton(
     Illuminate\Contracts\Console\Kernel::class,
     App\Console\Kernel::class
    );
    $app->singleton(
     Illuminate\Contracts\Debug\ExceptionHandler::class,
     App\Exceptions\Handler::class
    );
    /*
    |--------------------------------------------------------------------------
    | Return The Application
    |--------------------------------------------------------------------------
    |
    | This script returns the application instance. The instance is given to
    | the calling script so we can separate the building of the instances
    | from the actual running of the application and sending responses.
    |
    */
    return $app;

这里解释下为什么要在bootstrap\app.php中来定义是否为SAE环境,原因很明确了,就是要注入相应的应用程序实例和Http实例,然后再这里也定义一下Storage

然后就是config\app.php的相关配置,根据环境判断来注入相应的服务提供者


    if(SAE){
     $removeProviders = [
     Illuminate\Cache\CacheServiceProvider::class,
     Illuminate\Session\SessionServiceProvider::class,
     ]; 
     for($i = 0; $i < count($app['providers']); $i++){
     if (in_array($app['providers'][$i], $removeProviders)) {
     unset($app['providers'][$i]);
     }
     }
     $app['providers'] = array_merge($app['providers'],[
     Illuminate\Cloud\SAE\Cache\SaeCacheServiceProvider::class,
     Illuminate\Cloud\SAE\Session\SessionServiceProvider::class,
     Illuminate\Cloud\SAE\Storage\StorageServiceProvider::class,
     Illuminate\Cloud\SAE\Segment\SegmentServiceProvider::class,
     ]);
     $app['aliases']['Storage'] = Illuminate\Cloud\SAE\Storage\Storage::class;
     $app['aliases']['Segment'] = Illuminate\Cloud\SAE\Segment\Segment::class;
    }

最后再说说SAE专有应用程序实例和Http实例与原生的差别,主要还是本地写的问题。原生的会在应用程序启动时候生成路由、配置、服务提供者、模板编译的相关文件,以此来提升加载速度。但是到了SAE就不行了,所以重写了Application类的部分与路径相关的方法,来把这些文件生成到Storage中,而Http专有内核则是处理启动器中的日志类。具体代码就不贴出来,可以看看项目。

再给一个SAE可以使用的rewrite


    handle:
     - rewrite: if (path ~ "^/$") goto "public/index.php"
     - rewrite: if(!is_dir() && !is_file() && path~"^(.*)$") goto "public/index.php/$1"

总结

整个移植过程还算是很顺利,得益于Laravel的拓展性与SAE的便利.不过在对于putenv()函数和日志处理的解决方法上,还是实现的不够优雅,希望能有人给出更有优雅的实现方案。然后其他的SAE服务比如分词、邮件、队列等,则可以使用服务提供者自动加载,这个就不多说了。

项目github地址: https://github.com/wh469012917/laravel5-on-sae

软件点击此处[本站下载](http://xiazai.jb51.net/201610/yuanma/laravel5-on-sae-demo(jb51.net).rar)。

更多关于Laravel相关内容感兴趣的读者可查看本站专题:《Laravel框架入门与进阶教程》、《php优秀开发框架总结》、《smarty模板入门基础教程》、《php日期与时间用法总结》、《php面向对象程序设计入门教程》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总

希望本文所述对大家基于Laravel框架的PHP程序设计有所帮助。

 相关文章:
PHP分页显示制作详细讲解
SSH 登录失败:Host key verification failed
获取IMSI
将二进制数据转为16进制以便显示
获取IMEI
文件下载
贪吃蛇
双位运算符
PHP自定义函数获取搜索引擎来源关键字的方法
Java生成UUID
发送邮件
年的日历图
提取后缀名
在Zeus Web Server中安装PHP语言支持
让你成为最历害的git提交人
Yii2汉字转拼音类的实例代码
再谈PHP中单双引号的区别详解
指定应用ID以获取对应的应用名称
Python 2与Python 3版本和编码的对比
php封装的page分页类完整实例