2012年12月3日 星期一

Composer簡介

什麼是Composer?

Composer是一個PHP的"dependency management"工具, 它能讓你指定你的Project裡需要用到的"dependent libraries", 並安娤這些libraries到你的project裡.

Dependency management

Composer不是"package manager", 雖然它是處理packages, 但它是在project的層面上管理, 通常是在project的根目錄下建立一個叫vendor的directory, 然後把packages安裝到這個directory裡. 一般情況下它不會安裝global的packages.

Composer解決的問題

  1. 你有一個project需要數個libraries.
  2. 在那些libraries當中, 有些需要依頼其他libraries.
  3. 你能自己定義你的project所依賴的libraries
  4. Composer找出所需安裝的packages及versions, 並安裝(事實上是下載)到project的vendor目錄

安裝

要安裝Composer, 在你的project的根目錄下執行
$ curl -s https://getcomposer.org/installer | php

以上指令會先檢查PHP的設定然後下載composer.phar到你的目錄下. 
要執行composer, 執行
php composer.phar

如果你想直接以composer執行, 可以把composer.phar 複制到/usr/local/bin中
$ sudo mv composer.phar /usr/local/bin/composer

定義dependencies

例如你需要在你的project裡用monolog, 先建立composer.json, 內容為
{
    "require": {
        "monolog/monolog": "1.2.*"
    }
}

require傳入的物件格式為{ "vendor name/package name" : "version" }
version可以是:
  1. Exact version: 如1.0.2
  2. Range: 如>=1.0,<2.0
  3. Wildcard: 1.0.*
  4. Next Significant Release: 如 ~1.2(相當於>=1.2,<2.0)

使用

執行以下指定, Composer會自動安裝你所定義的dependencies
$ php composer.phar install

composer.lock及composer.json

Composer執行install後會把安裝過的packages寫入composer.lock中, 而Composer每次執行install時會先確認composer.lock是否存在, 如果存在則安裝composer.lock中的packages, 不會理會composer.json, 如不存在則以composer.json裡的packages內容建立composer.lock. 所以執行install不會自動升級packages, 要升級需執行
$php composer.phar update

2012年10月25日 星期四

Symfony2 console commands

# Generate Bundle.
php app/console generate:bundle --namespace="My/Bundle" --format=yml
Doctrine

# Create database.
php app/console doctrine:database:create
# Generate Entity.
php app/console doctrine:generate:entity --entity="MyBundle:MyEntity"
# Generate Entities getters and setters.
php app/console doctrine:generate:entities MyBundle
# Update schema.
php app/console doctrine:schema:update --force
# Generate CRUD.
php app/console doctrine:generate:crud --entity="MyBundle:MyEntity"
Asset
# Install assets into web folder with symlink.
php app/console assets:install web --symlink

2012年10月24日 星期三

Doctrine以Composite及Foreign Keys作主鍵(Primary Key)

Doctrine2 可以用composite keys作為primary key(例如用戶的姓加名字作為主鍵), 而Doctrine2.1更支援關聯的foreign key.

方法很簡單:
  1. Entity內不能有@GeneratedValue, 除非設定為"ASSIGNED".
  2. 在需要作為primary key的property加上@Id這個annotation.
  3. 需要__construct() 方法在建立物件時傳入作為primary key的property, 因為primary key不是自動生成, 沒有primary key呼叫EntityManager#persist()會有問題.
<?php
use Doctrine\Common\Collections\ArrayCollection;

/** @Entity */
class Order
{
    /** @Id @Column(type="integer") @GeneratedValue */
    private $id;

    /** @ManyToOne(targetEntity="Customer") */
    private $customer;
    /** @OneToMany(targetEntity="OrderItem", mappedBy="order") */
    private $items;

    /** @Column(type="boolean") */
    private $payed = false;
    /** @Column(type="boolean") */
    private $shipped = false;
    /** @Column(type="datetime") */
    private $created;

    public function __construct(Customer $customer)
    {
        $this->customer = $customer;
        $this->items = new ArrayCollection();
        $this->created = new \DateTime("now");
    }
}

/** @Entity */
class Product
{
    /** @Id @Column(type="integer") @GeneratedValue */
    private $id;

    /** @Column(type="string") */
    private $name;

    /** @Column(type="decimal") */
    private $currentPrice;

    public function getCurrentPrice()
    {
        return $this->currentPrice;
    }
}

/** @Entity */
class OrderItem
{
    /** @Id @ManyToOne(targetEntity="Order") */
    private $order;

    /** @Id @ManyToOne(targetEntity="Product") */
    private $product;

    /** @Column(type="integer") */
    private $amount = 1;

    /** @Column(type="decimal") */
    private $offeredPrice;

    public function __construct(Order $order, Product $product, $amount = 1)
    {
        $this->order = $order;
        $this->product = $product;
        $this->offeredPrice = $product->getCurrentPrice();
    }
}
參考資料: http://docs.doctrine-project.org/projects/doctrine-orm/en/2.1/tutorials/composite-primary-keys.html

2008年6月18日 星期三

MySQL的一些操作技巧

如果要backup MySQL database, 可以用mysqldump save成text file, 可以保存整個database或個別table, 要restore時可以在mysql 裡用source filename即可.

MySQL statement裡可以用變數來增加變化, 如想在select的result裡最左邊加一個column來表示行數, 而這個行數本身沒有記錄在table裡, 是select statement執行的時間動態產生.方法是:

1. set @v1=0;
(這裡是宣告一個叫@v1的變數, 值為0)
2. select @v1:=@v1+1, name from table;
(這裡是把最左邊的column定為@v1, 而@v1每次都會+1, 所以可以代表行數, 也可以混合其他function, 如 concat('no. ',@v1:=@v1+1) 這樣行數會變成"no. 1", "no. 2", ...)
p.s. 要注意是用":="而不是平常statement用的"="

2008年5月14日 星期三

Drupal

安裝好Drupal, cleanURL無法啟動, drupal.org中提到需要在/etc/httpd/conf/http.conf中uncomment LoadModule rewrite_module modules/mod_rewrite.so 這行才可以.
但照做了也一樣無法啟動, 後來看下去才知道要加

<Directory "/var/www/html/drupal-6.2">
AllowOverride All
</Directory>

加了以後就能啟動

2008年4月7日 星期一

find 指令 time 選項及 xargs 一起使用

今天看了一下catchall的mailbox, 有9萬多封郵件, 我的postfix是以directory方式儲存郵件,每個郵件都是一個檔案, 開次一打開這個資料夾都很慢, 所以想按日期分類, 減少單一資料夾的檔案數.

我的catchall是以IMAP連接dovecot的式, 需要先create 一些按日期的資料夾, 以2008-01, 2008-02, ...的分類成式, 由於每個用也有兩萬封, 還是太多, 所以再在每個月裡create 01-10, 11-20, 11-31資料夾, 按日分類, 兩這些資料夾的實際path是在catchall Maildir/.INBOX.2008-01.01-10, Maildir/.INBOX.2008-01.11-20, ...把郵件按日期move到這些folder裡的new或cur即可(dovecot會在IMAP登入時把郵件從new移到cur).

但catchall inbox的郵件太多, 執行ls等指令很慢, 單用mv 及 rm等指令一次也不能處理太多檔案. 其中一個辦法是以find找到想移動的檔案再用xargs送到mv處理, find 能處理的檔案很多, 但好像也有限(至少9萬個處理不了, 會直接停止執行), 所以find的使用要有點技巧.

find的功能很多, 這次要以郵件檔的modification time來判斷它到達server的時間, 所以要用mtime選項(因為ctime在移動後會改為移動的時間, 所以執行第二次已經不能判斷).

find . -mtime n 當中 . 為目前路徑搜尋, n 為數字, 代表多少個24小時. mtime default是以當前時間的n*24小時計算, 如果想要以當日的24:00作基準(實際是向未來的時間方向移動,即明日的00:00的n*24小時計算),需要加上-daystart參數.

n 的數值為 0 時代表現在到24小時前之間, 加上daystart代表現在到今天00:00之間
n 的數值為 1 時代表24小時前到48小時前之間, 加上daystart代表今天00:00到昨天00:00之間(即整個昨天)
n 還可以加+或-, 分別代表1(24小時前到48小時前的時段)的兩邊, 但不包括1, 即-1代表現在(理論上是無限的未來)到24小時前的時段, +1代表48小時及之前(理論上是無限的過去)的時段. -0應該沒有任何結果, 除非有未來建做的檔案存在, 有這樣的檔案應該是電腦的時間調校錯了.
之外mtime可以組會使用, 如:
find . -mtime +1 -mtime -3 這裡指48小時前及未到72小時之間, 相當於 -mtime 2.

了解mtime的用法後回到剛才的一個問題上, find遇到超出數量時也不能運作, 所以在我那個有9萬個files的folder上使用時需要些技巧, 經我測試發覺組合的mtime是由左至右執行,例如我想找48小時前至72小時前之間的files, 需要用 -mtime +1 及 -mtime -3, 如果是:

find . -mtime +1 -mtime -3 這樣會先執行 +1 , 即所有48小時前的檔案, 以我的情況是至少有8萬多個, 一段時間後自動跳出執行, 沒有結果. 相反:

find . -mtime -3 -mtime +1 這樣會先執行 -3, 現在至72小時前之間, 有幾千, 沒有超出限量, 跟著再以 +1把現在至48小時前之間的除去, 得到我想要的結果.

以find 找到檔案後要送給xargs再執行mv:
find . -mtime -3 -time +1 | xargs -i mv {} destination.
當中 -i 代表用{}代表前面送來的結果(這裡即find的結果), {}代表find的結果, 並作為mv的source, destination代表目標路徑.
除了-i外可以用 -I, 差別是-I可以指定代表結果的字完, 如:
xargs -i mv {} /tmp
相當於:
xargs -I [] mv [] /tmp

最後成功把emails按日期分類.

2008年1月13日 星期日

NTP server 設定

安裝套件:
ntp: NTP server的主要套件啦,包括設定檔以及執行檔等等,都是這個套件提供的;

tzdata: 套件名稱為『 Time Zone data 』的縮寫,提供了各個時區對應的顯示格式。

主要檔案:
/etc/ntp.conf: ntp的主要設定檔.
/usr/sbin/ntpd: ntp的daemon, 啟動時會讀取ntp.conf的設定.
/usr/sbin/ntpdate: ntp的client, 用來連接NTP server.
/bin/date: 可以顯示或修改時間, 但不會存到BIOS.
/sbin/hwclock: root才能執行,把時間寫入BIOS.

ntp是使用類似於DNS的階層式的架構, 每一層稱為stratum, 下層stratum會向上曾同步, 最多可以有15層.在Linux架設ntp server主要設定ntp.conf

ntp.conf中可以用restrict參數來限制連線, 其用法是:
restrict [ip] mask [netmask_ip] [parameter]
parameter有:
  1. ignore 拒絶所有ntp連線,
  2. nomodify 用戶不能修改,
  3. noquery 用戶不能查詢,等於不提供網絡校時,
  4. notrap 不提供trap ( remote event logging ),
  5. notrust 拒絶沒有認証的用戶.
如沒加任何parameter代表不設任何限制,另外上層的NTP server必須在被允許的清單內才能同步.
設定上層NTP server:
server [ ip or hostname ] [ prefer ]
其中prefer代表優先使用

設定記錄BIOS與NTP server震盪的誤差:
driftfile [可以被ntpd寫入的目錄及檔案 ]

設定以certificate來控制權限:
key [ keyfile]

另外在 /etc/sysconfig/ntpd裡面的SYNC_HWCLOCK改為yes:
SYNC_HWCLOCK=yes
可以就會把ntpd同步的時間寫入BIOS中

Client可以用ntpdate [ip or hostname]來與NTP server同步時間,然後用hwclock -w寫入BIOS即可.
在/etc/crontab中加入
10 5 * * * /usr/sbin/ntpdate server_ip && /sbin/hwclock -w
可以在每天5:10時與server_ip同步時間.