0

CakePHP app กับ userdir

เวลาเอา web app ที่เขียนด้วย cakephp ไปใส่ใน userdir เช่น /home/veer/public_html/myapp (ซึ่งมักจะไปตรงกับ url http://hostname/~veer/myapp) มักจะมีปัญหากับ mod_rewrite ขึ้นมา แต่ก็แก้ไม่ยาก เพียงแต่แก้ .htaccess ใน myapp กับ myapp/app/webroot

เดิมทีจะเขียนไว้ประมาณนี้ (ใน myapp กับ myapp/app/webroot ไม่เหมือนกัน แต่ก็แก้เหมือนกัน)


   RewriteEngine on
   RewriteRule    ^$ app/webroot/    [L]
   RewriteRule    (.*) app/webroot/$1 [L]

ก็แก้โดยใส่ RewriteBase เข้าไปเป็นแบบนี้


   RewriteEngine on
   RewriteBase    /~veer/myapp
   RewriteRule    ^$ app/webroot/    [L]
   RewriteRule    (.*) app/webroot/$1 [L]

เสร็จแล้ว

0

History สำหรับ CakePHP Model

สิ่งผมเขียนไม่ใช่ best practice จริงๆ แล้วผมก็ไม่ค่อยแน่ใจว่ามันจะใช้ได้ดีหรือเปล่า แต่ว่าก็บันทึกไว้ก่อน. เว็บที่ผมเขียนมักจะต้องทำอะไรประเภทมี version control ด้วย แนวๆ wiki ดังนั้นถ้า model ช่วงแบ่งเบาภาระพวก version control ไปได้บ้าง ก็ทำให้ controller ดูรกน้อยลงไปมาก (หวังว่าแบบนั้น) ก่อนหน้านี้ CakePHP เคยมี behavior ด้วยช่วยเก็บ history มาให้ถ้าจำไม่ผิด แต่ตอนนี้หาไม่เจอแล้ว และเพื่อให้ได้อย่างใช้ตัวเองผมก็เลยใช้แค่ callback function.

model ที่ผมต้องการจำ history ชื่อ Textunit สมมุตว่า textunits เป็น table มี column ได้แก่ id และ string เอาแค่นี้ก็พอ เพื่อเป็นตัวอย่าง วิธีของผมก็คือสร้างขึ้นมาอีก table เลยชื่อ history_textunits โดยมี column ดังนี้ id, old_id, revision และ string

จากนั้นก็สร้าง code ใน app/model ตามนี้

<?php
class Textunit extends AppModel {
   var $name = 'Textunit';
   var $history = 'HistoryTextunits';

    function beforeSave() {
        if(!empty($this->id)) {
            $historyModel = ClassRegistry::init($this->history);
            $historyData = $this->findById($this->id);
            $historyModel->record($historyData[$this->name]);
        }                 
        return true;
    }
}
?>

และ

<?php
class HistoryTextunits extends AppModel {
    var $name = 'HistoryTextunits';
    function record($textunit) {
        $history = array();
        foreach($textunit as $k => $v) {
            if($k == "id") 
                $k = "old_id";
            $history[$k] = $v;
        }
        $this->create();
        $this->save($history);
    }
}
?>

แค่นี้เอง :-P

0

CakePHP: สร้าง model แบบ many-to-many อย่างง่าย(มาก)

เวลาใช้ ORM ของ CakePHP เรื่องหนึ่งที่ผมรู้สึกว่าจะซับซ้อนสักหน่อย อย่างน้อยๆ ก็สำหรับผมก็คือ เวลาเขียน model ให้ใช้ความสัมพันธ์แบบ many to many ที่ต้องใส่ parameter เยอะ.

แต่ว่ามันก็ไม่จำเป็นต้องยากเสมอไป ถ้าเราเป็นรู้ก่อน ว่า convention ของ CakePHP คืออะไรแล้วก็เขียนตามนั้น

สมมุติว่าเรามี 2 table ได้แก่ documents และ tags ที่จะให้สัมพันธ์กัน แบบ many to many. แน่นอนต้องมี table ที่เอาไว้เก็บความสัมพันธ์โดยเฉพาะเลยอีก table หนึ่ง แต่ปัญหาก็มีอยู่ว่าให้ชื่อว่าอะไรดี ตามวิธีของ CakePHP คือต้องสร้าง table ใหม่ขึ้นมาชื่อเรียกตามลำดับตัวอักษร ในกรณีนี้คือ documents_tags ถ้าต้องว่า tags_documents แบบนี้ไม่ได้ เพราะว่าตัว d มันต้องมาก่อนตัว t ส่วน field ใน table ก็ประกอบด้วย id, document_id, tag_id

แล้วก็เขียน code แบบนี้

สำหรับ document.php

<?php
class Document extends AppModel {
	var $name = 'Document';
        var $hasAndBelongsToMany = 'Tag';
}
?>

สำหรับ tag.php

<?php
class Tag extends AppModel {
	var $name = 'Tag';
    var $hasAndBelongsToMany = 'Textunit';
}
?>

เพิ่มอีกไฟล์ละบรรทัดเองง่ายมาก แต่ว่าจะทำอะไรซับซ้อนกว่านี้ก็ได้ แต่ว่าสำหรับผมตอนนี้แค่นี้ก็พอใช้แล้ว

อ้างอิง
http://book.cakephp.org/view/78/Associations-Linking-Models-Together

0

CakePHP ออก 1.2 RC1 แล้ว

CakePHP ออก 1.2 RC1 แล้ว หลังจากเป็น Beta อยู่นานเหมือนกัน. และตามมาด้วยต้องออกแรงกันนิดหน่อยเพื่อที่จะ migrate จาก beta ไป rc1 ดูได้ที่ http://cakebaker.42dh.com/2008/06/05/migrating-from-cakephp-12beta-to-rc1/

ช่วงนี้ผมคงยังไม่ได้เขียน web แต่เขียน blog ไว้ก่อนกันลืม :-P

1

CakePHP + timestamp

เวลา save แล้วอยากให้ CakePHP ใส่ timestamp ให้ด้วยเวลาที่ row ที่ add เข้าไปถูก create เป็นครั้งแรก. ประมาณว่าต้องการเก็บว่า row นั้นสร้างมาแต่เมื่อไหร่. ผมใช้ callback function ใน model เอา เขียนสั้นๆ ก็เป็นอันใช้ได้.

class Corpus extends AppModel {
    function afterSave($created) {
        if($this-&gt;id &amp;&amp; $created) {
            $data = $this-&gt;read();
            $data[$this-&gt;name]["created"] = date("Y-m-d H:i:s");
            $this-&gt;save($data);
        }
    }
}

เวลาสั่ง save จาก controller, afterSave ก็จะถูกเรียกแล้วก็ไปแก้ column: created ให้เป็นเวลาปัจจุบัน. ถ้า row นั้นถูกสร้างขึ้นใหม่ (ตรวจสอบได้จาก $created).

update #1: แต่จะให้ดีใช้ beforeSave ดีกว่า. จะได้ save ครั้งเดียวไปเลย (ตาม comment ของ พี่ป๊อก) แล้วก็ดูเป็นธรรมชาติดีด้วย :-).

class Corpus extends AppModel {
    function beforeSave() {
        $data[$this-&gt;name]["created"] = date("Y-m-d H:i:s");
        return true;
    }
}

แต่ถ้า edit แต่ไม่ได้ create corpus ก็คงต้องวิธีมาตรวจสอบเอา.

update #2: ลองดูอีกนิด จริงๆ แล้วไม่ต้องใช้ before/after save เลย. CakePHP ทำ timestamp ให้เองแบบที่ต้องการเลย โดยที่ไม่ต้องทำอะไร … แป่ว

0

CakePHP 1.2 + ภาษาไทย + UTF-8 + MySQL

default encoding ของ MySQL เท่าที่ผมใช้ไม่ได้เป็น UTF-8. เวลาใช้ CakePHP ก็เลยต้องแก้ configuration นิดหน่อยเพื่อทำให้ ใช้ UTF-8 และ MySQL ได้เนียนๆ. ใน CakePHP รุ่นก่อนๆ หน้านี้บางทีก็ต้องไปแก้ AppModel ที่ไม่ค่อยเท่เท่าไหร่ เพราะน่าจะต้องมาแก้อีกเวลา port ไปใช้ database ตัวอื่นที่ไม่ใช่ MySQL.

ใน Cake 1.2.x สามารถตั้งค่า encoding/charset แบบรวมศูนย์ได้ใน app/config/database.php เลย. ตามตัวอย่างแบบด้านล่าง

class DATABASE_CONFIG {

    var $default = array(
        'driver' =&gt; 'mysql',
        'persistent' =&gt; false,
        'host' =&gt; 'localhost',
        'login' =&gt; 'your_username',
        'password' =&gt; 'your_password',
        'database' =&gt; 'my2',
        'prefix' =&gt; '',
        'encoding' =&gt; 'UTF8' #ดูบรรทัดนี้เป็นสำคัญ
    );

    var $test = array(
        'driver' =&gt; 'mysql',
        'persistent' =&gt; false,
        'host' =&gt; 'localhost',
        'login' =&gt; 'user',
        'password' =&gt; 'password',
        'database' =&gt; 'test_database_name',
        'prefix' =&gt; '',
    );
}
?&gt;

เพื่อม ‘encoding’ => ‘UTF8′ เข้าไปก็ทำให้ใช้ภาษาไทยและ UTF-8 ได้เนียนๆ แล้ว.

พอมาเปิดใน phpmyadmin ที่ตั้งค่าให้ใช้ UTF-8 และภาษาไทย

ก็แสดงผลออกมาได้ถูกต้อง.

สรุปว่าถ้าอยากใช้ UTF-8 กับ MySQL ใน CakePHP 1.2.x ก็เข้าไปตั้งค่าได้ใน app/config/database.php

อ้างอิง

0

ปรับแต่ง Pluralization บน CakePHP

ก่อนที่จะใช้ CakePHP และ Ruby on Rails ก็คิดว่าโปรแกรมพวกนี้เจ๋งจริงๆ ทำ Pluralization ให้ได้เลย ไม่ใช่แค่เติม s ให้เฉยๆ ด้วย. แต่แล้วพอเอามาทำโปรแกรมก็เจอ corpus -> corpora เข้าไป CakePHP ก็ทำ pluralization ให้ไม่ได้ซะงั้น. แต่ก็ไม่ใช่เรื่องใหญ่แต่อะไร สามารถปรับได้จากไฟล์ app/config/inflections.php

ในกรณีของผม ผมก็เพิม case นี้เข้าไปเลย

 $irregularPlural = array("corpus" =&gt; "corpora");

ก็เป็นอันว่าใช้ได้ :-).

0

เรียก cake acl … ได้โดยไม่ต้องแก้ dbo_source.php แล้ว

ทีแรกผมลองเอา code จาก svn trunk (svn co https://svn.cakephp.org/repo/trunk/cake/1.2.x.x cake12) ของ CakePHP มาใช้ ก็ยังไม่ได้แก้อะไร. แต่ถามไปอ่านใน trac เขาก็บอกว่าแก้แล้ว. https://trac.cakephp.org/ticket/3793 ถามต่อไปใน changeset อีก https://trac.cakephp.org/changeset/6312 ทีนี้ก็เห็นแล้วว่า code ส่วนที่แก้อยู่ใน branch …  svn co https://svn.cakephp.org/repo/branches/1.2.x.x cake12. ก็เป็นอันว่าแก้ไปแล้ว.

2

CakePHP 1.2.0.6311b: Group + ACL + AuthComponent

หลังจากที่ใช้ ACL กับ AuthComponent ได้แล้ว … ก็จะลองเปลี่ยนตัวอย่างเก่าให้ใช้ Group ได้ดู ก็แก้เยอะเหมือน :-P.

ผมเริ่มจากการแก้ database schema ก่อน. หลังจากที่ลองใช้ migration อยู่พักใหญ่แล้วผมก็งงๆ เลยตัดสินใจสละ table: aros และ users ไป.

เริ่มจากลบของใน table: aros และ aros_acos ก่อน ด้วยคำสั่ง:

mysql -u<your_username> -p<your_password> my_project -e 'delete from aros;'
mysql -u<your_username> -p<your_password> my_project -e 'delete from aros_acos;'

แล้วก็แก้ CakeSchema ของ user ใน folder: app/config/sql, ไฟล์: users.php แก้เป็นแบบนี้:

class UsersSchema extends CakeSchema {

    var $name = 'users';

    function before($event = array()) {
        return true;
    }

    function after($event = array()) {
    }

    var $users =
        array('id' =&gt; array('type'=&gt;'integer',
                            'null' =&gt; false,
                            'key' =&gt; 'primary',
                            'extra' =&gt; 'auto_increment'),
              'username' =&gt;  array('type'=&gt;'string',
                                   'null' =&gt; false,
                                   'length' =&gt; 255),
              'password' =&gt;  array('type'=&gt;'string',
                                   'null' =&gt; false,
                                   'length' =&gt; 255),
              'group_id' =&gt; array('type' =&gt; 'integer',
                                  'null' =&gt; false),
              'indexes' =&gt; array('PRIMARY' =&gt; array('column' =&gt; 'id',
                                                    'unique' =&gt; 1)));
    var $groups =
        array('id' =&gt; array('type' =&gt; 'integer',
                            'null' =&gt; false,
                            'key' =&gt; 'primary',
                            'extra' =&gt; 'auto_increment'),
              'name' =&gt; array('type' =&gt; 'string',
                              'null' =&gt; 'false',
                              'length' =&gt; 255,
                              'unique' =&gt; true),
              'parent_id' =&gt; array('type' =&gt; 'integer'),
              'indexes' =&gt; array('PRIMARY' =&gt; array('column' =&gt; 'id',
                                                    'unique' =&gt; true),
                                 'GRP_NAME_KEY' =&gt; array('column' =&gt; 'name',
                                                         'unique' =&gt; true)));

ของใหม่อีกอย่างหนึ่งในตัวอย่างนี้คือ AclBehavior ที่จะช่วย sync ระหว่าง users, groups และ acl. แต่เท่าที่ใช้มา AclBehavior ไม่แก้ค่า alias ใน Aro ก็เลยสร้าง AclaBehavior จากการดัดแปลง AclBehavior นิดๆ หน่อยๆ โดยเพิ่มไฟล์ acla.php ลงใน folder: app/model/behaviors แบบข้างล่าง (จริงแล้วต้องเปิด <?php และปิดด้วย ?> ด้วย … แต่ว่าใส่ใน wordpress แล้วเหมือนเพี้ยนๆ ผมก็แก้ไม่เป็นด้วย.)

/* SVN FILE: $Id: acl.php 6311 2008-01-02 06:33:52Z phpnut $ */
/**
 * ACL behavior class.
 *
 * Enables objects to easily tie into an ACL system
 *
 * PHP versions 4 and 5
 *
 * CakePHP :  Rapid Development Framework 
 * Copyright 2006-2008, Cake Software Foundation, Inc.
 *                                1785 E. Sahara Avenue, Suite 490-204
 *                                Las Vegas, Nevada 89104
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @filesource
 * @copyright        Copyright 2006-2008, Cake Software Foundation, Inc.
 * @link                http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
 * @package            cake
 * @subpackage        cake.cake.libs.model.behaviors
 * @since            CakePHP v 1.2.0.4487
 * @version            $Revision: 6311 $
 * @modifiedby        $LastChangedBy: phpnut $
 * @lastmodified    $Date: 2008-01-02 00:33:52 -0600 (Wed, 02 Jan 2008) $
 * @license            http://www.opensource.org/licenses/mit-license.php The MIT License
 */
/**
 * Short description for file
 *
 * Long description for file
 *
 * @package        cake
 * @subpackage    cake.cake.libs.model.behaviors
 */
class AclaBehavior extends ModelBehavior {

/**
 * Maps ACL type options to ACL models
 *
 * @var array
 * @access protected
 */
    var $__typeMaps = array('requester' =&gt; 'Aro', 'controlled' =&gt; 'Aco');
/**
 * Sets up the configuation for the model, and loads ACL models if they haven't been already
 *
 * @param mixed $config
 */
    function setup(&amp;$model, $config = array()) {
        if (is_string($config)) {
            $config = array('type' =&gt; $config);
        }
        $this-&gt;settings[$model-&gt;alias] = array_merge(array('type' =&gt; 'requester'), (array)$config);
        $type = $this-&gt;__typeMaps[$this-&gt;settings[$model-&gt;alias]['type']];

        if (!ClassRegistry::isKeySet($type)) {
            uses('model' . DS . 'db_acl');
            $object =&amp; new $type();
        } else {
            $object =&amp; ClassRegistry::getObject($type);
        }
        $model-&gt;{$type} =&amp; $object;
        if (!method_exists($model, 'parentNode')) {
            trigger_error("Callback parentNode() not defined in {$model-&gt;alias}", E_USER_WARNING);
        }
    }
/**
 * Retrieves the Aro/Aco node for this model
 *
 * @param mixed $ref
 * @return array
 */
    function node(&amp;$model, $ref = null) {
        $type = $this-&gt;__typeMaps[strtolower($this-&gt;settings[$model-&gt;alias]['type'])];
        if (empty($ref)) {
            $ref = array('model' =&gt; $model-&gt;alias, 'foreign_key' =&gt; $model-&gt;id);
        }

        return $model-&gt;{$type}-&gt;node($ref);
    }
/**
 * Creates a new ARO/ACO node bound to this record
 *
 * @param boolean $created True if this is a new record
 */
    function afterSave(&amp;$model, $created) {
        if ($created) {
            $type = $this-&gt;__typeMaps[strtolower($this-&gt;settings[$model-&gt;alias]['type'])];
            $parent = $model-&gt;parentNode();

            if (!empty($parent)) {
                $parent = $this-&gt;node($model, $parent);
            } else {
                $parent = null;
            }

            $acl_node_alias = null;

            if(method_exists($model, "aclNodeAlias"))
                $acl_node_alias = $model-&gt;aclNodeAlias();

            $model-&gt;{$type}-&gt;create();
            $model-&gt;{$type}-&gt;save(array(
                'parent_id'        =&gt; Set::extract($parent, "0.{$type}.id"),
                'model'            =&gt; $model-&gt;alias,
                'foreign_key'    =&gt; $model-&gt;id,
                'alias'         =&gt; $acl_node_alias
            ));
        }
    }
/**
 * Destroys the ARO/ACO node bound to the deleted record
 *
 */
    function afterDelete(&amp;$model) {
        $type = $this-&gt;__typeMaps[strtolower($this-&gt;settings[$model-&gt;alias]['type'])];
        $node = Set::extract($this-&gt;node($model), "0.{$type}.id");
        if (!empty($node)) {
            $model-&gt;{$type}-&gt;delete($node);
        }
    }
}

ไม่พอก็ยังต้องแก้ CakeShell ต่อใน folder: app/vendors/shells

แก้ user.php:

uses ('controller'.DS.'components'.DS.'auth');

class UserShell extends Shell {
    var $uses = array("User", "Group");
    function add() {
        $auth = new AuthComponent();
        $username = $this-&gt;args[0];
        $password = $auth-&gt;password($this-&gt;args[1]);
        $grp_name = $this-&gt;args[2];
        $grp = $this-&gt;get_group($grp_name);
        $data = array("User" =&gt;
                      array("username" =&gt; $username,
                            "password" =&gt; $password,
                            "group_id" =&gt; $grp["id"]));
        if($this-&gt;User-&gt;save($data))
            print "Success: $username was added\n";
        else
            print "Fail\n";
    }

    function get_group($name) {
        $data = $this-&gt;Group-&gt;findByName($name);
        if(!$data)
            return null;
        else
            return $data["Group"];

    }
}

สร้าง group.php ขึ้นมาใหม่:

class GroupShell extends Shell {

    var $uses = array("Group", "Aro");

    function add() {
        $name = $this-&gt;args[1];
        $parent_name = $this-&gt;args[0];
        if($parent_name == '/')
            $parent_id = null;
        else
            $parent_id = $this-&gt;get_parent($parent_name);
        $data = array("Group" =&gt;
                      array("parent_id" =&gt; $parent_id,
                            "name" =&gt; $name));
        if($this-&gt;Group-&gt;save($data))
            print "Success: group: $name has been added\n";
        else
            print "Fail\n";
    }

    function get_parent($name) {
        $data = $this-&gt;Group-&gt;findByName($name, null, null, False);
        if(!$data['Group']['id'])
            return null;
        else
            return $data['Group']['id'];
    }
}

ยังไม่หมดต้องมาแก้ model ต่อใน folder: app/model

แก้ user.php:

class User extends AppModel {
    var $actsAs = array('Acla');
    var $belongsTo = array('Group');

    function parentNode() {
        if(!$this-&gt;id)
            return null;

        $data = $this-&gt;read();
        if(!$data['Group']['id'])
            return null;
        else
            return array('model' =&gt; 'Group',
                         'foreign_key' =&gt; $data['Group']['id']); 
    }
}

ตามด้วยเขียน group.php ขึ้นมาใหม่:

class Group extends AppModel {
    var $actsAs = array('Acla');
    var $hasMany = array('User');
    function parentNode() {
        if(!$this-&gt;id)
            return null;
        $data = $this-&gt;read();
        if(!$data['Group']['parent_id'])
            return null;
        else
            return array('model' =&gt; 'Group',
                         'foreign_key' =&gt; $data['Group']['parent_id']);
    }

    function aclNodeAlias() {
        if(!$this-&gt;id)
            return null;
        $data = $this-&gt;read();
        if(!$data['Group']['name'])
            return null;
        else
            return $data['Group']['name'];
    }

}

จาก code ที่แก้มามากมายก็จะเริ่มเรียกใช้แล้ว. โดย cd เข้าไปใน cake/console สั่ง: ./cake schema run create users แล้วก็กด y ไปเรื่อยๆ. เพื่อที่จะ drop table: users เก่าทิ้งไป แล้วสร้าง table: users และ groups ขึ้นมาใหม่.

ตามด้วยสร้าง group ขึ้นมาใหม่แบ่งเป็น admins กับ users ตามนี้:

./cake group add ‘/’ users

./cake group add ‘/’ admins

แล้วก็ add user ไว้ทดลอง group ละ 1 user:

./cake user add myadmin mypassword admins
./cake user add myuser mypassword users

grant ให้ admins ดูได้ทั้ง site (ทุกหน้า, ทุก action):

./cake acl grant admins site ‘*’

grant ให้ users ดู Pages/display (เอาไว้ redirect มาเวลาดูหน้าอื่นไม่ได้). และ ดู Books/display1:

./cake acl grant users ‘Pages/display’ ‘*’

./cake acl grant users ‘Books/display1′ ‘*’

ถ้าลอง login ด้วย myadmin ก็จะดูได้ทุกหน้า. แต่ถ้า login ด้วย myuser ก็จะดู http://localhost/my_project/books/display2 ไม่ได้.

ก็เป็นอันว่า users แต่ละกลุ่ม ก็ดูหน้าเว็บได้ต่างๆ กันตามที่กำหมดไว้ :-).

อ้างอิง:

http://lemoncake.wordpress.com/2007/07/19/acl-with-groups/

3

CakePHP 1.2.x: Action-based ACL

หลังจากที่ลองใช้ AuthComponent อย่างง่ายไปแล้ว. ผมก็อยากจะลอง ACL (Access control list) บ้าง ไม่รู้ว่าทำถูกวิธีหรือเปล่าด้วย. ผมก็เริ่มจากแก้ app_controller.php ใน cake/libs/controller เลย

class AppController extends Controller {
    var $components = array('Auth', 'Acl');

    function beforeFilter() {
        if(isset($this-&gt;Auth)) {
            $this-&gt;Auth-&gt;authorize = "actions";
            $this-&gt;Auth-&gt;userModel = 'User';
        }
   }
}

ACL ใน CakePHP ระบุความสัมพันธ์ระหว่าง ARO และ ACO. ARO ใน blog entry นี้ก็คือ user ของเว็บ. ส่วน ACO ของ CakePHP เป็นได้หลายอย่าง ได้แก่ controller, model และ action. ในที่นี้ผมระบุว่าใช้ action $this->Auth->authorize = “actions”; โดย action ก็คงประมาณว่าระบุเลยว่า user เข้าไปใช้หน้าไหนได้บ้างเช่น ระบุว่า user1 เข้าไปใช้ http://localhost/books/display1 ได้หรือเปล่า ระบุเป็นรายหน้าเลย.

หลังจากระบุไปแบบนี้แล้วผมก็ลอง login เพื่อที่จะไปเปิดดูหน้า http://localhost/books/display1 ผมก็คือเจ๊งตอบรูปข้างล่าง:

ที่ยังใช้ไม่ได้เพราะยังไม่ได้ใส่ข้อมูลใน ACL. ดูๆ แล้วการใช้ action-based acl เหมือนจะออกแรงเยอะชอบกล :-P. เหมือนกัน. เราเพิ่ม acl ด้วย command line interface เริ่มจาก cd เข้าไปใน folder: cake/console แล้วใช้คำสั่งต่อไปนี้


./cake acl create aro ‘/’ ‘users’
./cake acl create aco ‘/’ ‘site’
./cake acl create aco ‘site’ ‘Pages’
./cake acl create aco ‘Pages’ ‘display’
./cake acl create aco ‘site’ ‘Books’
./cake acl create aco ‘Books’ ‘display1′
./cake acl create aco ‘Books’ ‘display2′
./cake acl create aco ‘site’ ‘Users’
./cake acl create aco ‘Users’ ‘login’
./cake acl create aco ‘Users’ ‘logout’
./cake acl grant ‘users’ ‘Pages/display’ ‘*’
./cake acl grant ‘users’ ‘Books/display1′ ‘*’

แล้วก็ยังไม่พอต้องเข้าไปแก้ database ตรงๆ อีกนิดหน่อย (ผมใช้ MySQL ในตัวอย่างนี้)

mysql -u<your_username> -p<your_password> my_project -e ‘set @userid = (select id from users where username = “myusername”); update aros set foreign_key = @userid, model = “User” where alias=”users”;’

เท่านี้ก็ลองเข้าไปในเว็บได้แล้ว หลังจาก login ที่หน้า http://localhost/my_project/users/login แล้ว. ก็ลองดูเว็บ page ใน http://localhost/my_project/books/display1 ก็ควรจะเข้าไปดูได้ แต่ถ้าเข้าไปใน http://localhost/my_project/books/display2 ก็จะถูก redirect กลับมาที่ http://localhost/my_project/

การใช้ acl แบบนี้ก็ยังมีปัญหาอยู่บ้าง ที่ว่าต้องมา grant สิทธิให้ user แต่ละคน กับหน้าแทบทุกหน้า เพราะ aco นึง map กับ user 1 คน … ถ้ามี user มากๆ ก็คงไม่เคยเหมาะ. ดังนั้นจึงน่าจะใช้ group เข้ามาช่วยได้ คือให้ aco เชื่อมกับ group แทน และระบุว่า group ไหน มี user คนไหนบ้าง.

อ้างอิง

http://aranworld.com/article/162/cakephp-acl-tutorial-initial-setup