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


Posted in PHP onOctober 09, 2016

本文实例讲述了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

软件点击此处本站下载

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

PHP 相关文章推荐
php下实现在指定目录搜索指定类型文件的函数
Oct 03 PHP
PHP 组件化编程技巧
Jun 06 PHP
php shell超强免杀、减少体积工具实现代码
Oct 16 PHP
PHP JSON格式的中文显示问题解决方法
Apr 09 PHP
8个PHP数组面试题
Jun 23 PHP
PHP代码维护,重构变困难的4种原因分析
Jan 25 PHP
Zend Framework教程之动作的基类Zend_Controller_Action详解
Mar 07 PHP
php进行ip地址掩码运算处理的方法
Jul 11 PHP
thinkPHP5.0框架URL访问方法详解
Mar 18 PHP
ThinkPHP5.0框架控制器继承基类和自定义类示例
May 25 PHP
php如何比较两个浮点数是否相等详解
Feb 12 PHP
php实现微信公众号创建自定义菜单功能的实例代码
Jun 11 PHP
ThinkPHP的SAE开发相关注意事项详解
Oct 09 #PHP
Laravel的throttle中间件失效问题解决方法
Oct 09 #PHP
Laravel日志用法详解
Oct 09 #PHP
Laravel手动分页实现方法详解
Oct 09 #PHP
Laravel5.1自定义500错误页面示例
Oct 09 #PHP
Laravel重写用户登录简单示例
Oct 08 #PHP
Laravel使用memcached缓存对文章增删改查进行优化的方法
Oct 08 #PHP
You might like
PHP的curl实现get,post和cookie(实例介绍)
2013/06/17 PHP
PHP+shell脚本操作Memcached和Apache Status的实例分享
2016/03/11 PHP
symfony2.4的twig中date用法分析
2016/03/18 PHP
PHP编程实现微信企业向用户付款的方法示例
2017/07/26 PHP
PHP 实现手机端APP支付宝支付功能
2018/06/07 PHP
在Javascript中为String对象添加trim,ltrim,rtrim方法
2006/09/22 Javascript
基于jquery的checkbox下拉框插件代码
2010/06/25 Javascript
jQuery源码分析-04 选择器-Sizzle-工作原理分析
2011/11/14 Javascript
JQuery实现绚丽的横向下拉菜单
2013/12/19 Javascript
window.location.reload 刷新使用分析(去对话框)
2015/11/11 Javascript
JS加载iFrame出现空白问题的解决办法
2016/05/13 Javascript
JavaScript定义数组的三种方法(new Array(),new Array('x','y')
2016/10/04 Javascript
js 两数组去除重复数值的实例
2017/12/06 Javascript
Vue数据监听方法watch的使用
2018/03/28 Javascript
JavaScript 判断对象中是否有某属性的常用方法
2018/06/14 Javascript
解决webpack dev-server不能匹配post请求的问题
2018/08/24 Javascript
Vue 中获取当前时间并实时刷新的实现代码
2020/05/12 Javascript
用Python的Django框架来制作一个RSS阅读器
2015/07/22 Python
Python标准库inspect的具体使用方法
2017/12/06 Python
PyQt4实现下拉菜单可供选择并打印出来
2018/04/20 Python
Python中使用双下划线防止类属性被覆盖问题
2019/06/27 Python
Tensorflow:转置函数 transpose的使用详解
2020/02/11 Python
python读取csv文件指定行的2种方法详解
2020/02/13 Python
Python项目打包成二进制的方法
2020/12/30 Python
CSS3实现任意图片lowpoly动画效果实例
2017/05/11 HTML / CSS
HTML5 video播放器全屏(fullScreen)方法实例
2015/04/24 HTML / CSS
美体小铺加拿大官方网站:The Body Shop加拿大
2016/10/30 全球购物
波兰家具和室内装饰品购物网站:Vivre
2018/04/10 全球购物
给民警的表扬信
2014/01/08 职场文书
律师授权委托书范本
2014/10/07 职场文书
出租车拒载检讨书
2015/01/28 职场文书
2015年党风廉政建设目标责任书
2015/05/08 职场文书
幼儿园中班班级总结
2015/08/10 职场文书
高中英语教学反思范文
2016/03/02 职场文书
五年级作文之劳动作文
2019/11/12 职场文书
win10系统计算机图标怎么调出来?win10调出计算机图标的方法
2022/08/14 数码科技