Permalink
Browse files

Adds Doctrine transaction support (first draft implementation) - full…

…y functional, fixed all tests. #18
  • Loading branch information...
1 parent ae2c123 commit 57f1d12dfa97ade90b1ea92d4198a83144f3294b @fruit committed Dec 27, 2012
Showing with 1,798 additions and 1,429 deletions.
  1. +1 −0 .gitignore
  2. +2 −22 README.markdown
  3. +8 −0 config/app.yml
  4. +117 −18 config/sfCacheTaggingPluginConfiguration.class.php
  5. +5 −0 lib/cache/drivers/sfSQLitePDOCache.class.php
  6. +16 −4 lib/cache/extended/sfFileTaggingCache.class.php
  7. +27 −0 lib/cache/extended/sfNoTaggingCache.class.php
  8. +0 −168 lib/cache/sfNoTaggingCache.class.php
  9. +30 −10 lib/cache/sfTaggingCache.class.php
  10. +1 −3 lib/cache/sfTaggingCacheInterface.class.php
  11. +67 −16 lib/doctrine/sfCachetaggableDoctrineRecord.class.php
  12. +1 −2 lib/filter/AuthParamFilter.class.php
  13. +2 −0 lib/log/sfCacheTagLogger.class.php
  14. +12 −15 lib/log/sfFileCacheTagLogger.class.php
  15. +4 −31 lib/log/sfNoCacheTagLogger.class.php
  16. +50 −66 lib/util/sfCacheTaggingToolkit.class.php
  17. +8 −0 lib/util/sfContentTagHandler.class.php
  18. +13 −13 lib/util/sfViewCacheTagManagerBridge.class.php
  19. +7 −75 lib/vendor/Doctrine/Cache/Proxy.php
  20. +43 −106 lib/vendor/Doctrine/Collection/Cachetaggable.php
  21. +66 −0 lib/vendor/Doctrine/EventListener/Cachetaggable.php
  22. +3 −5 lib/vendor/Doctrine/Query/Cachetaggable.php
  23. +62 −87 lib/vendor/Doctrine/Template/Cachetaggable.php
  24. +176 −102 lib/vendor/Doctrine/Template/Listener/Cachetaggable.php
  25. +52 −71 lib/view/sfViewCacheTagManager.class.php
  26. +1 −0 test/fixtures/project/apps/frontend/config/filters.yml
  27. +5 −0 test/fixtures/project/apps/frontend/config/frontendConfiguration.class.php
  28. +7 −12 test/fixtures/project/apps/frontend/modules/blog_post/actions/actions.class.php
  29. +10 −0 test/fixtures/project/apps/frontend/modules/blog_post/templates/treeSuccess.php
  30. +3 −7 test/fixtures/project/config/ProjectConfiguration.class.php
  31. +4 −7 test/fixtures/project/config/app.yml
  32. +3 −2 test/fixtures/project/config/factories.yml
  33. 0 test/fixtures/project/data/fixtures/{fixtures.yml → blog_post.yml}
  34. +36 −35 test/functional/frontend/CachetaggableAndSoftDeleteBehaviorsTest.php
  35. +62 −62 test/functional/frontend/CascadeDeleteOrInvalidateTest.php
  36. +19 −73 test/functional/frontend/DoctrineCacheProxyTest.php
  37. +19 −18 test/functional/frontend/DoctrineCollectionCachetaggableTest.php
  38. +40 −33 test/functional/frontend/DoctrineListenerCachetaggableTest.php
  39. +12 −5 test/functional/frontend/DoctrineNestedSetBehaviorTest.php
  40. +20 −13 test/functional/frontend/DoctrineQueryCachetaggableTest.php
  41. +51 −32 test/functional/frontend/DoctrineRecordLinkAndUnlinkTest.php
  42. +59 −49 test/functional/frontend/DoctrineTemplateCachetaggableTest.php
  43. +316 −0 test/functional/frontend/DoctrineTransactionTest.php
  44. +13 −6 test/functional/frontend/I18nBehaviorTest.php
  45. +12 −7 test/functional/frontend/InvalidateCollectionVersionByChangingColumnsTest.php
  46. +11 −5 test/functional/frontend/InvalidateCollectionVersionOnUpdateTest.php
  47. +12 −11 test/functional/frontend/ManyToManyTableTest.php
  48. +14 −6 test/functional/frontend/SkipOnColumnUpdateTest.php
  49. +17 −7 test/functional/frontend/UpdatingInvalidatesOnlySelfObjectTest.php
  50. +23 −5 test/functional/frontend/actionWithLayoutTest.php
  51. +24 −5 test/functional/frontend/actionWithoutLayoutTest.php
  52. +75 −59 test/functional/frontend/sfCacheTaggingPluginTest.php
  53. +20 −9 test/functional/frontend/sfCacheTaggingToolkitTest.php
  54. +2 −2 test/functional/frontend/sfCachetaggableDoctrineRecordTest.php
  55. +32 −28 test/functional/frontend/sfContentTagHandlerTest.php
  56. +55 −46 test/functional/frontend/sfViewCacheTagManagerBridgeTest.php
  57. +22 −17 test/functional/frontend/sfViewCacheTagManagerTest.php
  58. +10 −17 test/functional/notag/sfCacheTaggingToolkitTest.php
  59. +6 −4 test/unit/sfCacheTaggingToolkitTest.php
  60. +5 −12 test/unit/sfNoCacheTagLoggerTest.php
  61. +4 −20 test/unit/sfNoTaggingCacheTest.php
  62. +1 −1 test/unit/sfTaggingCacheTest.php
View
@@ -12,3 +12,4 @@ README
/test/fixtures/project/web/sf
/test/fixtures/project/web/sfDoctrinePlugin
php_errors.log
+test/fixtures/project/plugins/
View
@@ -77,27 +77,7 @@ Location: ``/config/ProjectConfiguration.class.php``
}
}
-## 2. Change default model class
-
-Switch the default model class ``sfDoctineRecord`` with ``sfCachetaggableDoctrineRecord``
-
- [php]
- <?php
-
- class ProjectConfiguration extends sfProjectConfiguration
- {
- # …
-
- public function configureDoctrine (Doctrine_Manager $manager)
- {
- sfConfig::set(
- 'doctrine_model_builder_options',
- array('baseClassName' => 'sfCachetaggableDoctrineRecord')
- );
- }
- }
-
-After, rebuild the models:
+## 2. Rebuild your the models
$ ./symfony doctrine:build-model
@@ -404,7 +384,7 @@ _NB. Please read "<a href="#quick-setup">Quick setup</a>" before reading this._
# Here you can switch to any other backend
# (see below "Restrictions" for more info)
storage:
- class: sfMemcacheTaggingCache
+ class: sfMemcacheTaggingCache # to disable storage, set class to "sfNoTaggingCache"
param:
storeCacheInfo: true
host: localhost
View
@@ -15,3 +15,11 @@ all:
# useful when tag name should contains extra information
# (e.g. Environment name, or application name)
object_class_tag_name_provider: []
+
+ # Collection name format
+ # Example: "_COLLECTIONS%separator%%name%"
+ collection_tag_name_format: ~
+
+ # Object name format
+ # Example: "_OBJECTS%separator%%name%"
+ object_tag_name_format: ~
@@ -14,41 +14,140 @@
* @package sfCacheTaggingPlugin
* @subpackage config
* @author Ilya Sabelnikov <fruit.dev@gmail.com>
+ * @property sfEventDispatcher $dispatcher Event dispatcher instance
*/
class sfCacheTaggingPluginConfiguration extends sfPluginConfiguration
{
/**
- * Handy method to get type hinting in IDE's
+ * Configure required listeners for proper plugin functionality
*
- * @return sfEventDispatcher
+ * {@inheritdoc}
*/
- public function getEventDispatcher ()
+ public function __construct (sfProjectConfiguration $configuration, $rootDir = null, $name = null)
{
- return $this->dispatcher;
+ parent::__construct($configuration, $rootDir, $name);
+
+ // Enable tags rollback/commit support inside Doctrine transactions
+ $this->connectToEvent('doctrine.configure');
+
+ // suppress custom sfAction method call without fail
+ $this->connectToEvent('component.method_not_found');
+
+ // Setup plugin's model class "sfCachetaggableDoctrineRecord"
+ $this->connectToEvent('doctrine.filter_model_builder_options');
+
+ // Enable tags rollback/commit support inside Doctrine transactions
+ $this->connectToEvent('doctrine.configure_connection');
}
- public function initialize ()
+ /**
+ * Binds callback on the passed event name
+ *
+ * @param string $eventName
+ * @return sfCacheTaggingPluginConfiguration
+ */
+ protected function connectToEvent ($eventName)
{
- $manager = Doctrine_Manager::getInstance();
+ $camelized = sfInflector::camelize(str_replace('.', '_', $eventName));
+ $this->dispatcher->connect($eventName, array($this, "listenOn{$camelized}Event"));
- # collection with additional methods to with tags
- $manager->setAttribute(
- Doctrine::ATTR_COLLECTION_CLASS, 'Doctrine_Collection_Cachetaggable'
- );
+ return $this;
+ }
- $manager->setAttribute(
- Doctrine_Core::ATTR_RESULT_CACHE, new Doctrine_Cache_Proxy()
+ /**
+ * Triggers on "component.method_not_found" event
+ *
+ * @param sfEvent $event
+ * @return null
+ */
+ public function listenOnComponentMethodNotFoundEvent (sfEvent $event)
+ {
+ try
+ {
+ $component = $event->getSubject();
+ /* @var $component sfComponent */
+
+ $event->setReturnValue(
+ call_user_func_array(
+ array(new sfViewCacheTagManagerBridge($component), $event['method']),
+ $event['arguments']
+ )
+ );
+
+ $event->setProcessed(true); // ok, this is the end
+ }
+ catch (BadMethodCallException $e)
+ {
+ // process not finished, unknown method, or cache was disabled
+ $event->setProcessed(false);
+ }
+ catch (sfException $e) // throws by sfCallable
+ {
+ // process is finished, method was valid, but call generates an error
+ $event->setProcessed(true);
+ }
+ }
+
+ /**
+ * Triggers on "doctrine.configure_connection" event
+ *
+ * @param sfEvent $event
+ */
+ public function listenOnDoctrineConfigureConnectionEvent (sfEvent $event)
+ {
+ if (! sfConfig::get('sf_cache')) return;
+
+ $connection = $event['connection'];
+ /* @var $connection Doctrine_Connection */
+
+ $connection->addListener(
+ new Doctrine_EventListener_Cachetaggable(), 'cache_tagging'
);
+ }
+
+ /**
+ * Triggers on "doctrine.filter_model_builder_options" event
+ *
+ * @param sfEvent $event
+ * @param array $params
+ * @return array
+ */
+ public function listenOnDoctrineFilterModelBuilderOptionsEvent (sfEvent $event, array $params)
+ {
+ return array_merge($params, array('baseClassName' => 'sfCachetaggableDoctrineRecord'));
+ }
+ /**
+ * Configures Doctrine manager.
+ *
+ * Connecting to doctrine.configure event will not work, if sfDoctrinePlugin
+ * declared before sfCacheTaggingPlugin.
+ *
+ * @return null
+ */
+ public function listenOnDoctrineConfigureEvent (sfEvent $event)
+ {
+ $manager = $event->getSubject();
+ /* @var $manager Doctrine_Manager */
+
+ // collection with additional methods to with tags
$manager->setAttribute(
- Doctrine_Core::ATTR_QUERY_CLASS, 'Doctrine_Query_Cachetaggable'
+ Doctrine_Core::ATTR_COLLECTION_CLASS, 'Doctrine_Collection_Cachetaggable'
);
- $manager->setAttribute(Doctrine::ATTR_USE_DQL_CALLBACKS, true);
+ // Enable Doctrine result query cache only if cache is enabled
+ if (sfConfig::get('sf_cache'))
+ {
+ $manager->setAttribute(
+ Doctrine_Core::ATTR_RESULT_CACHE, new Doctrine_Cache_Proxy()
+ );
- $this->getEventDispatcher()->connect(
- 'component.method_not_found',
- 'sfCacheTaggingToolkit::listenOnComponentMethodNotFoundEvent'
- );
+ $manager->setAttribute(
+ Doctrine_Core::ATTR_QUERY_CLASS, 'Doctrine_Query_Cachetaggable'
+ );
+ }
+
+ // Enable DQL callbacks because Doctrine model can actAs Cachetagging behavior
+ $manager->setAttribute(Doctrine::ATTR_USE_DQL_CALLBACKS, true);
}
}
@@ -173,6 +173,11 @@ protected function getColumn ($key, $columnName)
protected function createSchema ()
{
+ /**
+ * Sqlite supports transactional DDL
+ *
+ * @link http://goo.gl/3v48S
+ */
$statement = <<< SCHEMA
BEGIN TRANSACTION;
@@ -24,8 +24,8 @@ class sfFileTaggingCache extends sfFileCache implements sfTaggingCacheInterface
*/
public function get ($key, $default = null)
{
+ clearstatcache();
$data = parent::get($key, $default);
-
return null === $data ? $default : unserialize($data);
}
@@ -34,26 +34,38 @@ public function get ($key, $default = null)
*/
public function set ($key, $data, $lifetime = null)
{
+ clearstatcache();
return parent::set($key, serialize($data), $lifetime);
}
/**
+ * {@inheritdoc}
+ */
+ public function has ($key)
+ {
+ clearstatcache();
+ return parent::has($key);
+ }
+
+ /**
* @return array
*/
public function getCacheKeys ()
{
- $cacheDir = $this->getOption('cache_dir') . DIRECTORY_SEPARATOR;
+ $cacheDir = $this->getOption('cache_dir');
$keys = array();
- foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->getOption('cache_dir'))) as $path)
+ clearstatcache();
+
+ foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($cacheDir)) as $path)
{
if (! is_file($path))
{
continue;
}
- $key = str_replace($this->getOption('cache_dir').DIRECTORY_SEPARATOR, '', $path);
+ $key = str_replace($cacheDir . DIRECTORY_SEPARATOR, '', $path);
$key = str_replace(DIRECTORY_SEPARATOR, self::SEPARATOR, $key);
$key = substr($key, 0, - strlen(self::EXTENSION));
$keys[] = $key;
@@ -0,0 +1,27 @@
+<?php
+
+ /*
+ * This file is part of the sfCacheTaggingPlugin package.
+ * (c) 2009-2012 Ilya Sabelnikov <fruit.dev@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+ /**
+ * {@inheritdoc}
+ *
+ * @package sfCacheTaggingPlugin
+ * @subpackage cache
+ * @author Ilya Sabelnikov <fruit.dev@gmail.com>
+ */
+ class sfNoTaggingCache extends sfNoCache implements sfTaggingCacheInterface
+ {
+ /**
+ * {@inheritdoc}
+ */
+ public function getCacheKeys ()
+ {
+ return array();
+ }
+ }
Oops, something went wrong.

0 comments on commit 57f1d12

Please sign in to comment.