root/trunk/lib/AkDbSession.php

Revision 468, 5.0 kB (checked in by bermiferrer, 7 months ago)

WARNING: IMPORTANT CHANGES AHEAD!


* Relocated Active Record database adapters, behaviors and associations into lib/AkActiveRecord/AkDbAdapters, AkActsAsBehaviours? and AkAssociations? respectively.

## Merging Kaste's branch with the trunk.

* [387] Refactored AkActiveRecord::find().
* [387] API-change: removed find('first', $id, $options) cause finding one id is always "first". Use find($id, $options); instead.
* [395] Deprecated AkActiveRecord::find($sql) which silently expanded to AkActiveRecord::find('first', $sql).
This was ambiguous because find($sql, $bind_variables*) expanded to find('all',*)
Use AkActiveRecord::find('first', $sql) instead.
* [396] Added AkDbAdapter? between ADODb and the Active Record.
* [396] Expanded AkUnitTest? so its easy to generate Models on the fly like:

$AkUnitTest->installAndIncludeModels(array('Article'=>'id,name,description'));

Creates the table 'articles' with specified columns and builds the ActiveRecord? Model (class) 'Article'.
* [396] AkActiveRecord::toYaml now handles ActiveRecord? collections.

User::toYaml($found_users);

* [407] Fixed typos on the Active Record like $asssociated_ids....
* [407] Improved and refactored Active Record unit tests.
* [405] Fixed AkHasAndBelongsToMany/AkHasMany::getAssociatedModelInstance which Singleton was badly implemented.
* [416] Avoided unsetting database profiles.
* [416] Added support for extra database profiles you can quickly test with different db-adapters like:

ActiveRecord::establishConnection('super_user');
./test _some_test_case.php sqlite_test_profile

* [417] Changed NewDataDictionary(db->connection) to db->getDictionary();
* [418] AkHasAndBelongsToMany? now uses AkInstaller? to create the join table. Because of that it creates the sequence_table for sqlite straight away.
* [419] Fixed singleton implementation of Ak::getLogger()
* [425] AkInstaller?: Added magic 'lock_version' column.

'lock_version' => 'lock_version int default=1'

* [427] Refactored the Active Record "callback"-chain. Fixes #95 and #94.
* [427] Added create, update and execute methods to AkDbAdapter?.
* [428] Adding support for late bindings on AkDbAdapter::execute()
This allows you to safely sanitize parameters before adding them to your custom SQL queries.

AkDbAdapter::execute(array('select * from articles where id=?', 1));

* [429] Added addLimitAndOffset method to AkDbAdapter? for delegating limits and offsets.
* [431] Implemented renameColumn in AkDbAdapter?. Closes #47 and #96.
* [436] Removed AkActiveRecord::sqlSelect* (now in AkDbAdapter?)
* [437] Moved transactions to AkDbAdapter?
* [439] Fixed a serious issue in a TEST that could lead to data loss in the development database.
* [441] Replacing MetaTables() and MetaColumns() with AkDbAdapter::availableTables() and AkDbAdapter::getColumnDetails($table).
* [446] Improved the MenuHeper?
* [446] Changed default options for AkPluginManager::updatePlugin(). Disables externals and checkout.
* [448] AkActiveRecord::findBySql now uses AkDbAdapter::select
* [450] AkActiveRecord::incrementCounter() and decrementCounter() now are pseudo-static.
* [450] AkActiveRecord::updateAttribute() now validates when saving by default. Pass 'false' as third argument to bypass validation.
* [451] AkInstaller? automatically sets '*_count'-columns => 'columnname int default 0'
* [458] Fixed #103, quoting strings on PostgreSQL.
* [459] Adding decimal-type support on Active Records.
* [459] Datatypes for PostgreSQL changed. You need to update/change your table schemas! Run migrations!
Before this, we kinda hacked Mysql-behavior into PostgreSQL. Thus we didnt used features of Postgre on one side.

In the long run we had to fix - better now than later - since the design problems only "multiply" when time goes by.

At this point we wanted to implement the decimal/numeric datatype. And so we had to decide whether to hack further or to solve the underlying issue. This means we HAD to correct a wrong implementation.

(simplified type>) Akelos Postgre (<Actual Type)

Until now we had:

boolean => numeric(1)
integer => numeric(X,0)


From now on we have:

boolean => bool
integer => integer (int4)
decimal => numeric


To guide you through this we'll have a test at test/unit/lib/AkActiveRecord/_PostgreSQL_datatype_migration.php.

First make you comfortably with this test and make it pass. This is a test against a dummy-table of course.
(When you're on Postgre 7 you have to modify this test. But you'll see that.)

Next write appropriate migrations/installers for your real tables. (Again: You should always begin with a test.)

Keep in mind that we typecast TINYINT as boolean on MySQL. So you cannot use tinyint for other things.
* [459] Boolean columns now actually have three possible states: true, false and null. Before that null=>false!
* [461] ActiveRecordHelper::error_messages_for and error_message_on now translate the error messages.
* [467] NULL values can be saved on boolean and decimal columns. Fixes #114 and #113.

Line 
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
4 // +----------------------------------------------------------------------+
5 // | Akelos Framework - http://www.akelos.org                             |
6 // +----------------------------------------------------------------------+
7 // | Copyright (c) 2002-2006, Akelos Media, S.L.  & Bermi Ferrer Martinez |
8 // | Released under the GNU Lesser General Public License, see LICENSE.txt|
9 // +----------------------------------------------------------------------+
10
11 /**
12  * @package ActionController
13  * @subpackage Sessions
14  * @author Bermi Ferrer <bermi a.t akelos c.om>
15  * @copyright Copyright (c) 2002-2006, Akelos Media, S.L. http://www.akelos.org
16  * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html>
17  */
18
19 if(!defined('AK_DBSESSION_CLASS_INCLUDED')){ define('AK_DBSESSION_CLASS_INCLUDED',true); // Class overriding trick
20
21
22 require_once(AK_LIB_DIR.DS.'Ak.php');
23 require_once(AK_LIB_DIR.DS.'AkObject.php');
24
25
26 /**
27 * Database based session.
28 *
29 * This class enables saving sessions into a database. This can
30 * be usefull for multiple server sites, and to have more
31 * control over sessions.
32 *
33 * <code>
34 *
35 * require_once(AK_LIB_DIR.'/AkDbSession.php');
36 *
37 * $AkDbSession = new AkDbSession();
38 * $AkDbSession->sessionLife = AK_SESSION_EXPIRE;
39 * session_set_save_handler (
40 * array(&$AkDbSession, '_open'),
41 * array(&$AkDbSession, '_close'),
42 * array(&$AkDbSession, '_read'),
43 * array(&$AkDbSession, '_write'),
44 * array(&$AkDbSession, '_destroy'),
45 * array(&$AkDbSession, '_gc')
46 * );
47 *
48 * </code>
49 *
50 * @author Bermi Ferrer <bermi at akelos com>
51 * @copyright Copyright (c) 2002-2005, Akelos Media, S.L. http://www.akelos.org
52 * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html>
53 * @since 0.1
54 * @version $Revision 0.1 $
55 */
56 class AkDbSession extends AkObject
57 {
58     /**
59     * Secconds for the session to expire.
60     *
61     * @see setSessionLife
62     * @access public
63     * @var integer $sessionLife
64     */
65     var $sessionLife = AK_SESSION_EXPIRE;
66
67     /**
68     * Database instance handler
69     *
70     * Stores a reference to an ADODB database instance.
71     *
72     * @access protected
73     * @var object $_db
74     */
75     var $_db;
76
77     /**
78     * Original session value for avoiding hitting the database in case nothing has changed
79     *
80     * @access private
81     * @var string $_db
82     */
83     var $_original_sess_value = '';
84
85     /**
86     * $this->sessionLife setter
87     *
88     * Use this method to set $this->sessionLife value
89     *
90     * @access public
91     * @see get$sessionLife
92     * @param    integer    $sessionLife    Secconds for the session to expire.
93     * @return bool Returns true if $this->sessionLife has been set
94     * correctly.
95     */
96     function setSessionLife($sessionLife)
97     {
98         $this->sessionLife = $sessionLife;
99
100     }
101
102     // ---- Protected methods ---- //
103
104     /**
105     * Session open handler
106     *
107     * @access protected
108     * @return boolean
109     */
110     function _open()
111     {
112         $this->_db =& Ak::db();
113         return true;
114     }
115
116     /**
117     * Session close handler
118     *
119     * @access protected
120     * @return boolean
121     */
122     function _close()
123     {
124         /**
125         * @todo Get from cached vars last time garbage collection was made to avoid hitting db
126         * on every request
127         */
128         $this->_gc();
129         return true;
130     }
131
132     /**
133     * Session read handler
134     *
135     * @access protected
136     * @param    string    $id    Session Id
137     * @return string
138     */
139     function _read($id)
140     {
141         $result = $this->_db->selectValue("SELECT value FROM sessions WHERE id = ".$this->_db->quote_string($id));
142         return is_null($result) ? '' : (string)$result;
143     }
144
145     /**
146     * Session write handler
147     *
148     * @access protected
149     * @param    string    $id   
150     * @param    string    $data   
151     * @return boolean
152     */
153     function _write($id, $data)
154     {
155         // We don't want to hit the db if nothing has changed
156         if($this->_original_sess_value != $data){
157             /**
158             * @todo replace with dbAdapter-method
159             */
160             $ret = $this->_db->connection->Replace('sessions', array('id'=>$this->_db->quote_string($id),'expire'=>$this->_db->quote_datetime(time()),'value'=>$this->_db->quote_string($data)), 'id');
161             if($ret == 0){
162                 return false;
163             }else{
164                 return true;
165             }
166         }else {
167             return true;
168         }
169     }
170
171     /**
172     * Session destroy handler
173     *
174     * @access protected
175     * @param    string    $id   
176     * @return boolean
177     */
178     function _destroy($id)
179     {
180         return (bool)$this->_db->delete('DELETE FROM sessions WHERE id = '.$this->_db->quote_string($id));
181         }
182
183     /**
184     * Session garbage collection handler
185     *
186     * @access protected
187     * @return boolean
188     */
189     function _gc()
190     {
191         return (bool)$this->_db->delete('DELETE FROM sessions WHERE expire < '.$this->_db->quote_datetime(time()-$this->sessionLife));
192         }
193
194
195 }
196
197 }// End of if(!defined('AK_DBSESSION_CLASS_INCLUDED')){
198
199 ?>
200
Note: See TracBrowser for help on using the browser.