2016年7月31日 星期日

Laravel 使用 GCS 做為儲存空間

前言
Laravel 有內建 Filesystem 套件,所以可以用來和例如 Amazon S3, Dropbox, Google Cloud Storage 等等服務串接

但找了一下發現和 Google Cloud Storage (GCS) 這方面的資料好像滿零散的
所以整理了一下

正文
GCS 使用的 API 和 S3 是相同的,但是目前只有 v2 有支援,所以需要安裝 v2 的 s3 相關套件,於 composer.json 的 require 加上

 { ...
 "league/flysystem-aws-s3-v2": "~1.0"
  }
 


然後 composer update 或是 install


再來是建立 GCS 專用的 Laravel Filesystem Provider Service
於 app\Providers 建立 GCSServiceProvider.php

 namespace App\Providers;
 
 use Illuminate\Support\ServiceProvider;
 use Storage;
 use Aws\S3\S3Client;
 use League\Flysystem\AwsS3v2\AwsS3Adapter;
 use League\Flysystem\Filesystem;
 
 class CloudStorageServiceProvider extends ServiceProvider{
     public function boot(){
         Storage::extend('gcs', function( $app, $config )
         {
             $client = S3Client::factory([
                 'key'    => $config['key'],
                 'secret' => $config['secret'],
                 'region' => $config['region'],
                 'base_url' => $config['base_url'],
             ]);
 
             return new Filesystem(new AwsS3Adapter($client, $config['bucket']));
         });
     }
 
     public function register(){
     }
 }
 


然後在 config/app.php 載入剛剛建立的 Provider
 providers => [
 ...
     App\Providers\GCSServiceProvider::class,
 ...
 ]
 



接下來是在 Laravel 中的 config/filesystem.php 加上 GCS 的設定
(這邊要到 Google Cloud Console 取得 Storage 相關的 API Key )

 'gcs' => [
     'driver' => 'gcs',
     'key' => 'KEYYYYYYY',
     'secret' => 'SEC_KEY',
     'region' => 'ASIA-EAST1',
     'bucket' => 'BUKET_NAME',
     'base_url'=>'https://storage.googleapis.com',
 ],
 



接下來就可以使用了,範例:
 $disk = Storage::disk('gcs');
 // public 為將此檔案公開
 $disk->put('123.txt', Good, file content’, public');
 
 // 刪除檔案
 $disk->delete('123.txt');
 

2016年7月21日 星期四

Laravel Unit Test (上)

前言:
之所以寫這篇教學 ( 筆記 ),是因為希望執行 Unit Test 時可以有個單純的環境,且完整的測試 DB 設計 ( migration )是否正確
所以找了一下將開發環境和測試環境 DB 分離的方法

正文開始:

  1.   這邊使用 memory 形式的 SQLite 來做為 Laravel 與 PHPUnit 測試時的 DB 設定
    於 config/database.php 的 'connections' => [ … 設定 sql_testing 做為 Test 環境使用,如下範例

'connections' => [ ...

'sqlite_testing' => [
            'driver'   => 'sqlite',
            'database' => ':memory:',
            'prefix'   => '',
        ],

… ]

  1. 然後於 tests/TestCase.php 加上 putenv('DB_CONNECTION=sqlite_testing');  變數,使用上步 (1) 建立的 config


   public function createApplication()
    {
        putenv('DB_CONNECTION=sqlite_testing');

        $app = require __DIR__.'/../bootstrap/app.php';

        $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();

        return $app;
    }

  1. 再來是 tests/TestCase.php 的 setUp 與 tearDown 加上 DB 的 migrate 與 reset

    public function setUp(){
        parent::setUp();
        Artisan::call('migrate');
        Artisan::call('db:seed');
    }

    public function tearDown(){
        Artisan::call('migrate:reset');
        parent::tearDown();
    }

  1. 接下來就可以開始測試了...






2016年6月26日 星期日

iOS 模擬器 couldn't be completed. (LaunchServicesError ... 解法



如果有使用 CocoaPods 的 XCode 專案,有時候會遇到一些鬼打牆的問題
例如 無緣無故忽然間就出現什麼 /bin/sh exit code 1
或是

The operation couldn't be completed. (LaunchServicesError error 0.)



Command /bin/sh failed with exit code 1

還是不能 copy 什麼 framework,出現 exit code 之類的

都有可能是專案沒有 Clean 乾淨 ( 一般的 Product -> Clean 可能無效)
這時候要按 Alt ,再選一次 Product -> Clean Build Folder ( 隱藏功能)
就有可能變正常了


2016年5月19日 星期四

Laravel 客制化登入頁面



這邊使用Laravel內建的User 資料表,可以先加上一些欄位
於 database/migrations/xxxx_create_users_table.php
加上 account 做示範,例如:

    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('account’); // !!
            $table->string('email')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

然後migrate db, User 的Model fillable 也要填寫

先建立認證用的Controller,這邊叫User
於終端機輸入
php artisan make:controller UserController



再來設定router.php,指定我們的登入頁與Controller
Route::get('/login', 'UserController@login');
Route::post('/login', 'UserController@login_check');



然後透過 Auth::attempt 來檢查使用者,UserController的範例如下:

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Input;
use App\Http\Requests;
use Auth;
use Redirect;

class UserController extends Controller
{
    function login(){
        return view('user/login');
    }

    function login_check(){
        $account = Input::get('account');
        $password = Input::get('password');
        if (Auth::attempt(array('account' => $account, 'password' => $password))){  // !!
            return Redirect::intended(‘home’); 
        }
        return view('user/login')->withErrors(array(
            'msg' => 'Account or Password Error.'
            ));
    }
}


withErrors 是在認證失敗,會將原因透過msg給view

view的範例如下:
(於 resources/views/user/login.blade.php )

<form  action="{{ url('/mlogin') }}">
    {!! csrf_field() !!}
    Account:<input type="text" name="nickname" /><br />
    Password:<input type="password" name="password" /><br />
    @if ($errors->has('msg'))
        <span >
            <strong>{{ $errors->first('msg') }}</strong>
        </span>
    @endif
    <input type="submit" />
</form>





2016年5月10日 星期二

[Android]Android Studio Error:Execution failed for task ':app:mergeDebugResources'. > String index out of range: 0

剛剛在編輯文字檔(strings.xml)時,因為先打了一堆的<string name=""></string>,想說直接輸入name跟value值就好了。
結果多餘的<string name=""></string>我既然忘記刪除啦~~

執行專案Android Studio就跑出這樣的錯誤了。如果你也遇到了,快去檢查你是否跟我遇到同樣的問題呢?
Error:Execution failed for task ':app:mergeDebugResources'. > String index out of range: 0