2016年6月6日 星期一

php版 取得台灣地址區碼

常常為了地址的事情感到麻煩,所以寫了一個程式能把舊5都地址轉新5都地址,再取得區碼的程式

packagist.org github

composer require recca0120/twzipcode
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 github

Laravel Repository

Latest Stable Version Total Downloads Latest Unstable Version License Monthly Downloads Daily Downloads

Demo in tests/RepositoryTest.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 github

Laravel Web Artisan

Latest Stable Version Total Downloads Latest Unstable Version License Monthly Downloads Daily Downloads

Installation

Add Presenter to your composer.json file:

"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.

'providers' => [
    ...
    Recca0120\Terminal\ServiceProvider::class,
    ...
];

publish

artisan vendor:publish --provider="Recca0120\Terminal\ServiceProvider"

URL

http://localhost/path/to/terminal

Whitelist

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)

find ./vendor -name tests -type d -maxdepth 4 -delete

Add Your Command

Add Command Class

// 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

// 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

$ help

Available Commands

Artisan List

$ artisan

Artisan List

Migrate

$ artisan migrate --seed

Migrate

Artisan Tinker

$ artisan tinker

Tinker

Find Command

$ find ./ -name * -maxdepth 1

Find Command

Find and Delete

$ find ./storage/logs -name * -maxdepth 1 -delete

Find and Delete

Vi

$ vi server.php

Vi Command

Vi Editor

Vi Save

Tail

$ tail
$ tail --line=1
$ tail server.php
$ tail server.php --line 5

Tail Command

Cleanup

$ cleanup

Cleanup Command

Laravel Tracy

一個laravel的debug工具,它是MIT的!大家可以安裝來試看看 用得習慣的話就請多多使用....

packagist.org github

Nette Tracy for Laravel 5

Better Laravel Exception Handler

Latest Stable Version Total Downloads Latest Unstable Version License Monthly Downloads Daily Downloads

Features

  • Visualization of errors and exceptions
  • Debugger Bar
  • Exception stack trace contains values of all method arguments.

Online Demo

Demo

Installing

To get the latest version of Laravel Exceptions, simply require the project using Composer:

composer require recca0120/laravel-tracy

Instead, you may of course manually update your require block and run composer update if you so choose:

{
    "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.

'providers' => [
    ...
    Recca0120\LaravelTracy\ServiceProvider::class,
    ...
];

publish

artisan vendor:publish --provider="Recca0120\LaravelTracy\ServiceProvider"

Config

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
];

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

Route

Route

View

View

Session

Session

Request

Request

Login

Login

Web Artisan

web artisan is another package recca0120/terminal Terminal

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 才發現可以利用它來改善我們的程式寫法 讓程式的可讀性更高

先讓我們看看用Promise來撰寫非同步code的樣子

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的寫法

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

2016年4月25日 星期一

ubuntu下安裝atom editor

只要執行三行指令即可

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

# centos
yum install php70w-pdo_dblib.x86_64

# ubuntu
sudo apt-get install freetds-bin php-sybase

接下來我們更改freetds的設定檔,裝連線設定為utf8

# centos
vi /etc/freetds.conf

# ubuntu
sudo vi /etc/freetds/freetds.conf

加入兩行設定即可

# centos
tds version = 7.2
client charset = UTF-8

# ubuntu
tds version = 7.1
client charset = UTF-8

freetds config

設定完成後連線到mssql charset就會是utf8 如果還是顯示為亂碼的話則可以利用tsql的指令來debug

tsql -S [ip] -U [username] -P [password]

tsql