2013年4月18日 星期四

Extjs

之前曾用過Extjs一段時間, 但總覺得Extjs的運作方式傾向於使用整個頁面作為一個Application的介面, 這另我很難簡單地在其他網頁上內嵌一些Extjs的Component, 而又不影響網頁本來的樣子, 最終放棄了這個使用方式.

最近突然想把Extjs的GridPanel放在一個用Bootstrap用theme的網頁上, 因為GridPanel實在做得很好, 不用有點可惜, 於是研究了一下

首先要在Html裡導入Extjs的js及css檔, 我用的是Extjs的gray theme, Extjs版本是4.2, css檔是/resources/ext-theme-gray/ext-theme-gray-all.css這個file. 導入後一看, 整個頁面的字型, 大小, 排版等都有些走樣了, 其原因主要是ext-theme-gray-all.css裡的一些CSS被應用到Extjs以外的DOM裡, 需要作以下修改:

.x-body { margin:0 }
Extjs會強制為body加上x-body這個class, 這有可能會對網頁做成影響, 而x-body只有這個margin:0的Style, 所以可以把x-body改成其他不會用的字串.

.x-border-box, .x-border * { box-sizing:borderbox;-moz-box-sizing:border-box;-ms-box-sizing:border-box;-webkit-box-sizing:border-box}
這個規則會同樣被應用到很多DOM上, 我把.x-border *改成.x-border .x-panel *, 這樣只有x-panel內的DOM會被加上border-box, 我只需要用GridPanel, 這已經夠了, 如果以後發現其他有些Extjs的Component不正常可以再修改

另外Bootstrap的CSS會設定lineheight, 這會導致Extjs的MessageBox有些走樣, 以後需要用到再看看怎樣解決


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按日期分類.