New component Doctrine_EventListener_AccessorInvoker for automatic invoking of get* and set* methods
This commit is contained in:
parent
92b7f2a03d
commit
e49319f490
@ -1,4 +1,23 @@
|
|||||||
<?php
|
<?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::autoload('Doctrine_EventListener_Interface');
|
||||||
/**
|
/**
|
||||||
* Doctrine_EventListener all event listeners extend this base class
|
* 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 onSave(Doctrine_Record $record) { }
|
||||||
public function onPreSave(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 onInsert(Doctrine_Record $record) { }
|
||||||
public function onPreInsert(Doctrine_Record $record) { }
|
public function onPreInsert(Doctrine_Record $record) { }
|
||||||
|
|
||||||
|
78
Doctrine/EventListener/AccessorInvoker.php
Normal file
78
Doctrine/EventListener/AccessorInvoker.php
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* interface for event listening, forces all classes that extend
|
* interface for event listening, forces all classes that extend
|
||||||
* Doctrine_EventListener to have the same method arguments as their parent
|
* 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 onSave(Doctrine_Record $record);
|
||||||
public function onPreSave(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 onInsert(Doctrine_Record $record);
|
||||||
public function onPreInsert(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]))
|
if( ! isset($this->data[$name]))
|
||||||
throw new InvalidKeyException();
|
throw new InvalidKeyException();
|
||||||
|
|
||||||
if($this->data[$name] == self::$null)
|
if($this->data[$name] === self::$null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return $this->data[$name];
|
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
|
* get
|
||||||
* returns a value of a property or a related component
|
* returns a value of a property or a related component
|
||||||
*
|
*
|
||||||
* @param $name name of the property or related component
|
* @param mixed $name name of the property or related component
|
||||||
* @throws InvalidKeyException
|
* @param boolean $invoke whether or not to invoke the onGetProperty listener
|
||||||
|
* @throws Doctrine_Exception
|
||||||
* @return mixed
|
* @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])) {
|
if(isset($this->data[$name])) {
|
||||||
|
|
||||||
// check if the property is null (= it is the Doctrine_Null object located in self::$null)
|
// check if the property is null (= it is the Doctrine_Null object located in self::$null)
|
||||||
if($this->data[$name] === self::$null) {
|
if($this->data[$name] === self::$null) {
|
||||||
|
|
||||||
// only load the data from database if the Doctrine_Record is in proxy state
|
$this->load();
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($this->data[$name] === self::$null)
|
if($this->data[$name] === self::$null)
|
||||||
return null;
|
$value = null;
|
||||||
}
|
|
||||||
return $this->data[$name];
|
} else
|
||||||
|
$value = $this->data[$name];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($this->id[$name]))
|
if(isset($this->id[$name]))
|
||||||
return $this->id[$name];
|
$value = $this->id[$name];
|
||||||
|
|
||||||
if($name === $this->table->getIdentifier())
|
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]))
|
if( ! isset($this->references[$name]))
|
||||||
$this->loadReference($name);
|
$this->loadReference($name);
|
||||||
|
|
||||||
|
|
||||||
return $this->references[$name];
|
return $this->references[$name];
|
||||||
@ -658,9 +683,13 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
|
|||||||
$value = $id;
|
$value = $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
$old = $this->get($name);
|
$old = $this->get($name, false);
|
||||||
|
|
||||||
if($old !== $value) {
|
if($old !== $value) {
|
||||||
|
|
||||||
|
// invoke the onPreSetProperty listener
|
||||||
|
$value = $this->table->getAttribute(Doctrine::ATTR_LISTENER)->onPreSetProperty($this, $name, $value);
|
||||||
|
|
||||||
if($value === null)
|
if($value === null)
|
||||||
$value = self::$null;
|
$value = self::$null;
|
||||||
|
|
||||||
|
@ -1,5 +1,20 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once("UnitTestCase.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 {
|
class Doctrine_EventListenerTestCase extends Doctrine_UnitTestCase {
|
||||||
public function testEvents() {
|
public function testEvents() {
|
||||||
@ -9,7 +24,45 @@ class Doctrine_EventListenerTestCase extends Doctrine_UnitTestCase {
|
|||||||
$this->assertTrue($last->getObject() instanceof Doctrine_Connection);
|
$this->assertTrue($last->getObject() instanceof Doctrine_Connection);
|
||||||
$this->assertTrue($last->getCode() == Doctrine_EventListener_Debugger::EVENT_OPEN);
|
$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 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 = new GroupTest("Doctrine Framework Unit Tests");
|
||||||
|
|
||||||
|
$test->addTestCase(new Doctrine_EventListenerTestCase());
|
||||||
|
|
||||||
$test->addTestCase(new Doctrine_RecordTestCase());
|
$test->addTestCase(new Doctrine_RecordTestCase());
|
||||||
|
|
||||||
$test->addTestCase(new Doctrine_TableTestCase());
|
$test->addTestCase(new Doctrine_TableTestCase());
|
||||||
@ -42,8 +44,6 @@ $test->addTestCase(new Doctrine_ManagerTestCase());
|
|||||||
|
|
||||||
$test->addTestCase(new Doctrine_AccessTestCase());
|
$test->addTestCase(new Doctrine_AccessTestCase());
|
||||||
|
|
||||||
$test->addTestCase(new Doctrine_EventListenerTestCase());
|
|
||||||
|
|
||||||
$test->addTestCase(new Doctrine_BatchIteratorTestCase());
|
$test->addTestCase(new Doctrine_BatchIteratorTestCase());
|
||||||
|
|
||||||
$test->addTestCase(new Doctrine_ConfigurableTestCase());
|
$test->addTestCase(new Doctrine_ConfigurableTestCase());
|
||||||
|
Loading…
Reference in New Issue
Block a user