2016年6月6日 星期一

php版 取得台灣地址區碼

常常為了地址的事情感到麻煩,所以寫了一個程式能把舊5都地址轉新5都地址,再取得區碼的程式 [packagist.org](https://packagist.org/packages/recca0120/twzipcode) [github](https://github.com/recca0120/twzipcode) ```bash composer require recca0120/twzipcode ``` ```php use Recca0120\Twzipcode\Twzipcode; $twzipcode = new Twzipcode('北 縣 萬里鄉中正路100號'); $twzipcode->getZipcode(); // 207 $twzipcode->getCounty(); // 新北市 $twzipcode->getDistrict(); // 萬里區 $twzipcode->getAddress(); // 新北市萬里區中正路100號 $twzipcode->getShortAddress(); // 中正路100號 ```

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年5月12日 星期四

活用 es6 generator + co 讓async看起來像sync

仔細研究了es6的generator function + [co](https://github.com/tj/co "co") 才發現可以利用它來改善我們的程式寫法 讓程式的可讀性更高 先讓我們看看用Promise來撰寫非同步code的樣子 ```javascript let num = function (num) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(num+1); }, 500); }); } num(1).then((res) => { return num(res); }).then((res) => { return num(res); }).then((res) => { // output // promise result: 4 console.log(`promise result: ${res}`); }); ``` 接下來讓我們來看看generator function + [co](https://github.com/tj/co "co")的寫法 ```javascript let num = function (num) { return (callback) => { setTimeout(function() { callback(null, num+1); }, 500); } } co(function*() { let num1 = yield num(1); let num2 = yield num(num1); let num3 = yield num(num2); return num3; }).then((res) => { // output // generator result: 4 console.log(`generator result: ${res}`); }); ``` [jsfiddle](https://jsfiddle.net/recca0120/eocp5h2c/ "jsfiddle範例")

2016年4月25日 星期一

ubuntu下安裝atom editor

只要執行三行指令即可 ```bash sudo add-apt-repository ppa:webupd8team/atom sudo apt-get update sudo apt-get install atom ```

Linux使用php7連接mssql,並設定utf-8

使用php7要連接mssql要安裝的套件為pdo_dblib ```bash # centos yum install php70w-pdo_dblib.x86_64 # ubuntu sudo apt-get install freetds-bin php-sybase ``` 接下來我們更改freetds的設定檔,裝連線設定為utf8 ```bash # centos vi /etc/freetds.conf # ubuntu sudo vi /etc/freetds/freetds.conf ``` 加入兩行設定即可 ```ini # centos tds version = 7.2 client charset = UTF-8 # ubuntu tds version = 7.1 client charset = UTF-8 ``` ![freetds config](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfZxvhvTwGAuP2pwtB80Bbypwb54mp8uAIPe5kAPEB8Swk4l5BFpt0ZncIr_SMZ43RW5ibnF7SOP_AeE5D7PX5JFbk2uBPZkK_Q0jL0MFFlMXRkmgJeUNFv17CszpfALpdfu-HJ23aKN92/s1600/Image+3.png) 設定完成後連線到mssql charset就會是utf8 如果還是顯示為亂碼的話則可以利用tsql的指令來debug ```bash tsql -S [ip] -U [username] -P [password] ``` ![tsql](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhplyPJmyyXaqfmXpo1D9Tl72GhIOrn_P2QgjwASD3-QNn_3YUyVBsCX6FPv0TdYC6D9hhYd2JIVR8OEHZXnBErLy2004Kmsah5y1YOqCoZ5WtiPL5sbYzWiB-6dxaPz3OKny6Ji2qJw-Vf/s1600/Image+2.png)