顯示具有 laravel 標籤的文章。 顯示所有文章
顯示具有 laravel 標籤的文章。 顯示所有文章

2016年6月5日 星期日

Laravel Repository

最近寫好的repository的package 還沒時間整理readme 所以就先拿phpunit來充當readme [packagist.org](https://packagist.org/packages/recca0120/repository) [github](https://github.com/recca0120/laravel-repository) # Laravel Repository [![Latest Stable Version](https://poser.pugx.org/recca0120/repository/v/stable)](https://packagist.org/packages/recca0120/repository) [![Total Downloads](https://poser.pugx.org/recca0120/repository/downloads)](https://packagist.org/packages/recca0120/repository) [![Latest Unstable Version](https://poser.pugx.org/recca0120/repository/v/unstable)](https://packagist.org/packages/recca0120/repository) [![License](https://poser.pugx.org/recca0120/repository/license)](https://packagist.org/packages/recca0120/repository) [![Monthly Downloads](https://poser.pugx.org/recca0120/repository/d/monthly)](https://packagist.org/packages/recca0120/repository) [![Daily Downloads](https://poser.pugx.org/recca0120/repository/d/daily)](https://packagist.org/packages/recca0120/repository) ### Demo in tests/RepositoryTest.php ```php use Faker\Factory as FakerFactory; use Illuminate\Database\Eloquent\Model; use Mockery as m; use Recca0120\Repository\Criteria; use Recca0120\Repository\EloquentRepository; class EloquentRepositoryTest extends PHPUnit_Framework_TestCase { use Laravel; public function setUp() { $app = $this->createApplication(); $db = $this->createDatabase(); Schema::create('users', function ($table) { $table->increments('id'); $table->string('name'); $table->string('email'); $table->string('password', 60); $table->rememberToken(); $table->timestamps(); }); Schema::create('roles', function ($table) { $table->increments('id'); $table->string('name'); $table->string('description'); $table->timestamps(); }); Schema::create('user_roles', function ($table) { $table->integer('user_id'); $table->integer('role_id'); }); $faker = FakerFactory::create(); for ($i = 0; $i < 3; $i++) { User::create([ 'name' => sprintf('%03d', $i + 1), 'email' => sprintf('%03d@test.com', $i + 1), 'password' => $faker->text, ]); } Role::create([ 'name' => 'superuser', 'description' => 'superuser', ]); Role::create([ 'name' => 'administrator', 'description' => 'administrator', ]); User::find(1)->roles()->sync([1]); } public function tearDown() { m::close(); Schema::drop('users'); } public function test_repository_create() { $repository = new EloquentRepository(new User()); $repositoryUser = $repository->create([ 'name' => 'test9999', 'email' => 'test9999@test.com', 'password' => str_random(30), ]); $modelUser = User::where('name', '=', 'test9999')->first(); $this->assertSame($repositoryUser->id, $modelUser->id); } public function test_repository_find() { $repository = new EloquentRepository(new User()); $repositoryUser = $repository->find(1); $modelUser = User::find(1); $this->assertSame($repositoryUser->id, $modelUser->id); } public function test_repository_update() { $repository = new EloquentRepository(new User()); $repositoryUser = $repository->update([ 'password' => 'test_update', ], 2); $modelUser = User::find(2); $this->assertSame($repositoryUser->id, $modelUser->id); $this->assertSame($modelUser->password, 'test_update'); } public function test_repository_delete() { $counter = User::count(); $repository = new EloquentRepository(new User()); $this->assertTrue($repository->delete(1)); $this->assertSame(User::count(), $counter - 1); } public function test_repository_find_all() { $repository = new EloquentRepository(new User()); $repositoryUsers = $repository->findAll(); $modelUsers = User::all(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_find_by_criteria() { $repository = new EloquentRepository(new User()); $criteria = (new Criteria()) ->where('name', '0001') ->having('email', '=', '0001@test.com') ->groupBy('name'); $repositoryUsers = $repository->findBy($criteria); $modelUsers = User::where('name', 'like', '0001') ->where('email', '0001@test.com') ->groupBy('name') ->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_find_by_criteria_where() { $repository = new EloquentRepository(new User()); $criteria = (new Criteria()) ->where('name', '0001'); $repositoryUsers = $repository->findBy($criteria); $modelUsers = User::where('name', '0001') ->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_find_by_criteria_where_closure() { $repository = new EloquentRepository(new User()); $criteria = (new Criteria()) ->where(function ($criteria) { return $criteria->where('name', '0001'); }); $repositoryUsers = $repository->findBy($criteria); $modelUsers = User::where(function ($query) { return $query->where('name', '0001'); })->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_find_by_criteria_or_where() { $repository = new EloquentRepository(new User()); $criteria = (new Criteria()) ->where('name', '0001') ->orWhere('name', '0002'); $repositoryUsers = $repository->findBy($criteria); $modelUsers = User::where('name', '0001') ->orWhere('name', '0002') ->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_find_by_criteria_or_where_closure() { $repository = new EloquentRepository(new User()); $criteria = (new Criteria()) ->where(function ($criteria) { return $criteria->where('name', '0001') ->orWhere('name', '0002'); }); $repositoryUsers = $repository->findBy($criteria); $modelUsers = User::where(function ($query) { return $query->where('name', '0001') ->orWhere('name', '0002'); })->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_criteria_where_has() { $repository = new EloquentRepository(new User()); $criteria = (new Criteria()) ->whereHas('roles', function ($criteria) { return $criteria->where('id', '=', 1); }); $repositoryUsers = $repository->findBy($criteria); $modelUsers = User::whereHas('roles', function ($query) { return $query->where('id', '=', 1); }) ->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_criteria_join() { $repository = new EloquentRepository(new User()); $criteria = (new Criteria()) ->join('user_roles', function ($criteria) { return $criteria->on('users.id', '=', 'user_roles.user_id'); }); $repositoryUsers = $repository->findBy($criteria); $modelUsers = User::join('user_roles', function ($query) { return $query->on('users.id', '=', 'user_roles.user_id'); }) ->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_criteria_order_by() { $repository = new EloquentRepository(new User()); $criteria = (new Criteria()) ->orderBy('name', 'desc'); $repositoryUsers = $repository->findBy($criteria); $modelUsers = User::orderBy('name', 'desc') ->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_criteria_select() { $repository = new EloquentRepository(new User()); $criteria = (new Criteria()) ->select('name'); $repositoryUsers = $repository->findBy($criteria); $modelUsers = User::select('name') ->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_criteria_experssion() { $repository = new EloquentRepository(new User()); $criteria = (new Criteria()) ->select(Criteria::expr('REPLACE(name, "0001", "0003")')); $repositoryUsers = $repository->findBy($criteria); $modelUsers = User::select(DB::raw('REPLACE(name, "0001", "0003")')) ->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_criteria_paginated() { $repository = new EloquentRepository(new User()); $repositoryUsers = $repository->paginatedAll(15); $modelUsers = User::paginate(15); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_criteria_with() { $repository = new EloquentRepository(new User()); $criteria = (new Criteria()) ->with('roles'); $repositoryUsers = $repository->findBy($criteria); $modelUsers = User::with('roles')->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_find_by_array() { $repository = new EloquentRepository(new User()); $repositoryUsers = $repository->findBy([ ['name', '=', '0002'], ['email', '=', '0002@test.com'], ]); $modelUsers = User::where('name', '0002') ->where('email', '0002@test.com')->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_find_by_array_key() { $repository = new EloquentRepository(new User()); $repositoryUsers = $repository->findBy([ 'name' => '0002', 'email' => '0002@test.com', ]); $modelUsers = User::where('name', '0002') ->where('email', '0002@test.com')->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_custom_criteria() { $repository = new EloquentRepository(new User()); $repositoryUsers = $repository->findBy(new CustomCriteria()); $modelUsers = User::where('name', '0002')->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } public function test_multiple_criteria() { $repository = new EloquentRepository(new User()); $repositoryUsers = $repository->findBy([ new CustomCriteria(), (new Criteria())->orderBy('name', 'desc'), ]); $modelUsers = User::where('name', '0002') ->orderBy('name', 'desc')->get(); $this->assertSame($repositoryUsers->toArray(), $modelUsers->toArray()); } } class CustomCriteria extends Criteria { public function __construct() { $this->where('name', '0002'); } } class User extends Model { protected $fillable = [ 'name', 'email', 'password', ]; public function roles() { return $this->belongsToMany( Role::class, 'user_roles', 'role_id', 'user_id' ); } } class Role extends Model { protected $fillable = [ 'name', 'description', ]; public function users() { return $this->belongsToMany( self::class, 'user_roles', 'user_id', 'role_id' ); } } function dump() { call_user_func_array('var_dump', func_get_args()); } ```

Laravel Terminal

這是一個將artisan移植到web介面的package, 並增加了一些自定義的command 在server不支援bash shell時,還能執行一些aritsan的命令 [packagist.org](https://packagist.org/packages/recca0120/terminal) [github](https://github.com/recca0120/laravel-terminal) # Laravel Web Artisan [![Latest Stable Version](https://poser.pugx.org/recca0120/terminal/v/stable)](https://packagist.org/packages/recca0120/terminal) [![Total Downloads](https://poser.pugx.org/recca0120/terminal/downloads)](https://packagist.org/packages/recca0120/terminal) [![Latest Unstable Version](https://poser.pugx.org/recca0120/terminal/v/unstable)](https://packagist.org/packages/recca0120/terminal) [![License](https://poser.pugx.org/recca0120/terminal/license)](https://packagist.org/packages/recca0120/terminal) [![Monthly Downloads](https://poser.pugx.org/recca0120/terminal/d/monthly)](https://packagist.org/packages/recca0120/terminal) [![Daily Downloads](https://poser.pugx.org/recca0120/terminal/d/daily)](https://packagist.org/packages/recca0120/terminal) ## Installation Add Presenter to your composer.json file: ```js "require": { "recca0120/terminal": "^1.3.3" } ``` Now, run a composer update on the command line from the root of your project: ``` composer update ``` ### Registering the Package Include the service provider within `app/config/app.php`. The service povider is needed for the generator artisan command. ```php 'providers' => [ ... Recca0120\Terminal\ServiceProvider::class, ... ]; ``` publish ```php artisan vendor:publish --provider="Recca0120\Terminal\ServiceProvider" ``` ### URL http://localhost/path/to/terminal ### Whitelist ```php return [ 'whitelists' => ['127.0.0.1', 'your ip'], ]; ``` ## Available Commands * artisan * artisan tinker * find * mysql ### Find not full support, but you can delete file use this function (please check file permission) ```bash find ./vendor -name tests -type d -maxdepth 4 -delete ``` ## Add Your Command ### Add Command Class ```php // src/Console/Commands/Mysql.php namespace Recca0120\Terminal\Console\Commands; use Illuminate\Console\Command; use Illuminate\Foundation\Inspiring; class Inspire extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'inspire'; /** * The console command description. * * @var string */ protected $description = 'Display an inspiring quote'; /** * Execute the console command. * * @return mixed */ public function handle() { $this->comment(PHP_EOL.Inspiring::quote().PHP_EOL); } } ``` ### Add Command ```php // src/Console/Kernel.php namespace Recca0120\Terminal\Console; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; use Recca0120\Terminal\Console\Application as Artisan; class Kernel extends ConsoleKernel { /** * The Artisan commands provided by your application. * * @var array */ protected $commands = [ Commands\Inspire::class, ]; } ``` ## ScreenShot ### Available Commands ```bash $ help ``` ![Available Commands](https://cdn.rawgit.com/recca0120/terminal/master/screenshots/available-commands.png) ### Artisan List ```bash $ artisan ``` ![Artisan List](https://cdn.rawgit.com/recca0120/terminal/master/screenshots/artisan-list.png) ### Migrate ```bash $ artisan migrate --seed ``` ![Migrate](https://cdn.rawgit.com/recca0120/terminal/master/screenshots/artisan-migrate.png) ### Artisan Tinker ```bash $ artisan tinker ``` ![Tinker](https://cdn.rawgit.com/recca0120/terminal/master/screenshots/artisan-tinker.png) ### Find Command ```bash $ find ./ -name * -maxdepth 1 ``` ![Find Command](https://cdn.rawgit.com/recca0120/terminal/master/screenshots/find-command.png) ### Find and Delete ```bash $ find ./storage/logs -name * -maxdepth 1 -delete ``` ![Find and Delete](https://cdn.rawgit.com/recca0120/terminal/master/screenshots/find-and-delete.png) ### Vi ```bash $ vi server.php ``` ![Vi Command](https://cdn.rawgit.com/recca0120/terminal/master/screenshots/vi-command.png) ![Vi Editor](https://cdn.rawgit.com/recca0120/terminal/master/screenshots/vi-editor.png) ![Vi Save](https://cdn.rawgit.com/recca0120/terminal/master/screenshots/vi-save.png) ### Tail ```bash $ tail $ tail --line=1 $ tail server.php $ tail server.php --line 5 ``` ![Tail Command](https://cdn.rawgit.com/recca0120/terminal/master/screenshots/tail-command.png) ### Cleanup ```bash $ cleanup ``` ![Cleanup Command](https://cdn.rawgit.com/recca0120/terminal/master/screenshots/cleanup-command.png)

Laravel Tracy

一個laravel的debug工具,它是MIT的!大家可以安裝來試看看 用得習慣的話就請多多使用.... [packagist.org](https://packagist.org/packages/recca0120/laravel-tracy) [github](https://github.com/recca0120/laravel-tracy) ## [Nette Tracy](https://github.com/nette/tracy.git) for Laravel 5 Better Laravel Exception Handler [![Latest Stable Version](https://poser.pugx.org/recca0120/laravel-tracy/v/stable)](https://packagist.org/packages/recca0120/laravel-tracy) [![Total Downloads](https://poser.pugx.org/recca0120/laravel-tracy/downloads)](https://packagist.org/packages/recca0120/laravel-tracy) [![Latest Unstable Version](https://poser.pugx.org/recca0120/laravel-tracy/v/unstable)](https://packagist.org/packages/recca0120/laravel-tracy) [![License](https://poser.pugx.org/recca0120/laravel-tracy/license)](https://packagist.org/packages/recca0120/laravel-tracy) [![Monthly Downloads](https://poser.pugx.org/recca0120/laravel-tracy/d/monthly)](https://packagist.org/packages/recca0120/laravel-tracy) [![Daily Downloads](https://poser.pugx.org/recca0120/laravel-tracy/d/daily)](https://packagist.org/packages/recca0120/laravel-tracy) ## Features - Visualization of errors and exceptions - Debugger Bar - Exception stack trace contains values of all method arguments. ## Online Demo [Demo](https://cdn.rawgit.com/recca0120/laravel-tracy/master/screenshots/tracy-exception.html) ## Installing To get the latest version of Laravel Exceptions, simply require the project using [Composer](https://getcomposer.org): ```bash composer require recca0120/laravel-tracy ``` Instead, you may of course manually update your require block and run `composer update` if you so choose: ```json { "require": { "recca0120/laravel-tracy": "~1.3.5" } } ``` Include the service provider within `config/app.php`. The service povider is needed for the generator artisan command. ```php 'providers' => [ ... Recca0120\LaravelTracy\ServiceProvider::class, ... ]; ``` publish ```bash artisan vendor:publish --provider="Recca0120\LaravelTracy\ServiceProvider" ``` ## Config ```php return [ 'ajax' => [ 'debugbar' => false, // enable render debugbar when http request is ajax 'gzCompressLevel' => 5, // gzcompress level /* * http://stackoverflow.com/questions/3326210/can-http-headers-be-too-big-for-browsers/3431476#3431476 * Lowest limit found in popular browsers: * - 10KB per header * - 256 KB for all headers in one response. * - Test results from MacBook running Mac OS X 10.6.4: */ 'maxHeaderSize' => 102400, // 102400b its => 100 kb ], 'basePath' => null, 'strictMode' => true, 'maxDepth' => 4, 'maxLen' => 1000, 'showLocation' => true, 'editor' => 'subl://open?url=file://%file&line=%line', 'panels' => [ 'routing' => true, 'database' => true, 'view' => true, 'session' => true, 'request' => true, 'event' => false, 'user' => true, 'terminal' => true, ], // value: js or tracy 'panelDumpMethod' => 'js', // tracy dump need more memory ]; ``` ### Editor Link windows ``` copy /recca0120/laravel-tracy/tools/subl-handler/subl-handler.vbs to any directory where you want to place double click subl-handler.vbs and select editor (support eclipse, sublime, notepad++, else...) ``` OSX ``` https://github.com/dhoulb/subl ``` ## Debugger Bar ### SystemInfo ![SystemInfo](https://cdn.rawgit.com/recca0120/laravel-tracy/master/screenshots/systeminfo.png) ### Route ![Route](https://cdn.rawgit.com/recca0120/laravel-tracy/master/screenshots/route.png) ### View ![View](https://cdn.rawgit.com/recca0120/laravel-tracy/master/screenshots/view.png) ### Session ![Session](https://cdn.rawgit.com/recca0120/laravel-tracy/master/screenshots/session.png) ### Request ![Request](https://cdn.rawgit.com/recca0120/laravel-tracy/master/screenshots/request.png) ### Login ![Login](https://cdn.rawgit.com/recca0120/laravel-tracy/master/screenshots/login.png) ### Web Artisan web artisan is another package [recca0120/terminal](https://github.com/recca0120/laravel-terminal) ![Terminal](https://cdn.rawgit.com/recca0120/laravel-tracy/master/screenshots/terminal.png) #### notice if you install terminal before, this panel will throw errors, please remove folder `app/resources/views/vendor/terminal` ## ISSUE when ajax debugbar is enabled and debugbar is bigger than 256k, will throw 500 exception, or browser will be no response so I try to compress debugbar in php, and decompress debugbar in javascript. It looks like working at chrome 48.0.2564.116 64bit, windows 10 but if you use Laravel-Tracy and it doesn't work correctly you can try - disable panel [view , request, event] - panelDumpMethod change to js - disable ajax debugbar

2016年2月16日 星期二

獨立使用Laravel Blade Template Engine

有別於之前獨立使用Socialite 這次我們利用ServiceProvider來設定Laravel Blade Engine 利用composer安裝 illuminate/view ``` composer require illunimate/view ``` config.php ```php require __DIR__.'/vendor/autoload.php'; use Illuminate\Container\Container; use Illuminate\Events\Dispatcher; use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Facades\Facade; use Illuminate\Support\Facades\View; use Illuminate\Support\Fluent; use Illuminate\View\ViewServiceProvider; $app = new Container(); $app['events'] = new Dispatcher(); $app['config'] = new Fluent(); $app['files'] = new Filesystem(); // 設定view資料夾 $app['config']['view.paths'] = [__DIR__.'/views/']; // 設定快取資料夾 $app['config']['view.compiled'] = __DIR__.'/compiled/'; // 利用ServiceProvider來初始化View $serviceProvider = new ViewServiceProvider($app); // 註冊 $serviceProvider->register(); // boot $serviceProvider->boot(); Facade::setFacadeApplication($app); // 設Facade View Alias方便使用 class_alias(View::class, 'View'); ``` views/test.blade.php ```php @foreach ([1,2,3] as $v) {{ $v }} @endforeach ``` index.php ```php require __DIR__.'/config.php'; echo View::make('test')->render(); ``` 完整檔案在[Github](https://github.com/recca0120/laravel-blade-standalone-demo)

2016年2月4日 星期四

Mock Laravel Application

研究了好久的mockery終於理出一些頭緒了 Laravel的Application的Mock原來如此簡單 ```php m::mock('Illuminate\Container\Container, Illuminate\Contracts\Foundation\Application') ->makePartial() ->shouldReceive('basePath')->andReturn(realpath(__DIR__.'/../').'/') ->shouldReceive('version')->andReturn('5.x.testing') ->shouldReceive('environment')->andReturn('testing') ->mock(); ```

2016年2月1日 星期一

獨立使用Laravel Socialite

有別於前一篇,這次我們用不使用Illuminate\Container\Container來執行Laravel Socialite ## composer ``` composer require laravel/socialite ``` ## php ```php require __DIR__.'/vendor/autoload.php'; use Illuminate\Http\Request; use Illuminate\Support\Fluent; use Laravel\Socialite\SocialiteManager; use Symfony\Component\HttpFoundation\Session\Session; /* * 用 \Illuminate\Support\Fluent * 替代 \Illuminate\Container\Container */ $app = new Fluent(); /* * 用 \Illuminate\Support\Fluent * 替代 \Illuminate\Contracts\Config\Repository */ $config = new Fluent(); /* * 取得 Request */ $request = Request::capture(); /* * 使用 Symfony Session */ $session = new Session(); /* * session start */ $session->start(); /* * 設置 session */ $request->setSession($session); /* * Facebook飍數 */ $config['services.facebook'] = [ 'client_id' => '900358040081723', 'client_secret' => '06134ad6946069c6457d06688b22c259', 'redirect' => 'http://localhost/test/socialite/index.php/callback', ]; /* * 將 config, request置入 app */ $app['config'] = $config; $app['request'] = $request; // 以上為 socalite app所需設定,接下來參考官方文件即可 $socialiteManager = new SocialiteManager($app); $provider = $socialiteManager ->with('facebook') /* * 只要是oauth2就必須執行此方法, * 因為我們用的是Symfony Session而不是Laravel Session */ ->stateless(); if (strpos($_SERVER['REQUEST_URI'], '/callback') === false) { $response = $provider->redirect(); return $response->send(); } var_dump((array) $provider->user()); ```

2016年1月31日 星期日

如何獨立使用Laravel Eloquent

Laravel的套件是可以獨立使用的,並不需要加入整個framework 我們一起來了解如何操作 composer 新增套件 ```bash composer require illuminate/container illuminate/contracts illuminate/database illuminate/events illuminate/hashing illuminate/support nesbot/carbon ``` 新增bootstrap.php ```php require __DIR__.'/../vendor/autoload.php'; use Illuminate\Container\Container; use Illuminate\Support\Facades\Facade; use Illuminate\Support\Str; class Application extends Container { public $aliases = [ \Illuminate\Support\Facades\Facade::class => 'Facade', \Illuminate\Support\Facades\App::class => 'App', \Illuminate\Support\Facades\Schema::class => 'Schema', ]; public function __construct() { date_default_timezone_set('UTC'); if (class_exists('\Carbon\Carbon') === true) { \Carbon\Carbon::setTestNow(\Carbon\Carbon::now()); } $this['app'] = $this; $this->setupAliases(); $this->setupDispatcher(); $this->setupConnection(); Facade::setFacadeApplication($this); Container::setInstance($this); } public function setupDispatcher() { if (class_exists('\Illuminate\Events\Dispatcher') === false) { return; } $this['events'] = new \Illuminate\Events\Dispatcher($this); } public function setupAliases() { foreach ($this->aliases as $className => $alias) { class_alias($className, $alias); } } public function setupConnection() { if (class_exists('\Illuminate\Database\Capsule\Manager') === false) { return; } $connection = new \Illuminate\Database\Capsule\Manager(); $connection->addConnection([ 'driver' => 'sqlite', 'database' => ':memory:', ]); if (isset($this['events']) === true) { $connection->setEventDispatcher($this['events']); } $connection->bootEloquent(); $connection->setAsGlobal(); $this['db'] = $connection; } public function migrate($method) { if (class_exists('\Illuminate\Database\Capsule\Manager') === false) { return; } foreach (glob(__DIR__.'/../database/migrations/*.php') as $file) { include_once $file; if (preg_match('/\d+_\d+_\d+_\d+_(.*)\.php/', $file, $m)) { $className = Str::studly($m[1]); $migration = new $className(); call_user_func_array([$migration, $method], []); } } } public function environment() { return 'testing'; } } if (function_exists('bcrypt') === false) { /** * Hash the given value. * * @param string $value * @param array $options * * @return string */ function bcrypt($value, $options = []) { return (new \Illuminate\Hashing\BcryptHasher())->make($value, $options); } } if (function_exists('app') === false) { function app() { return App::getInstance(); } } if (Application::getInstance() == null) { new Application(); } ``` 只要再建立資料表及建立Model 就可以正常使用Eloquent了

2015年12月28日 星期一

遠振主機 escapeshellarg() has been disabled for security reasons

用遠振主機又踩雷啦,遠振將escapeshellarg這個函式disabled 所以只要有用到 SebastianBergmann\Environment\Runtime Symfony\Component\Console\Input\Input Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser Symfony\Component\Process\ProcessUtils Tracy\Debugger 都會提示 escapeshellarg() has been disabled for security reasons 不過還好php5.3之後就支援namespace,可以讓我們輕鬆略過這個問題 (如果使用的套件不支援namespace那就只好認命的去修改程式囉) 只要require下面的檔案就可以解決這些問題了 ```php namespace Yuan\Jhen { if (function_exists('escapeshellarg') === true) { function escapeshellarg($input) { return \escapeshellarg($input); } } else { function escapeshellarg($input) { $input = str_replace('\'', '\\\'', $input); return '\''.$input.'\''; } } } namespace SebastianBergmann\Environment { function escapeshellarg($input) { return \Yuan\Jhen\escapeshellarg($input); } } namespace Symfony\Component\Console\Input { function escapeshellarg($input) { return \Yuan\Jhen\escapeshellarg($input); } } namespace Symfony\Component\HttpFoundation\File\MimeType { function escapeshellarg($input) { return \Yuan\Jhen\escapeshellarg($input); } } namespace Symfony\Component\Process { function escapeshellarg($input) { return \Yuan\Jhen\escapeshellarg($input); } } namespace Tracy { function escapeshellarg($input) { return \Yuan\Jhen\escapeshellarg($input); } } ```

2015年12月22日 星期二

利用Git來升級Laravel

照著影片操作,就會出現conflicts,處理完conflicts之後,再執行 ```bash composer install ``` 這樣大致上就升級完畢了,而且如果升級出問題還可以利用git本身的功能來進行還原...

2015年10月23日 星期五

Laravel的Session不等於PHP Native Session

在Laravel內我們可能寫了以下的程式碼 ```php get('/session', function () { session_start(); session()->put('foo', 'bar'); $_SESSION['foo'] = 'bar'; header('location: '.url('/session/display')); exit; }); get('/session/display', function () { session_start(); ob_start(); dump(session()->get('foo')); dump($_SESSION['foo']); $content = ob_get_clean(); // output null, 'bar' return $content; }); ``` 會發現輸出結果完全不如我們所預期,為什麼會這樣呢?我們就好好的來做個探討吧... ## 原因出在Laravel的Session根本不是用PHP Native Session 在遇到這個狀況後,於是就去查了一下Laravel Session倒底是怎麼一回事,發現Laravel的程式碼內根本沒有執行session_start()啊 ## Laravel Session倒底是怎麼運作的 追了一下Laravel的原始碼,發現它是利用[Illuminate\Session\Middleware\StartSession](https://github.com/illuminate/session/blob/master/Middleware/StartSession.php)來進行php session模擬的, 在Laravel執行的最後階段在將存在記憶體內的資料進行實體寫入, 所以只要在我們只要在程式內任意一個地方執行了php的exit, die, header('location: xxx'); 那Session就不會被存入檔案內,自然在下一次連線也就取不到值了 ## 有沒有解決方案 有,當然有,只要輸入 ```php get('/session', function () { session_start(); session()->put('foo', 'bar'); $_SESSION['foo'] = 'bar'; session()->save(); // 手動寫入 dump($_SESSION['foo']); $content = ob_get_clean(); // output 'bar', 'bar' return $content; }); ``` ## 後記 為什麼會有這一篇的出現,因為我們可能會用很多其它已經寫好的library,但它們就是有用到session_start();外加header, die, exit等等指令啊,所以記錄一下來提醒自己囉

2015年9月20日 星期日

重寫Laravel Socialite

最近需要用到OAuth的Client套件 所以就使用目前最多人使用的Laravel 不過需要的部份只有Laravel Socialite 看了一下composer.json的相依性 ```json "require": { "php": ">=5.4.0", "illuminate/contracts": "~5.0", "illuminate/http": "~5.0", "illuminate/support": "~5.0", "guzzlehttp/guzzle": "~5.0|~6.0", "league/oauth1-client": "~1.0" }, ``` 只需要這些package並不需要整個Laravel 所以就開始使用它 不過在使用的過程遇到了不少問題 它所需要的package其實不止這些 所以程式在撰寫的過程中確實遇到不少問題 再在上在本機端上開發會遇到cURL error 60: SSL certificate problem 於是決定以[PHPoAuthLib](https://github.com/Lusitanian/PHPoAuthLib.git)進行開發 所以就寫了[Recca0120 Socialite](https://github.com/recca0120/Socialite) 並使它可以獨立使用 [Demo](https://github.com/recca0120/Socialite/tree/master/demo) 目前只先實作Laravel Socialite原本的功能,之後會視情形再加功能 OAuth1 BitBucket Twitter OAuth2 Facebook GitHub Google Instagram LinkedIn

2015年8月14日 星期五

Laravel 5 取得 Artisan::call的執行結果

```php // 輸出結果 class WelcomeController extends controller { public function index() { return response()->stream(function() { Artisan::call('inspire'); echo Artisan::output(); }); } } ```

2015年8月9日 星期日

Laravel 5 資料庫timezone設定

原本在設定database的timezone的設定方式是採取 ```php 'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', 'localhost'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', 'strict' => false, 'options' => [ PDO::MYSQL_ATTR_INIT_COMMAND => 'SET time_zone = "+08:00"' ], ], ``` 後來卻在laravel的原始碼發現 ![Alt text](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_u-41FbGyPsJq6Z6AqMqSbCalwbp1QGNb5pazM_r-74k1coiFCRQE_2sRby6ZdxDPAumL7GPPKDJwlthyphenhyphenlrA4nujOquoQk2pRyf-5Tbjtm0iYv2N3NJyZz9ozEzxtyR69BtKVJuk7lZSL/s1600/Image+6.png) 所以timezone的設定只要這樣寫就可以 ```php 'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', 'localhost'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', 'strict' => false, 'timezone' => '+08:00', ], ```

2015年7月27日 星期一

使用Laravel artisan schedule:run時 exec被禁用時的替代方案

```php namespace App\Console; use Artisan; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; class Kernel extends ConsoleKernel { /** * The Artisan commands provided by your application. * * @var array */ protected $commands = [ 'App\Console\Commands\Inspire', ]; /** * Define the application's command schedule. * * @param \Illuminate\Console\Scheduling\Schedule $schedule */ protected function schedule(Schedule $schedule) { // 當exec被disabled時只要改成使用Artisan::call('command')即可 $schedule->call(function () { Artisan::call('inspire'); }) ->hourly(); } } ```

遠振主機上利用crontab執行 laravel artisan schedule:run

在專案中有個需求需要在固定時間去抓取固定資料 既然都已經使用laravel所以當然開始使用artisan寫寫console指令 於是很快速的寫完程式,當然第一時間就在自己本機上測試 測試的結果當然是一切都正常 所以很快的就把程式上傳到遠振主機上 並且設定了Cron的排程 ```bash * * * * * php /path/to/artisan schedule:run 1>> /dev/null 2>&1 ``` 設定完後,想說一切都妥當了, 但程式一直出錯 系統就回應 ```ini [ErrorException] Invalid argument supplied foreach() ``` 這要怎麼debug啊 而且明明在自己電腦內測試都能正常執行啊 所以只好開始研究程式碼囉,查到最後原來..... 遠振主機的php預設為 php-cgi 所以無法取得正確的參數 如果要artisan正常執行的話必須使用php-cli 所以在遠振主機上要執行artisan應該要改為 ```bash * * * * * /usr/bin/php-cli /path/to/artisan schedule:run 1>> /dev/null 2>&1 ``` 應該所有的cpanel主機只要是可選php版本的都會遇到這個問題...... php-cli和php-cgi兩個在console上執行的差異 php-cli 的參數會存入 $_SERVER['argv']; php-cgi的參數則會存入 $_GET; 如果要讓php-cgi能正常執行則可以用以下做法 ```php if (empty($_GET) === false) { foreach ($_GET as $key => $value) { $_SERVER['argv'][] = $key; } } ```