/** * The process to automatically construct data object output configurations, executed on project build. */ public function requireDefaultRecords() { parent::requireDefaultRecords(); // Grab the list of data objects that have been completely removed. foreach (DB::getConn()->tableList() as $table) { // Delete existing output configurations for these data objects. if (!class_exists($table)) { $existing = DataObjectOutputConfiguration::get_one('DataObjectOutputConfiguration', "IsFor = '" . Convert::raw2sql($table) . "'"); $this->deleteConfiguration($table, $existing); } } // Grab the list of all data object types, along with any inclusions/exclusions defined. $objects = ClassInfo::subclassesFor('DataObject'); $inclusions = self::$custom_inclusions; $exclusions = array_unique(array_merge(self::$exclusions, self::$custom_exclusions)); // Check existing output configurations for these data objects. foreach ($objects as $object) { $existing = DataObjectOutputConfiguration::get_one('DataObjectOutputConfiguration', "IsFor = '" . Convert::raw2sql($object) . "'"); // Delete existing output configurations for invalid data objects, or for those excluded. if ($existing && (self::$disabled || get_parent_class($object) !== 'DataObject' || ClassInfo::classImplements($object, 'TestOnly') || count($inclusions) > 0 && !in_array($object, $inclusions) || count($inclusions) === 0 && in_array($object, $exclusions))) { $this->deleteConfiguration($object, $existing); } else { if (!$existing && !self::$disabled && get_parent_class($object) === 'DataObject' && !ClassInfo::classImplements($object, 'TestOnly') && (count($inclusions) > 0 && in_array($object, $inclusions) || count($inclusions) === 0 && !in_array($object, $exclusions))) { $this->addConfiguration($object); } } } }
/** * Determine the existing and configuration defined tag types to consolidate. * * @return array(string, string) */ public function getFusionTagTypes() { // Determine existing tag types. $types = array(); $configuration = Config::inst(); // The tag type exclusions need checking. $exclusions = $configuration->get('FusionService', 'tag_type_exclusions'); $classes = ClassInfo::subclassesFor('DataObject'); unset($classes['FusionTag']); foreach ($classes as $class) { // Determine the tag types to consolidate, based on data objects ending with "Tag". if (strpos(strrev($class), strrev('Tag')) === 0 && !in_array($class, $exclusions) && !ClassInfo::classImplements($class, 'TestOnly')) { // Use the title field as a default. $types[$class] = 'Title'; } } // Determine configuration defined tag types. foreach ($configuration->get('FusionService', 'custom_tag_types') as $type => $field) { if (in_array($type, $classes) && !in_array($type, $exclusions)) { // Use the configuration defined field. $types[$type] = $field; } } return $types; }
/** * Sets the renderer for markdown fields to use * @param {string} $renderer Class Name of an implementation of IMarkdownRenderer */ public static function setRenderer($renderer) { if (ClassInfo::classImplements($renderer, 'IMarkdownRenderer')) { self::$renderer = $renderer; } else { user_error('The renderer ' . $renderer . ' does not implement IMarkdownRenderer', E_USER_ERROR); } }
public static function get_question_types() { $classes = array(); foreach (ClassInfo::subclassesFor('Question') as $i => $class) { if ($class != 'Question' && !ClassInfo::classImplements($class, 'TestOnly')) { $classes[$class] = $class; } } return $classes; }
/** * Returns a filtered list of fields which could contain shortcodes. * * @param String * @return Array Map of class names to an array of field names on these classes. */ function getShortcodeFields($class) { $fields = array(); $ancestry = array_values(ClassInfo::dataClassesFor($class)); foreach ($ancestry as $ancestor) { if (ClassInfo::classImplements($ancestor, 'TestOnly')) { continue; } $ancFields = DataObject::custom_database_fields($ancestor); if ($ancFields) { foreach ($ancFields as $ancFieldName => $ancFieldSpec) { if (preg_match($this->fieldSpecRegex, $ancFieldSpec)) { if (!@$fields[$ancestor]) { $fields[$ancestor] = array(); } $fields[$ancestor][$ancFieldName] = $ancFieldSpec; } } } } return $fields; }
private static function cache_composite_fields($class) { $compositeFields = array(); $fields = Config::inst()->get($class, 'db', Config::UNINHERITED); if ($fields) { foreach ($fields as $fieldName => $fieldClass) { if (!is_string($fieldClass)) { continue; } // Strip off any parameters $bPos = strpos('(', $fieldClass); if ($bPos !== FALSE) { $fieldClass = substr(0, $bPos, $fieldClass); } // Test to see if it implements CompositeDBField if (ClassInfo::classImplements($fieldClass, 'CompositeDBField')) { $compositeFields[$fieldName] = $fieldClass; } } } ExternalDataObject::$_cache_composite_fields[$class] = $compositeFields; }
public function getCMSFields() { if ($this->List) { $opts = array('random' => 'A random list of objects', 'query' => 'A specific list of objects'); } else { $opts = array('static' => 'A static value', 'random' => 'A random object', 'query' => 'A specific object'); } $map = ArrayLib::valuekey(ClassInfo::subclassesFor('DataObject')); unset($map['DataObject']); foreach ($map as $k => $class) { if (ClassInfo::classImplements($class, 'TestOnly')) { unset($map[$class]); } } ksort($map); $f = FieldList::create(TabSet::create('Root')); $f->addFieldToTab('Root.Main', ReadonlyField::create('Variable', 'Variable name')); $f->addFieldToTab('Root.Main', OptionsetField::create('ValueType', 'Value type', $opts)); $f->addFieldToTab('Root.Main', DropdownField::create('RecordClass', 'Object type', $map)->displayIf('ValueType')->isEqualTo('random')->orIf('ValueType')->isEqualTo('query')->end()); $f->addFieldToTab('Root.Main', TextField::create('Value')->displayIf('ValueType')->isEqualTo('static')->end()); $f->addFieldToTab('Root.Main', TextField::create('Query', 'Query string')->displayIf('ValueType')->isEqualTo('query')->end()->setDescription('E.g. Name:StartsWith=Uncle&Status=Awesome')); return $f; }
/** * Build a {@link SQLQuery} object to perform the given query. * * @param string $filter A filter to be inserted into the WHERE clause. * @param string|array $sort A sort expression to be inserted into the ORDER BY clause. If omitted, self::$default_sort will be used. * @param string|array $limit A limit expression to be inserted into the LIMIT clause. * @param string $join A single join clause. This can be used for filtering, only 1 instance of each DataObject will be returned. * @param boolean $restictClasses Restrict results to only objects of either this class of a subclass of this class * @param string $having A filter to be inserted into the HAVING clause. * * @return SQLQuery Query built. */ public function buildSQL($filter = "", $sort = "", $limit = "", $join = "", $restrictClasses = true, $having = "") { // Find a default sort if(!$sort) { $sort = $this->stat('default_sort'); } // Get the tables to join to $tableClasses = ClassInfo::dataClassesFor($this->class); if(!$tableClasses) { if(!ManifestBuilder::has_been_included()) { user_error("DataObjects have been requested before the manifest is loaded. Please ensure you are not querying the database in _config.php.", E_USER_ERROR); } else { user_error("DataObject::buildSQL: Can't find data classes (classes linked to tables) for $this->class. Please ensure you run dev/build after creating a new DataObject.", E_USER_ERROR); } } $baseClass = array_shift($tableClasses); $select = array("`$baseClass`.*"); // Build our intial query $query = new SQLQuery($select); $query->from("`$baseClass`"); $query->where($filter); $query->orderby($sort); $query->limit($limit); // Add SQL for multi-value fields on the base table $databaseFields = $this->databaseFields(); if($databaseFields) foreach($databaseFields as $k => $v) { if(!in_array($k, array('ClassName', 'LastEdited', 'Created'))) { if(ClassInfo::classImplements($v, 'CompositeDBField')) { $this->dbObject($k)->addToQuery($query); } } } // Join all the tables if($tableClasses && self::$subclass_access) { foreach($tableClasses as $tableClass) { $query->from[$tableClass] = "LEFT JOIN `$tableClass` ON `$tableClass`.ID = `$baseClass`.ID"; $query->select[] = "`$tableClass`.*"; // Add SQL for multi-value fields $SNG = singleton($tableClass); $databaseFields = $SNG->databaseFields(); if($databaseFields) foreach($databaseFields as $k => $v) { if(!in_array($k, array('ClassName', 'LastEdited', 'Created'))) { if(ClassInfo::classImplements($v, 'CompositeDBField')) { $SNG->dbObject($k)->addToQuery($query); } } } } } $query->select[] = "`$baseClass`.ID"; $query->select[] = "if(`$baseClass`.ClassName,`$baseClass`.ClassName,'$baseClass') AS RecordClassName"; // Get the ClassName values to filter to $classNames = ClassInfo::subclassesFor($this->class); if(!$classNames) { user_error("DataObject::get() Can't find data sub-classes for '$callerClass'"); } // If querying the base class, don't bother filtering on class name if($restrictClasses && $this->class != $baseClass) { // Get the ClassName values to filter to $classNames = ClassInfo::subclassesFor($this->class); if(!$classNames) { user_error("DataObject::get() Can't find data sub-classes for '$callerClass'"); } $query->where[] = "`$baseClass`.ClassName IN ('" . implode("','", $classNames) . "')"; } if($having) { $query->having[] = $having; } if($join) { $query->from[] = $join; $query->groupby[] = reset($query->from) . ".ID"; } return $query; }
function providePermissions() { $perms = array("CMS_ACCESS_LeftAndMain" => array('name' => _t('CMSMain.ACCESSALLINTERFACES', 'Access to all CMS sections'), 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access'), 'help' => _t('CMSMain.ACCESSALLINTERFACESHELP', 'Overrules more specific access settings.'), 'sort' => -100)); // Add any custom ModelAdmin subclasses. Can't put this on ModelAdmin itself // since its marked abstract, and needs to be singleton instanciated. foreach (ClassInfo::subclassesFor('ModelAdmin') as $i => $class) { if ($class == 'ModelAdmin') { continue; } if (ClassInfo::classImplements($class, 'TestOnly')) { continue; } $title = _t("{$class}.MENUTITLE", LeftAndMain::menu_title_for_class($class)); $perms["CMS_ACCESS_" . $class] = array('name' => _t('CMSMain.ACCESS', "Access to '{title}' section", "Item in permission selection identifying the admin section. Example: Access to 'Files & Images'", array('title' => $title)), 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access')); } return $perms; }
/** * Gets the rendered results from searching * @return {HTMLText} */ public function getSearchResults() { if ($this->config()->search_engine === false || !class_exists($this->config()->search_engine) || !ClassInfo::classImplements($this->config()->search_engine, 'ICMSUserDocsSearchEngine')) { return $this->httpError(404); } $results = Injector::inst()->get($this->config()->search_engine)->getSearchResults($this->request->getVar('q'), $this->request->getVar('start'), $this->request); return $results->renderWith('CMSDocumentationViewer_results'); }
/** * A utility funciton to retrieve subclasses of a given class that * are instantiable (ie, not abstract) and have a valid menu title. * * @todo A variation of this function could probably be moved to {@link ClassInfo} * @param string $root The root class to begin finding subclasses * @param boolean $recursive Look for subclasses recursively? * @return array Valid, unique subclasses */ public static function get_cms_classes($root = 'LeftAndMain', $recursive = true) { $subClasses = array_values(ClassInfo::subclassesFor($root)); foreach ($subClasses as $className) { if ($recursive && $className != $root) { $subClasses = array_merge($subClasses, array_values(ClassInfo::subclassesFor($className))); } } $subClasses = array_unique($subClasses); foreach ($subClasses as $key => $className) { // Remove abstract classes and LeftAndMain $classReflection = new ReflectionClass($className); if (!$classReflection->isInstantiable() || 'LeftAndMain' == $className || ClassInfo::classImplements($className, 'TestOnly')) { unset($subClasses[$key]); } } return $subClasses; }
/** * Build a {@link SQLQuery} object to perform the given query. * * @param string $filter A filter to be inserted into the WHERE clause. * @param string|array $sort A sort expression to be inserted into the ORDER BY clause. If omitted, self::$default_sort will be used. * @param string|array $limit A limit expression to be inserted into the LIMIT clause. * @param string $join A single join clause. This can be used for filtering, only 1 instance of each DataObject will be returned. * @param boolean $restictClasses Restrict results to only objects of either this class of a subclass of this class * @param string $having A filter to be inserted into the HAVING clause. * * @return SQLQuery Query built. */ public function buildSQL($filter = "", $sort = "", $limit = "", $join = "", $restrictClasses = true, $having = "") { // Cache the big hairy part of buildSQL if (!isset(self::$cache_buildSQL_query[$this->class])) { // Get the tables to join to $tableClasses = ClassInfo::dataClassesFor($this->class); if (!$tableClasses) { if (!ManifestBuilder::has_been_included()) { user_error("DataObjects have been requested before the manifest is loaded. Please ensure you are not querying the database in _config.php.", E_USER_ERROR); } else { user_error("DataObject::buildSQL: Can't find data classes (classes linked to tables) for {$this->class}. Please ensure you run dev/build after creating a new DataObject.", E_USER_ERROR); } } $baseClass = array_shift($tableClasses); // $collidingFields will keep a list fields that appear in mulitple places in the class // heirarchy for this table. They will be dealt with more explicitly in the SQL query // to ensure that junk data from other tables doesn't corrupt data objects $collidingFields = array(); // Build our intial query $query = new SQLQuery(array()); $query->from("\"{$baseClass}\""); // Add SQL for multi-value fields on the base table $databaseFields = self::database_fields($baseClass); if ($databaseFields) { foreach ($databaseFields as $k => $v) { if (!in_array($k, array('ClassName', 'LastEdited', 'Created')) && ClassInfo::classImplements($v, 'CompositeDBField')) { $this->dbObject($k)->addToQuery($query); } else { $query->select[$k] = "\"{$baseClass}\".\"{$k}\""; } } } // Join all the tables if ($tableClasses && self::$subclass_access) { foreach ($tableClasses as $tableClass) { $query->from[$tableClass] = "LEFT JOIN \"{$tableClass}\" ON \"{$tableClass}\".\"ID\" = \"{$baseClass}\".\"ID\""; // Add SQL for multi-value fields $databaseFields = self::database_fields($tableClass); $compositeFields = self::composite_fields($tableClass, false); if ($databaseFields) { foreach ($databaseFields as $k => $v) { if (!isset($compositeFields[$k])) { // Update $collidingFields if necessary if (isset($query->select[$k])) { if (!isset($collidingFields[$k])) { $collidingFields[$k] = array($query->select[$k]); } $collidingFields[$k][] = "\"{$tableClass}\".\"{$k}\""; } else { $query->select[$k] = "\"{$tableClass}\".\"{$k}\""; } } } } if ($compositeFields) { foreach ($compositeFields as $k => $v) { $dbO = $this->dbObject($k); if ($dbO) { $dbO->addToQuery($query); } } } } } // Resolve colliding fields if ($collidingFields) { foreach ($collidingFields as $k => $collisions) { $caseClauses = array(); foreach ($collisions as $collision) { if (preg_match('/^"([^"]+)"/', $collision, $matches)) { $collisionBase = $matches[1]; $collisionClasses = ClassInfo::subclassesFor($collisionBase); $caseClauses[] = "WHEN \"{$baseClass}\".\"ClassName\" IN ('" . implode("', '", $collisionClasses) . "') THEN {$collision}"; } else { user_error("Bad collision item '{$collision}'", E_USER_WARNING); } } $query->select[$k] = "CASE " . implode(" ", $caseClauses) . " ELSE NULL END" . " AS \"{$k}\""; } } $query->select[] = "\"{$baseClass}\".\"ID\""; $query->select[] = "CASE WHEN \"{$baseClass}\".\"ClassName\" IS NOT NULL THEN \"{$baseClass}\".\"ClassName\" ELSE '{$baseClass}' END AS \"RecordClassName\""; // Get the ClassName values to filter to $classNames = ClassInfo::subclassesFor($this->class); if (!$classNames) { user_error("DataObject::get() Can't find data sub-classes for '{$callerClass}'"); } // If querying the base class, don't bother filtering on class name if ($restrictClasses && $this->class != $baseClass) { // Get the ClassName values to filter to $classNames = ClassInfo::subclassesFor($this->class); if (!$classNames) { user_error("DataObject::get() Can't find data sub-classes for '{$callerClass}'"); } $query->where[] = "\"{$baseClass}\".\"ClassName\" IN ('" . implode("','", $classNames) . "')"; } self::$cache_buildSQL_query[$this->class] = clone $query; } else { $query = clone self::$cache_buildSQL_query[$this->class]; } // Find a default sort if (!$sort) { $sort = $this->stat('default_sort'); } // Add quoting to sort expression if it's a simple column name if (preg_match('/^[A-Z][A-Z0-9_]*$/i', $sort)) { $sort = "\"{$sort}\""; } $query->where($filter); $query->orderby($sort); $query->limit($limit); if ($having) { $query->having[] = $having; } if ($join) { $query->from[] = $join; // In order to group by unique columns we have to group by everything listed in the select foreach ($query->select as $field) { // Skip the _SortColumns; these are only going to be aggregate functions if (preg_match('/AS\\s+\\"?_SortColumn/', $field, $matches)) { // Identify columns with aliases, and ignore the alias. Making use of the alias in // group by was causing problems when those queries were subsequently passed into // SQLQuery::unlimitedRowCount. } else { if (preg_match('/^(.*)\\s+AS\\s+(\\"[^"]+\\")\\s*$/', $field, $matches)) { $query->groupby[] = $matches[1]; // Otherwise just use the field as is } else { $query->groupby[] = $field; } } } } return $query; }
/** * A utility funciton to retrieve subclasses of a given class that * are instantiable (ie, not abstract) and have a valid menu title. * * Sorted by url_priority config. * * @todo A variation of this function could probably be moved to {@link ClassInfo} * @param string $root The root class to begin finding subclasses * @param boolean $recursive Look for subclasses recursively? * @param string $sort Name of config on which to sort. Can be 'menu_priority' or 'url_priority' * @return array Valid, unique subclasses */ public static function get_cms_classes($root = null, $recursive = true, $sort = self::MENU_PRIORITY) { if (!$root) { $root = 'LeftAndMain'; } /** @todo Make these actual abstract classes */ $abstractClasses = ['LeftAndMain', 'SilverStripe\\CMS\\Controllers\\CMSMain']; $subClasses = array_values(ClassInfo::subclassesFor($root)); foreach ($subClasses as $className) { if ($recursive && $className != $root) { $subClasses = array_merge($subClasses, array_values(ClassInfo::subclassesFor($className))); } } $subClasses = array_unique($subClasses); foreach ($subClasses as $key => $className) { // Remove abstract classes and LeftAndMain if (in_array($className, $abstractClasses) || ClassInfo::classImplements($className, 'TestOnly')) { unset($subClasses[$key]); } else { // Separate conditional to avoid autoloading the class $classReflection = new ReflectionClass($className); if (!$classReflection->isInstantiable()) { unset($subClasses[$key]); } } } // Sort by specified sorting config usort($subClasses, function ($a, $b) use($sort) { $priorityA = Config::inst()->get($a, $sort); $priorityB = Config::inst()->get($b, $sort); return $priorityB - $priorityA; }); return $subClasses; }
/** * Internal cacher for the composite field information */ private static function cache_composite_fields($class) { $compositeFields = array(); $fields = Object::uninherited_static($class, 'db'); if ($fields) { foreach ($fields as $fieldName => $fieldClass) { // Strip off any parameters $bPos = strpos('(', $fieldClass); if ($bPos !== FALSE) { $fieldClass = substr(0, $bPos, $fieldClass); } // Test to see if it implements CompositeDBField if (ClassInfo::classImplements($fieldClass, 'CompositeDBField')) { $compositeFields[$fieldName] = $fieldClass; } } } self::$_cache_composite_fields[$class] = $compositeFields; }
/** * @return array */ public function providePermissions() { $perms = array(); // Add any custom SinglePageAdmin subclasses. foreach (ClassInfo::subclassesFor('SinglePageAdmin') as $i => $class) { if ($class == 'SinglePageAdmin') { continue; } if (ClassInfo::classImplements($class, 'TestOnly')) { continue; } $title = _t("{$class}.MENUTITLE", LeftAndMain::menu_title_for_class($class)); $perms["CMS_ACCESS_" . $class] = array('name' => _t('CMSMain.ACCESS', "Access to '{title}' section", "Item in permission selection identifying the admin section. Example: Access to 'Files & Images'", array('title' => $title)), 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access')); } return $perms; }
public function testGetSerializer() { $serializer = CacheHelper::get_serializer(); $this->assertTrue(ClassInfo::classImplements($serializer->class, 'ICacheSerializer')); }
public static function get_extra_config($class, $extension, $args) { if (!ClassInfo::classImplements($class, "ContentNotifier")) { throw new RuntimeException("{$class} must implement ContentNotifier to be used by the ContentNotifierExtension"); } }
/** * Get config store * * @return SolrConfigStore */ protected function getSolrConfigStore() { $options = Solr::solr_options(); if (!isset($options['indexstore']) || !($indexstore = $options['indexstore'])) { user_error('No index configuration for Solr provided', E_USER_ERROR); } // Find the IndexStore handler, which will handle uploading config files to Solr $mode = $indexstore['mode']; if ($mode == 'file') { return new SolrConfigStore_File($indexstore); } elseif ($mode == 'webdav') { return new SolrConfigStore_WebDAV($indexstore); } elseif (ClassInfo::exists($mode) && ClassInfo::classImplements($mode, 'SolrConfigStore')) { return new $mode($indexstore); } else { user_error('Unknown Solr index mode ' . $indexstore['mode'], E_USER_ERROR); } }