最近常常需要在沒有 phpMyAdmin 的情形下進行 MySQL 的操作,索性把一些常用的指令寫成了一個 tool,就叫做 MySQL Scripter 吧。
2014/11/26
2014/11/11
Laravel With Vagrant
一般 programmer 開發程式都是自己安裝自己的開發環境,不管在 Windows 或者是 Linux 都有所謂的懶人包,譬如說早期的 AppServ、 XAMPP 以及 WampServer,Linux 的部分也有,但我通常都是用套件管理裝的所以就不舉例了,如果大家都是 Windows 並且強迫安裝同一套就還好,但如果 A 同事是 Windows 愛用者,B 同事用 Ubuntu,C 同事用 Mac,這樣就有點麻煩了,虛擬機器這個 solution 就可以確保所有的人開發環境都一樣,目前最佳解大概就是 Vagrant + VirtualBox 了。
Vagrant 可以說是 VirtualBox 的管理套件,以往我們要使用 VirtualBox,就是開一個環境,然後 download 某個 OS 的 ISO 檔案,掛載虛擬光碟,然後再進 VirtualBox 慢慢安裝,Vagrant 可以讓你把已經設定好的環境打包成一個 box,有點類似 ghost,所以你可以找人家包好的環境,例如說今天需要一個「真正」的 IE 6 的測試環境,你可以去 http://www.vagrantbox.es/ 或者是 https://vagrantcloud.com/ 搜尋 Windows XP,看到有人打包了 indows XP with IE6
,我們就可以輕輕鬆鬆部屬這個環境,只要以下的指令即可。
vagrant add ie6_test http://aka.ms/vagrant-xp-ie6 vagrant ie6_test vagrant up
甚至你可以自己把自己建置好的環境打包給別人使用,今天來示範一下怎麼快速建置一個 Laravel 環境,Laravel 有製作自己的 Vagrant Box 叫 Homestead,我來一步步操作怎麼在 Windows 建立官方的範例。
下載 laravel/homestead
vagrant box add laravel/homestead
當然你要在你的電腦先裝好 Vagrant 以及 VirtualBox,當他跑完安裝以後,可以執行 vagrant box list
,如果有看到 laravel/homestead (virtualbox, 0.2.0)
代表你的 box 已經進來了,接下來我在 D:/
建立一個叫 vm
的資料夾,進入 D:/vm
,執行 git clone https://github.com/laravel/homestead.git Homestead
,成功後看到 D:/vm/Homestead
資料夾,進去之後打開 Homestead.yaml
來修改,一般來說我們要 init 一個新的 box 都是修改 Vagrantfile
這個 config,而 Laravel 這個 yaml 就是他們獨立出來的客製化 config,預設如下:
--- ip: "192.168.10.10" memory: 2048 cpus: 1 authorize: ~/.ssh/id_rsa.pub keys: - ~/.ssh/id_rsa folders: - map: ~/Code to: /home/vagrant/Code sites: - map: homestead.app to: /home/vagrant/Code/Laravel/public variables: - key: APP_ENV value: loca
ip
就是該虛擬機器的 ip,memory
就是你要給這台機器占用多少記憶體,authorize
以及 keys
是 Laravel 驗證 ssh 使用,folders
是指 folder sync,也就是說,假設我們在 D:/
建立了一個資料夾,將他跟 vm 裡面的開發資料夾做 sync 的話,我們就不用整天都要 ssh 進去該 vm 來改程式,只要改我們 D:/
的資料夾以後 vm 裡面的開發資料夾就會同步 sync 了,sites
就是將 domain name 指定到開發資料夾,如果你沒有要修改 hosts 的話,這個東西就沒有作用了,variables
就不用管,所以修改過後的內容如下:
--- ip: "192.168.10.14" memory: 1024 cpus: 1 authorize: C:/Users/YOUR_USER_NAME/.ssh/id_rsa.pub keys: - C:/Users/YOUR_USER_NAME/.ssh/id_rsa folders: - map: 'D:/vm/laravel' to: /home/vagrant/www sites: - map: laravel.app to: /home/vagrant/www/laravel/public variables: - key: APP_ENV value: local
如果你的驗證有問題的話,請執行 ssh-keygen -t rsa -C "you@homestead"
,如果順利起來的話,執行 vagrant ssh
就可以直接進入 server,如果你想用其他的 ssh 軟體,只要指定 ssh 127.0.0.1 2222
即可,帳號密碼都是 vagrant,我們進入剛指定的資料夾 /home/vagrant/www
,開始建立我們的 Laravel 專案,執行 composer create-project laravel/laravel --prefer-dist
,composer 會開始幫我們載入檔案,我們可以切換到 D:/vm/laravel
資料夾,應該多了一個 laravel 資料夾並且正在同步下載檔案,安裝完畢後在 browser 跑 192.168.10.14
,如果看到 Laravel 歡迎畫面,表示打完收工。
Homestead 幫你打造了下列的環境:
- Ubuntu 14.04
- PHP 5.6
- HHVM
- Nginx
- MySQL
- Postgres
- Node (With Bower, Grunt, and Gulp)
- Redis
- Memcached
- Beanstalkd
- Laravel Envoy
- Fabric + HipChat Extension
實用的 vagrant 指令
vagrant box list # 列出現在所有的 box vagrant box remove xxx # 移除某個 box vagrant destroy # 將某個目錄下的 vm 銷毀 vagrant status # 查看目前 vm 的狀況 vagrant halt # 關閉目前的 vm vagrant reload # 重啟 vm
2014/11/07
Transaction With Eloquent
今天研究 Database Transaction 的時候發現了一招可以 Eloquent 跟 Transaction 混用。
<? $user = new User; $user->name = 'Chan'; $member = new Member; $member->age = 33; DB::transaction(function() use ($user, $member) { try { $user->save(); $member->save(); } catch (Exception $e) { dd($e->getMessage()); } });
Abstract Interface Traits 差異
PHP 對於 class 的使用方式很多,在這邊做一下筆記整理。
Basic
<?php class Main { public function foo() { echo 'foo'; } } class Sub extends Main { public function bar() { echo 'bar'; } } $sub = new Sub; $sub->bar(); // bar $sub->foo(); // foo
這是最基本的 class 應用,Sub
extends 了 Main
,因此可以在 Sub
拿到 protected
以及 public
的變數以及使用 function。
Interface
<?php interface Main { public function foo(); } class Sub implements Main { public function bar() { echo 'bar'; } } $sub = new Sub; $sub->bar(); // bar
interface 是規範 class 一定要有對應的 function 宣告,所以上面的例子退吐出下列的錯誤訊息。
Fatal error: Class Sub contains 1 abstract method and must therefore be declared abstract or implement the remaining methods
我們只要宣告一個同等名稱的 function 即可。
<?php interface Main { public function foo(); } class Sub implements Main { public function foo() { } public function bar() { echo 'bar'; } } $sub = new Sub; $sub->bar(); // bar
interface
本身是不可以下功能的,所以通常設計來當作一種使用規範。
abstract
<?php abstract class Main { abstract public function foobar(); public function foo() { echo 'foo'; } } class Sub extends Main { public function bar() { echo 'bar'; } } $sub = new Sub; $sub->foo(); // foo $sub->bar(); // bar
abstract
等於 basic
用法跟 interface
用法的集合,所以上述的內容會吐出錯誤訊息。
Fatal error: Class Sub contains 1 abstract method and must therefore be declared abstract or implement the remaining methods
此時我們要在 Sub
加上對應的 function name。
<?php abstract class Main { abstract public function foobar(); public function foo() { echo 'foo'; } } class Sub extends Main { public function foobar() { } public function bar() { echo 'bar'; } } $sub = new Sub; $sub->foo(); // foo $sub->bar(); // bar
traits
<?php trait Main { public function foo() { echo 'foo'; } } class Sub { use Main; public function bar() { echo 'bar'; } } $sub = new Sub; $sub->foo(); // foo $sub->bar(); // bar
trait
是一個有趣的東西,他可以透過 use
的方式直接調用 class,彈性無比的大,但確切的使用時機目前我還不清楚。
大亂鬥
<?php abstract class Cool { abstract public function foo3(); public function foo2() { echo 'foo2'; } } interface Happy { public function foo4(); } interface Smile { public function foo5(); } trait Main { public function foo() { echo 'foo'; } } class Sub extends Cool implements Happy, Smile { use Main; public function bar() { echo 'bar'; } public function foo3() { } public function foo4() { } public function foo5() { } } $sub = new Sub; $sub->foo(); // foo $sub->bar(); // bar $sub->foo2(); // foo2
2014/11/06
MongoDB 初探
NoSQL 紅一陣子了,比較有名的不外乎是 Redis 或者是 MongoDB,Redis 一般來說比較會運用在快取上(類似 memcached),MongoDB 比較會使用在 persistence database solution,來示範一下這兩天試用 Mongo 的心得。
安裝
http://www.mongodb.org/downloads
MongoDB 對各家 OS 支援度很高,今天測試的環境是 Windows,所以我們就下載 Windows 的版本,我是下載了 zip 版本,下載後將壓縮檔案內 bin 資料夾下的檔案全部複製到 c:\mongodb
PHP 預設是沒有支援 MongoDB 的,但安裝方式很簡單,首先我們去下載 dll 檔案,下載最新的版本 php_mongo-1.5.7.zip
,解壓縮後選擇符合你 server 版本的 dll,將他複製到 PHP 的 ext 資料夾,並且更名為 php_mongo.dll,修改 php.ini
,加入 extension=php_mongo.dll
,重啟 Apache,接著看一下 phpinfo
,如果你看到以下的畫面,表示你已經成功了。
啟用
基本的 MongoDB 啟用很簡單,首先我在 c:\mongodb
下多建了一個 db
資料夾,接著啟用他。
mongod --dbpath="c:\mongodb\db"
如果沒有任何的錯誤訊息,恭喜你成功啟用了
使用
http://us3.php.net/manual/en/book.mongo.php
PHP 官方有非常詳細的使用文件,我們來看幾個比較常用的例子。
Connection
$m = new MongoClient(); $db = $m->selectDB('db');
若預設值如 ip 以及 port 沒改變的話,這是最基本的連線方式,當然還有其他的連線方式,甚至可以做到 replica。
$m = new MongoClient(); $db = $m->selectDB('db'); $users = $db->users; echo $users->count(); // 0
MongoDB 的資料是一種 collection 的概念要存取相當簡單,上面的例子指定了 users
這個 connection,但我們沒有任何的資料,所以 count 的結果當然是 0,接下來我們塞一些資料進去。
$m = new MongoClient(); $db = $m->selectDB('db'); $users = $db->users; $data = array( 'name' => 'Chan', 'age' => 34 ); $users->insert($data); echo $users->count(); // 1
上面的例子我們使用了 insert
功能塞進了一筆資料,count 的結果就變成 1 了,如果 refresh 頁面的話數字就會變成 2,若要多重存取的話可以使用另一個 batchInsert
function。
$m = new MongoClient(); $db = $m->selectDB('db'); $users = $db->users; $users->drop(); $data = array( array( 'name' => 'Chan', 'age' => 34 ), array( 'name' => 'Phoebe', 'age' => 35 ) ); $users->batchInsert($data); echo $users->count(); // 2
上面的範例為了避免資料重複的 insert,所以我多加了 $users->drop()
的 function,此時 count 的結果就為 2 了,接下來我們來抓取資料。
$m = new MongoClient(); $db = $m->selectDB('db'); $users = $db->users; $users->drop(); $data = array( array( 'name' => 'Chan', 'age' => 34 ), array( 'name' => 'Phoebe', 'age' => 35 ) ); $users->batchInsert($data); foreach ($users->find() as $id => $item) { echo 'id: ' . $id; var_dump($item); }
我們會得到
id: 545af6263ad521b819000031 array (size=3) '_id' => object(MongoId)[9] public '$id' => string '545af6263ad521b819000031' (length=24) 'name' => string 'Chan' (length=4) 'age' => int 34 id: 545af6263ad521b819000032 array (size=3) '_id' => object(MongoId)[10] public '$id' => string '545af6263ad521b819000032' (length=24) 'name' => string 'Phoebe' (length=6) 'age' => int 35
以上就是最基本的存跟取了,其他的條件式 PHP 官網有詳細的範例,SQL to Mongo Mapping Chart。
SQL Statement | Mongo Query Language Statement |
---|---|
CREATE TABLE USERS (a Number, b Number) | Implicit or use MongoDB::createCollection(). |
INSERT INTO USERS VALUES(1,1) | $db->users->insert(array("a" => 1, "b" => 1)); |
SELECT a,b FROM users | $db->users->find(array(), array("a" => 1, "b" => 1)); |
SELECT * FROM users WHERE age=33 | $db->users->find(array("age" => 33)); |
SELECT a,b FROM users WHERE age=33 | $db->users->find(array("age" => 33), array("a" => 1, "b" => 1)); |
SELECT a,b FROM users WHERE age=33 ORDER BY name | $db->users->find(array("age" => 33), array("a" => 1, "b" => 1))->sort(array("name" => 1)); |
SELECT * FROM users WHERE age>33 | $db->users->find(array("age" => array('$gt' => 33))); |
SELECT * FROM users WHERE age<33 | $db->users->find(array("age" => array('$lt' => 33))); |
SELECT * FROM users WHERE name LIKE "%Joe%" | $db->users->find(array("name" => new MongoRegex("/Joe/"))); |
SELECT * FROM users WHERE name LIKE "Joe%" | $db->users->find(array("name" => new MongoRegex("/^Joe/"))); |
SELECT * FROM users WHERE age>33 AND age<=40 | $db->users->find(array("age" => array('$gt' => 33, '$lte' => 40))); |
SELECT * FROM users ORDER BY name DESC | $db->users->find()->sort(array("name" => -1)); |
CREATE INDEX myindexname ON users(name) | $db->users->ensureIndex(array("name" => 1)); |
CREATE INDEX myindexname ON users(name,ts DESC) | $db->users->ensureIndex(array("name" => 1, "ts" => -1)); |
SELECT * FROM users WHERE a=1 and b='q' | $db->users->find(array("a" => 1, "b" => "q")); |
SELECT * FROM users LIMIT 20, 10 | $db->users->find()->limit(10)->skip(20); |
SELECT * FROM users WHERE a=1 or b=2 | $db->users->find(array('$or' => array(array("a" => 1), array("b" => 2)))); |
SELECT * FROM users LIMIT 1 | $db->users->find()->limit(1); |
EXPLAIN SELECT * FROM users WHERE z=3 | $db->users->find(array("z" => 3))->explain() |
SELECT DISTINCT last_name FROM users | $db->command(array("distinct" => "users", "key" => "last_name")); |
SELECT COUNT(*y) FROM users | $db->users->count(); |
SELECT COUNT(*y) FROM users where AGE > 30 | $db->users->find(array("age" => array('$gt' => 30)))->count(); |
SELECT COUNT(AGE) from users | $db->users->find(array("age" => array('$exists' => true)))->count(); |
UPDATE users SET a=1 WHERE b='q' | $db->users->update(array("b" => "q"), array('$set' => array("a" => 1))); |
UPDATE users SET a=a+2 WHERE b='q' | $db->users->update(array("b" => "q"), array('$inc' => array("a" => 2))); |
DELETE FROM users WHERE z="abc" | $db->users->remove(array("z" => "abc")); |