diff --git a/_config/config.yml b/_config/config.yml index 22543ce..483d40c 100644 --- a/_config/config.yml +++ b/_config/config.yml @@ -4,5 +4,11 @@ After: - gridfieldextensions --- +SilverStripe\Core\Injector\Injector: + Psr\SimpleCache\CacheInterface.ListingsCache: + factory: SilverStripe\Core\Cache\CacheFactory + constructor: + namespace: "ListingsCache" + Fromholdio\Listings\Forms\GridFieldListedPagesAddNewButton: showEmptyString: true diff --git a/src/Extensions/ListedPageExtension.php b/src/Extensions/ListedPageExtension.php index 56910c6..31b869c 100644 --- a/src/Extensions/ListedPageExtension.php +++ b/src/Extensions/ListedPageExtension.php @@ -13,11 +13,6 @@ class ListedPageExtension extends SiteTreeExtension { - public static function add_to_class($class, $extensionClass, $args = null) - { - ListedPages::register_class($class); - } - public function updateCMSFields(FieldList $fields) { // Remove ParentID dropdown (if mode != cmstree) diff --git a/src/Extensions/ListingsRootPageExtension.php b/src/Extensions/ListingsRootPageExtension.php index e58c970..28f74ec 100644 --- a/src/Extensions/ListingsRootPageExtension.php +++ b/src/Extensions/ListingsRootPageExtension.php @@ -77,11 +77,6 @@ class ListingsRootPageExtension extends ListingsSiteTreeExtension */ private static $administration_mode = 'cmstree'; - public static function add_to_class($class, $extensionClass, $args = null) - { - ListingsRoots::register_class($class); - } - public function getListedPagesParentIDs() { return [$this->owner->ID]; diff --git a/src/ListedPages.php b/src/ListedPages.php index deecdf8..8b66e48 100644 --- a/src/ListedPages.php +++ b/src/ListedPages.php @@ -4,33 +4,41 @@ use Fromholdio\CommonAncestor\CommonAncestor; use Fromholdio\Listings\Extensions\ListedPageExtension; +use Psr\SimpleCache\CacheInterface; use SilverStripe\CMS\Model\SiteTree; +use SilverStripe\Control\Middleware\FlushMiddleware; use SilverStripe\Core\ClassInfo; -use SilverStripe\Core\Config\Configurable; use SilverStripe\Core\Extensible; +use SilverStripe\Core\Flushable; +use SilverStripe\Core\Config\Configurable; use SilverStripe\Core\Injector\Injectable; +use SilverStripe\Core\Injector\Injector; use SilverStripe\ORM\DataList; -class ListedPages +class ListedPages implements Flushable { use Injectable; use Extensible; use Configurable; - protected static $classes = []; - - public static function register_class($class) - { - self::validate_class($class); - self::$classes[$class] = $class; - } - public static function get_classes($includeSubclasses = true) { - $classes = self::$classes; + $classes = []; + + // retrieve classes from cache + $cache = self::get_cache(); + $cacheKey = self::get_cache_key('Classes'); + if (!$cache->has($cacheKey)) { + self::build_cache(); + } + if ($cache->has($cacheKey)) { + $classes = $cache->get($cacheKey); + } + if ($includeSubclasses) { $classes = self::add_subclasses($classes); } + return $classes; } @@ -51,7 +59,7 @@ public static function get_classes_dropdown_source($includeSubclasses = true, $u public static function get_index_classes() { - $classes = self::$classes; + $classes = self::get_classes(); foreach ($classes as $class) { if (!$class::singleton()->config()->get('can_be_root')) { unset($classes[$class]); @@ -133,15 +141,27 @@ public static function get_common_class($classes = null) protected static function add_subclasses($classes) { - $classes = array_combine($classes, $classes); - - foreach ($classes as $class) { - $subclasses = ClassInfo::subclassesFor($class); - foreach ($subclasses as $subclass) { - $classes[$subclass] = $subclass; + // retrieve classes from cache + $cache = self::get_cache(); + $cacheKey = self::get_cache_key('IncludeSubclasses', $classes); + if ($cache->has($cacheKey)) { + + $classes = $cache->get($cacheKey); + + } else { + + $classes = array_combine($classes, $classes); + + foreach ($classes as $class) { + $subclasses = ClassInfo::subclassesFor($class); + foreach ($subclasses as $subclass) { + $classes[$subclass] = $subclass; + } } + + $cache->set($cacheKey, $classes); } - + return $classes; } @@ -203,4 +223,42 @@ public static function validate_classes($classes) return true; } + + /** + * This function is triggered early in the request if the "flush" query + * parameter has been set. Each class that implements Flushable implements + * this function which looks after it's own specific flushing functionality. + * + * @see FlushMiddleware + */ + public static function flush() + { + self::get_cache()->clear(); + self::build_cache(); + } + + private static function build_cache() { + // build pages cache + $pages = []; + $classes = ClassInfo::subclassesFor(SiteTree::class); + foreach ($classes as $class) { + if ($class::has_extension(ListedPageExtension::class)) { + self::validate_class($class); + $pages[$class] = $class; + } + } + $cache = self::get_cache(); + $cacheKey = self::get_cache_key('Classes'); + $cache->set($cacheKey, $pages); + self::add_subclasses($pages); + } + + private static function get_cache() { + return Injector::inst()->get(CacheInterface::class . '.ListingsCache'); + } + + private static function get_cache_key($suffix, $classes=null) { + return 'ListedPagesClasses-'.$suffix.($classes ? md5(implode('-', $classes)) : ''); + } + } diff --git a/src/ListingsRoots.php b/src/ListingsRoots.php index 581079e..8c7062e 100644 --- a/src/ListingsRoots.php +++ b/src/ListingsRoots.php @@ -2,33 +2,42 @@ namespace Fromholdio\Listings; +use Fromholdio\CommonAncestor\CommonAncestor; use Fromholdio\Listings\Extensions\ListingsRootPageExtension; +use Psr\SimpleCache\CacheInterface; use SilverStripe\CMS\Model\SiteTree; +use SilverStripe\Control\Middleware\FlushMiddleware; use SilverStripe\Core\ClassInfo; -use SilverStripe\Core\Config\Configurable; use SilverStripe\Core\Extensible; +use SilverStripe\Core\Flushable; +use SilverStripe\Core\Config\Configurable; use SilverStripe\Core\Injector\Injectable; +use SilverStripe\Core\Injector\Injector; -class ListingsRoots +class ListingsRoots implements Flushable { use Injectable; use Extensible; use Configurable; - protected static $classes = []; - - public static function register_class($class) - { - self::validate_class($class); - self::$classes[$class] = $class; - } - public static function get_classes($includeSubclasses = true) { - $classes = self::$classes; + $classes = []; + + // retrieve classes from cache + $cache = self::get_cache(); + $cacheKey = self::get_cache_key('Classes'); + if (!$cache->has($cacheKey)) { + self::build_cache(); + } + if ($cache->has($cacheKey)) { + $classes = $cache->get($cacheKey); + } + if ($includeSubclasses) { $classes = self::add_subclasses($classes); } + return $classes; } @@ -120,15 +129,28 @@ public static function get_common_plural_name($classes) protected static function add_subclasses($classes) { - $classes = array_combine($classes, $classes); - - foreach ($classes as $class) { - $subclasses = ClassInfo::subclassesFor($class); - foreach ($subclasses as $subclass) { - $classes[$subclass] = $subclass; + $cache = self::get_cache(); + + // retrieve classes from cache + $cacheKey = self::get_cache_key('IncludeSubclasses', $classes); + if ($cache->has($cacheKey)) { + + $classes = $cache->get($cacheKey); + + } else { + + $classes = array_combine($classes, $classes); + + foreach ($classes as $class) { + $subclasses = ClassInfo::subclassesFor($class); + foreach ($subclasses as $subclass) { + $classes[$subclass] = $subclass; + } } + + $cache->set($cacheKey, $classes); } - + return $classes; } @@ -190,4 +212,41 @@ public static function validate_classes($classes) return true; } + + /** + * This function is triggered early in the request if the "flush" query + * parameter has been set. Each class that implements Flushable implements + * this function which looks after it's own specific flushing functionality. + * + * @see FlushMiddleware + */ + public static function flush() + { + self::get_cache()->clear(); + self::build_cache(); + } + + private static function build_cache() { + // build pages cache + $pages = []; + $classes = ClassInfo::subclassesFor(SiteTree::class); + foreach ($classes as $class) { + if ($class::has_extension(ListingsRootPageExtension::class)) { + self::validate_class($class); + $pages[$class] = $class; + } + } + $cache = self::get_cache(); + $cacheKey = self::get_cache_key('Classes'); + $cache->set($cacheKey, $pages); + self::add_subclasses($pages); + } + + private static function get_cache() { + return Injector::inst()->get(CacheInterface::class . '.ListingsCache'); + } + + private static function get_cache_key($suffix, $classes=null) { + return 'ListingsRootClasses-'.$suffix.($classes ? md5(implode('-', $classes)) : ''); + } }