diff --git a/src/Storm/Collection.php b/src/Storm/Collection.php index 9268caeaf5cebab5aecded253c985b80ebe04318..23a00c646957e269b2276d0213253ff7f2f3fc6d 100644 --- a/src/Storm/Collection.php +++ b/src/Storm/Collection.php @@ -26,18 +26,25 @@ THE SOFTWARE. class Storm_Collection extends ArrayObject { public function addAll($collection) { - foreach($collection as $element) { - $this->append($element); - } + foreach($collection as $element) + $this->add($element); + return $collection; } + public function add($anObject) { + $this->append($anObject); + return $this; + } + + public function newInstance($elements) { $classname = get_class($this); return new $classname($elements); } + public function collect($closure) { return $this->newInstance(array_map($closure, (array)$this)); diff --git a/src/Storm/Event/Save.php b/src/Storm/Event/Save.php new file mode 100644 index 0000000000000000000000000000000000000000..2a1267a86f257c2985ceb9313055058057e656e7 --- /dev/null +++ b/src/Storm/Event/Save.php @@ -0,0 +1,39 @@ +<?php +/* +STORM is under the MIT License (MIT) + +Copyright (c) 2010-2020 Agence Française Informatique http://www.afi-sa.fr + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + +class Storm_Event_Save { + protected $_model; + + public function __construct($model) { + $this->_model = $model; + } + + + public function getModel() { + return $this->_model; + } +} diff --git a/src/Storm/Events.php b/src/Storm/Events.php new file mode 100644 index 0000000000000000000000000000000000000000..f497336bfc72e62536dc12a2cb6a88011b851be4 --- /dev/null +++ b/src/Storm/Events.php @@ -0,0 +1,98 @@ +<?php +/* +STORM is under the MIT License (MIT) + +Copyright (c) 2010-2020 Agence Française Informatique http://www.afi-sa.fr + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +class Storm_Events { + protected static $_instance; + + protected $_observers; + + /** @category testing */ + public static function setInstance($instance) { + static::$_instance = $instance; + } + + + public static function getInstance() { + return static::$_instance + ? static::$_instance + : static::$_instance = new static(); + } + + + public function __construct() { + $this->_observers = new Storm_Set(); + } + + + /** + * @param $observer callable + */ + public function register($observer) { + $this->_observers->add($observer); + return $this; + } + + + /** + * @param $observer callable + */ + public function unregister($observer) { + $this->_observers = $this->_observers + ->reject(function($each) use($observer) + { + return $each === $observer; + }); + + return $this; + } + + + /** + * @param $classname name of a class of observer + */ + public function unregisterClass($classname) { + $this->_observers = $this->_observers + ->reject(function($each) use($classname) + { + return is_object($each) && get_class($each) == $classname; + }); + + return $this; + } + + + /** + * @param $event Storm_Event + */ + public function notify($event) { + $this->_observers->eachDo(function($observer) use($event) + { + $observer($event); + }); + + return $this; + } +} diff --git a/src/Storm/Model/Abstract.php b/src/Storm/Model/Abstract.php index 9744b107f8163a9729f5aea00705e81cc92dcc1f..7e03c01f94d1a72b17f2dc70a74044c8bc56751f 100644 --- a/src/Storm/Model/Abstract.php +++ b/src/Storm/Model/Abstract.php @@ -268,13 +268,19 @@ abstract class Storm_Model_Abstract { $this->_updateNullBelongsToIdFieldsFromDependents(); if ($valid = $this->isValid()) { $this->saveWithoutValidation(); - $this->_attributes_in_db=$this->_attributes; + $this->_getEvents()->notify(new Storm_Event_Save($this)); + $this->_attributes_in_db = $this->_attributes; } return $valid; } + protected function _getEvents() { + return Storm_Events::getInstance(); + } + + public function assertSave() { if (!$this->save()) throw new Storm_Model_Exception('Can\'t save '.get_class($this).': '.implode(',',$this->getErrors())); diff --git a/src/Storm/Set.php b/src/Storm/Set.php new file mode 100644 index 0000000000000000000000000000000000000000..d3337d618e6ea42de3293c9818f47264eba120da --- /dev/null +++ b/src/Storm/Set.php @@ -0,0 +1,34 @@ +<?php +/* +STORM is under the MIT License (MIT) + +Copyright (c) 2010-2020 Agence Française Informatique http://www.afi-sa.fr + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +class Storm_Set extends Storm_Collection { + public function add($anObject) { + if (!$this->includes($anObject)) + parent::add($anObject); + + return $this; + } +} diff --git a/tests/Storm/Model/EventTriggeringTest.php b/tests/Storm/Model/EventTriggeringTest.php new file mode 100644 index 0000000000000000000000000000000000000000..046ab262a351636f33698b477f74e981b7826f36 --- /dev/null +++ b/tests/Storm/Model/EventTriggeringTest.php @@ -0,0 +1,134 @@ +<?php +/* +STORM is under the MIT License (MIT) + +Copyright (c) 2010-2020 Agence Française Informatique http://www.afi-sa.fr + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + +abstract class Storm_Model_EventTriggeringTestCase extends Storm_Test_ModelTestCase { + protected + $_events, + $_callable, + $_called = false; + + public function setUp() { + parent::setUp(); + Storm_Model_Loader::defaultToVolatile(); + $this->_events = Storm_Events::getInstance(); + } + + + public function tearDown() { + Storm_Model_Loader::defaultToDb(); + parent::tearDown(); + } + + + /** @test */ + public function withRegisteredClosureShouldCallBackOnSave() { + $this->_events->register($this->_callable); + (new Storm_Model_EventTriggeringModel)->save(); + $this->assertTrue($this->_called); + } + + + /** @test */ + public function withUnregisteredClosureShouldNotCallbackOnSave() { + $this->_events->register($this->_callable) + ->unregister($this->_callable); + (new Storm_Model_EventTriggeringModel)->save(); + + $this->assertFalse($this->_called); + } +} + + + + +class Storm_Model_EventTriggeringClosureTest extends Storm_Model_EventTriggeringTestCase { + public function setUp() { + parent::setUp(); + $this->_callable = function($event) { $this->_called = true; }; + } +} + + + + +class Storm_Model_EventTriggeringCallableArrayTest extends Storm_Model_EventTriggeringTestCase { + public function setUp() { + parent::setUp(); + $this->_callable = [$this, 'onSave']; + } + + + public function onSave($event) { + $this->_called = true; + } +} + + + + +class Storm_Model_EventTriggeringInvokableTest extends Storm_Model_EventTriggeringTestCase { + public function setUp() { + parent::setUp(); + $this->_callable = new Storm_Model_EventTriggeringInvokable($this); + } + + + public function beCalled() { + $this->_called = true; + } + + + /** @test */ + public function withUnregisteredByClassNameShouldNotCallbackOnSave() { + $this->_events->register($this->_callable) + ->unregisterClass(Storm_Model_EventTriggeringInvokable::class); + (new Storm_Model_EventTriggeringModel)->save(); + + $this->assertFalse($this->_called); + } +} + + + + +class Storm_Model_EventTriggeringModel extends Storm_Model_Abstract {} + + + + +class Storm_Model_EventTriggeringInvokable { + protected $_test; + + public function __construct($test) { + $this->_test = $test; + } + + + public function __invoke($event) { + $this->_test->beCalled(); + } +} \ No newline at end of file