Commit e49319f4 authored by zYne's avatar zYne

New component Doctrine_EventListener_AccessorInvoker for automatic invoking of...

New component Doctrine_EventListener_AccessorInvoker for automatic invoking of get* and set* methods
parent 92b7f2a0
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
Doctrine::autoload('Doctrine_EventListener_Interface');
/**
* Doctrine_EventListener all event listeners extend this base class
......@@ -30,6 +49,13 @@ abstract class Doctrine_EventListener implements Doctrine_EventListener_Interfac
public function onSave(Doctrine_Record $record) { }
public function onPreSave(Doctrine_Record $record) { }
public function onGetProperty(Doctrine_Record $record, $property, $value) {
return $value;
}
public function onPreSetProperty(Doctrine_Record $record, $property, $value) {
return $value;
}
public function onInsert(Doctrine_Record $record) { }
public function onPreInsert(Doctrine_Record $record) { }
......
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
/**
* Doctrine_EventListener_AccessorInvoker
*
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
*/
class Doctrine_EventListener_AccessorInvoker extends Doctrine_EventListener {
/**
* @var boolean $lockGetCall a simple variable to prevent recursion
*/
private $lockGetCall = false;
/**
* @var boolean $lockSetCall a simple variable to prevent recursion
*/
private $lockSetCall = false;
/**
* onGetProperty
*
* @param Doctrine_Record $record
* @param string $property
* @param mixed $value
* @return mixed
*/
public function onGetProperty(Doctrine_Record $record, $property, $value) {
$method = 'get' . ucwords($property);
if (method_exists($record, $method) && ! $this->lockGetCall) {
$this->lockGetCall = true;
$value = $record->$method($value);
$this->lockGetCall = false;
return $value;
}
return $value;
}
/**
* onPreSetProperty
*
* @param Doctrine_Record $record
* @param string $property
* @param mixed $value
* @return mixed
*/
public function onPreSetProperty(Doctrine_Record $record, $property, $value) {
$method = 'set' . ucwords($property);
if (method_exists($record, $method) && ! $this->lockSetCall) {
$this->lockSetCall = true;
$value = $record->$method($value);
$this->lockSetCall = false;
return $value;
}
return $value;
}
}
<?php
<?php
/**
* interface for event listening, forces all classes that extend
* Doctrine_EventListener to have the same method arguments as their parent
......@@ -17,6 +17,9 @@ interface Doctrine_EventListener_Interface {
public function onSave(Doctrine_Record $record);
public function onPreSave(Doctrine_Record $record);
public function onGetProperty(Doctrine_Record $record, $property, $value);
public function onPreSetProperty(Doctrine_Record $record, $property, $value);
public function onInsert(Doctrine_Record $record);
public function onPreInsert(Doctrine_Record $record);
......
......@@ -533,53 +533,78 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
if( ! isset($this->data[$name]))
throw new InvalidKeyException();
if($this->data[$name] == self::$null)
if($this->data[$name] === self::$null)
return null;
return $this->data[$name];
}
/**
* load
* loads all the unitialized properties from the database
*
* @return boolean
*/
public function load() {
// only load the data from database if the Doctrine_Record is in proxy state
if($this->state == Doctrine_Record::STATE_PROXY) {
if( ! empty($this->collections)) {
// delegate the loading operation to collections in which this record resides
foreach($this->collections as $collection) {
$collection->load($this);
}
} else {
$this->refresh();
}
$this->state = Doctrine_Record::STATE_CLEAN;
return true;
}
return false;
}
/**
* get
* returns a value of a property or a related component
*
* @param $name name of the property or related component
* @throws InvalidKeyException
* @param mixed $name name of the property or related component
* @param boolean $invoke whether or not to invoke the onGetProperty listener
* @throws Doctrine_Exception
* @return mixed
*/
public function get($name) {
public function get($name, $invoke = true) {
$listener = $this->table->getAttribute(Doctrine::ATTR_LISTENER);
$value = self::$null;
if(isset($this->data[$name])) {
// check if the property is null (= it is the Doctrine_Null object located in self::$null)
if($this->data[$name] === self::$null) {
// only load the data from database if the Doctrine_Record is in proxy state
if($this->state == Doctrine_Record::STATE_PROXY) {
if( ! empty($this->collections)) {
// delegate the loading operation to collections in which this record resides
foreach($this->collections as $collection) {
$collection->load($this);
}
} else {
$this->refresh();
}
$this->state = Doctrine_Record::STATE_CLEAN;
}
$this->load();
if($this->data[$name] === self::$null)
return null;
}
return $this->data[$name];
$value = null;
} else
$value = $this->data[$name];
}
if(isset($this->id[$name]))
return $this->id[$name];
$value = $this->id[$name];
if($name === $this->table->getIdentifier())
return null;
$value = null;
if($value !== self::$null) {
if($invoke) {
return $this->table->getAttribute(Doctrine::ATTR_LISTENER)->onGetProperty($this, $name, $value);
} else
return $value;
}
if( ! isset($this->references[$name]))
$this->loadReference($name);
$this->loadReference($name);
return $this->references[$name];
......@@ -658,9 +683,13 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$value = $id;
}
$old = $this->get($name);
$old = $this->get($name, false);
if($old !== $value) {
// invoke the onPreSetProperty listener
$value = $this->table->getAttribute(Doctrine::ATTR_LISTENER)->onPreSetProperty($this, $name, $value);
if($value === null)
$value = self::$null;
......
<?php
require_once("UnitTestCase.php");
class EventListenerTest extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn("name", "string", 100);
$this->hasColumn("password", "string", 8);
}
public function setUp() {
$this->setAttribute(Doctrine::ATTR_LISTENER, new Doctrine_EventListener_AccessorInvoker());
}
public function getName($name) {
return strtoupper($name);
}
public function setPassword($password) {
return md5($password);
}
}
class Doctrine_EventListenerTestCase extends Doctrine_UnitTestCase {
public function testEvents() {
......@@ -9,7 +24,45 @@ class Doctrine_EventListenerTestCase extends Doctrine_UnitTestCase {
$this->assertTrue($last->getObject() instanceof Doctrine_Connection);
$this->assertTrue($last->getCode() == Doctrine_EventListener_Debugger::EVENT_OPEN);
}
public function testAccessorInvoker() {
$e = new EventListenerTest;
$e->name = "something";
$e->password = "123";
$this->assertEqual($e->get('name'), 'SOMETHING');
// test repeated calls
$this->assertEqual($e->get('name'), 'SOMETHING');
$this->assertEqual($e->rawGet('name'), 'something');
$this->assertEqual($e->password, '202cb962ac59075b964b07152d234b70');
$e->save();
$this->assertEqual($e->name, 'SOMETHING');
$this->assertEqual($e->rawGet('name'), 'something');
$this->assertEqual($e->password, '202cb962ac59075b964b07152d234b70');
$this->connection->clear();
$e->refresh();
$this->assertEqual($e->name, 'SOMETHING');
$this->assertEqual($e->rawGet('name'), 'something');
$this->assertEqual($e->password, '202cb962ac59075b964b07152d234b70');
$this->connection->clear();
$e = $e->getTable()->find($e->id);
$this->assertEqual($e->name, 'SOMETHING');
$this->assertEqual($e->rawGet('name'), 'something');
$this->assertEqual($e->password, '202cb962ac59075b964b07152d234b70');
}
public function prepareData() { }
public function prepareTables() { }
public function prepareTables() {
$this->tables = array('EventListenerTest');
parent::prepareTables();
}
}
?>
......@@ -32,6 +32,8 @@ error_reporting(E_ALL);
$test = new GroupTest("Doctrine Framework Unit Tests");
$test->addTestCase(new Doctrine_EventListenerTestCase());
$test->addTestCase(new Doctrine_RecordTestCase());
$test->addTestCase(new Doctrine_TableTestCase());
......@@ -42,8 +44,6 @@ $test->addTestCase(new Doctrine_ManagerTestCase());
$test->addTestCase(new Doctrine_AccessTestCase());
$test->addTestCase(new Doctrine_EventListenerTestCase());
$test->addTestCase(new Doctrine_BatchIteratorTestCase());
$test->addTestCase(new Doctrine_ConfigurableTestCase());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment