public function augmentSQL(SQLQuery &$query, DataQuery &$dataQuery = null) { // Actives locales defined on a SiteConfig are there as a global setting if ($this->owner instanceof SiteConfig) { return; } // In admin, show everthing anyway if ($this->isAdminBackend()) { return; } // Find in set is only compatible with MySql $c = DB::getConn(); if (!$c instanceof MySQLDatabase) { return; } $locale = $dataQuery->getQueryParam('Fluent.Locale') ?: Fluent::current_locale(); $from = $query->getFrom(); $where = $query->getWhere(); $column = 'ActiveLocales'; $table = null; // Check on which table is the ActiveLocales field foreach ($from as $fromTable => $conditions) { if ($table === null) { $table = $fromTable; } $db = DataObject::custom_database_fields($fromTable); if ($db && isset($db[$column])) { $table = $fromTable; break; } } $identifier = "\"{$table}\".\"{$column}\""; $where[] = "{$identifier} IS NULL OR FIND_IN_SET ('{$locale}', {$identifier}) > 0"; $query->setWhere($where); }
/** * Determines the fields to translate on the given class * * @return array List of field names and data types */ public static function translated_fields_for($class) { if (isset(self::$translated_fields_for_cache[$class])) { return self::$translated_fields_for_cache[$class]; } return self::$translated_fields_for_cache[$class] = self::without_fluent_fields(function () use($class) { $db = DataObject::custom_database_fields($class); $filter = Config::inst()->get($class, 'translate', Config::UNINHERITED); if ($filter === 'none') { return array(); } // Data and field filters $fieldsInclude = Fluent::config()->field_include; $fieldsExclude = Fluent::config()->field_exclude; $dataInclude = Fluent::config()->data_include; $dataExclude = Fluent::config()->data_exclude; // filter out DB if ($db) { foreach ($db as $field => $type) { if (!empty($filter)) { // If given an explicit field name filter, then remove non-presented fields if (!in_array($field, $filter)) { unset($db[$field]); } } else { // Without a name filter then check against each filter type if ($fieldsInclude && !Fluent::any_match($field, $fieldsInclude) || $fieldsExclude && Fluent::any_match($field, $fieldsExclude) || $dataInclude && !Fluent::any_match($type, $dataInclude) || $dataExclude && Fluent::any_match($type, $dataExclude)) { unset($db[$field]); } } } } return $db; }); }
/** * 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; }
public function forApi() { $fields = array_merge(array('ID', 'ClassName', 'LastEdited', 'Title', 'MenuTitle', 'ShowInMenus', 'ShowInSearch', 'Sort', 'ParentID', 'Content', 'Sections'), array_keys(DataObject::custom_database_fields($this->ClassName))); return $this->getFieldsForAPI($fields); }
/** * Test that db fields for a translated objects is correctly extended */ public function testTranslateFields() { $db = DataObject::custom_database_fields('FluentTest_TranslatedObject'); ksort($db); $this->assertEquals(array('Description' => 'Text', 'Description_en_NZ' => 'Text', 'Description_en_US' => 'Text', 'Description_es_ES' => 'Text', 'Description_fr_CA' => 'Text', 'ImageID' => 'ForeignKey', 'ImageID_en_NZ' => 'Int', 'ImageID_en_US' => 'Int', 'ImageID_es_ES' => 'Int', 'ImageID_fr_CA' => 'Int', 'Title' => 'Varchar(255)', 'Title_en_NZ' => 'Varchar(255)', 'Title_en_US' => 'Varchar(255)', 'Title_es_ES' => 'Varchar(255)', 'Title_fr_CA' => 'Varchar(255)', 'URLKey' => 'Text'), $db); }
/** * Getter similar to DataObject::get(); returns a SS_List of products filtered by the requirements in self::getRequiredAttributes(); * If an product is free of charge, it can have no price. This is for giveaways and gifts. * * Expected format of $joins: * <pre> * array( * array( * 'table' => 'JoinTableName_1', * 'on' => 'JoinTableOnClause_1', * 'alias' => 'JoinTableAlias_1', * ), * array( * 'table' => 'JoinTableName_2', * 'on' => 'JoinTableOnClause_2', * 'alias' => 'JoinTableAlias_2', * ), * ... * ) * </pre> * * @param string $whereClause to be inserted into the sql where clause * @param string $sort string with sort clause * @param array $joins left join data as multi dimensional array * @param integer $limit DataObject limit * * @return PaginatedList|ArrayList PaginatedList of products or empty ArrayList * * @author Roland Lehmann <*****@*****.**>, * Sebastian Diel <*****@*****.**> * @since 03.02.2015 */ public static function getProducts($whereClause = "", $sort = null, $joins = null, $limit = null) { $requiredAttributes = self::getRequiredAttributes(); $pricetype = SilvercartConfig::Pricetype(); $filter = ""; if (!empty($requiredAttributes)) { foreach ($requiredAttributes as $requiredAttribute) { //find out if we are dealing with a real attribute or a multilingual field if (array_key_exists($requiredAttribute, DataObject::custom_database_fields('SilvercartProduct')) || $requiredAttribute == "Price") { if ($requiredAttribute == "Price") { // Gross price as default if not defined if ($pricetype == "net") { $filter .= sprintf("(PriceNetAmount != 0.0) AND "); } else { $filter .= sprintf("(PriceGrossAmount != 0.0) AND "); } } else { $filter .= sprintf("%s != '' AND ", $requiredAttribute); } } else { // if its a multilingual attribute it comes from a relational class $filter .= sprintf("SilvercartProductLanguage.%s != '' AND ", $requiredAttribute); } } } if ($whereClause != "") { $filter = $filter . $whereClause . ' AND '; } $filter .= 'isActive = 1 AND SilvercartProductGroupID > 0'; if ($sort === null) { $sort = self::defaultSort(); } $onclause = sprintf('"SPL"."SilvercartProductID" = "SilvercartProduct"."ID" AND "SPL"."Locale" = \'%s\'', Translatable::get_current_locale()); $databaseFilteredProducts = SilvercartProduct::get()->leftJoin('SilvercartProductLanguage', $onclause, 'SPL')->where($filter)->sort($sort); if (!is_null($joins) && is_array($joins)) { foreach ($joins as $joinData) { $table = $alias = $joinData['table']; $onClause = $joinData['on']; if (array_key_exists('alias', $joinData)) { $alias = $joinData['alias']; } $databaseFilteredProducts = $databaseFilteredProducts->leftJoin($table, $onClause, $alias); } } if (!is_null($limit)) { $offset = 0; if (strpos($limit, ',') !== false) { list($offset, $limit) = explode(',', $limit); } $databaseFilteredProducts = $databaseFilteredProducts->limit($limit, $offset); } if (Controller::curr()->hasMethod('getProductsPerPageSetting') && $databaseFilteredProducts) { $databaseFilteredProducts = new PaginatedList($databaseFilteredProducts, $_GET); $databaseFilteredProducts->setPageLength(Controller::curr()->getProductsPerPageSetting()); } return $databaseFilteredProducts; }
/** * used to find the imported DataObject, e.g not relations * @param $proxy * @param $fields * @return mixed */ private function findDataObject(ProxyObject $proxy, $fields) { $filters = array(); $uniqueFields = array(); foreach ($this->uniqueFields as $field) { if (strpos($field, '.') === false) { $uniqueFields[] = $field; } } if (empty($uniqueFields)) { return null; } $class = $this->dataObjectClass; $dbFields = DataObject::custom_database_fields($class); foreach ($this->uniqueFields as $field) { if (isset($fields[$field]) && isset($dbFields[$field])) { $values = $this->getProxyFieldValues($proxy, $fields[$field]); $filters[$field] = empty($values) ? null : $values[0]; } else { // throw error, field does not exist } } return $class::get()->filter($filters)->first(); }
/** * Returns the active products for this page. * * @return DataObject * * @author Sebastian Diel <*****@*****.**>, * Sascha Koehler <*****@*****.**> * @since 27.07.2015 */ public function ActiveSilvercartProducts() { if (!array_key_exists($this->ID, self::$activeSilvercartProducts)) { $requiredAttributes = SilvercartProduct::getRequiredAttributes(); $activeProducts = array(); $productGroupIDs = self::getFlatChildPageIDsForPage($this->ID); $translations = $this->getTranslations(); if ($translations && $translations->count() > 0) { foreach ($translations as $translation) { $productGroupIDs = array_merge($productGroupIDs, self::getFlatChildPageIDsForPage($translation->ID)); } } $filter = array(''); if (!empty($requiredAttributes)) { foreach ($requiredAttributes as $requiredAttribute) { //find out if we are dealing with a real attribute or a multilingual field if (array_key_exists($requiredAttribute, DataObject::custom_database_fields('SilvercartProduct')) || $requiredAttribute == "Price") { if ($requiredAttribute == "Price") { // Gross price as default if not defined if (SilvercartConfig::Pricetype() == "net") { $filter[] = sprintf('("PriceNetAmount" != 0.0)'); } else { $filter[] = sprintf('("PriceGrossAmount" != 0.0)'); } } else { $filter[] = sprintf('"%s" != \'\'', $requiredAttribute); } } else { // if its a multilingual attribute it comes from a relational class $filter[] = sprintf("SilvercartProductLanguage.%s != ''", $requiredAttribute); } } } if (count($filter) == 1) { $filter = array(); } $filterString = sprintf("isActive = 1\n AND (SilvercartProductGroupID IN (%s)\n OR ID IN (\n SELECT\n SilvercartProductID\n FROM\n SilvercartProduct_SilvercartProductGroupMirrorPages\n WHERE\n SilvercartProductGroupPageID IN (%s)))\n %s", implode(',', $productGroupIDs), implode(',', $productGroupIDs), implode(' AND ', $filter)); $this->extend('updateActiveSilvercartProductsFilter', $filterString); $records = DB::query(sprintf("SELECT\n ID\n FROM\n SilvercartProduct\n WHERE\n %s", $filterString)); foreach ($records as $record) { $activeProducts[] = $record['ID']; } self::$activeSilvercartProducts[$this->ID] = $activeProducts; } $result = new DataObject(); $result->ID = count(self::$activeSilvercartProducts[$this->ID]); $result->Count = count(self::$activeSilvercartProducts[$this->ID]); $result->IDs = self::$activeSilvercartProducts[$this->ID]; return $result; }
/** * Creates pages into the SiteTree and populates them with content * * @see "silversmith help" * @param The parameters, e.g. from the command line */ public static function seed_content($params = array()) { if (!isset($params[2])) { fail("Usage: silversmith seed-content <class name>"); } $className = $params[2]; if (!class_exists($className)) { fail("Class {$className} does not exist!"); } $parentField = !isset($params['parent-field']) ? "ParentID" : $params['parent-field']; $parent = !isset($params['parent']) ? false : $params['parent']; $count = !isset($params['count']) ? 10 : (int) $params['count']; $seedingLevel = !isset($params['seeding-level']) ? 3 : $params['seeding-level']; $verbose = isset($params['verbose']); $site_tree = is_subclass_of($className, "SiteTree"); if (!$site_tree && $seedingLevel < 2) { fail("For non SiteTree objects, a seeding level of at least 2 is required."); } if ($parent) { if (is_numeric($parent)) { $parentObj = DataList::create("SiteTree")->byId((int) $parent); if (!$parentObj) { fail("Page #{$parent} could not be found."); } } else { $parentObj = SiteTree::get_by_link($parent); if (!$parentObj) { $parentObj = DataList::create("SiteTree")->where("Title = '" . trim($parent) . "'")->first(); } if (!$parentObj) { fail("Page '{$parent}' could not be found."); } } } $sample = Folder::find_or_make("silversmith-samples"); if (!$sample->hasChildren()) { $answer = ask("This project does not have sample assets installed, which can be useful for content seeding. Do you want to install them now? (y/n)"); if (strtolower(trim($answer)) == "y") { SilverSmith::add_sample_assets(); } } for ($i = 0; $i < $count; $i++) { $p = new $className(); if ($site_tree) { $p->Title = SilverSmithUtil::get_lipsum_words(rand(2, 5)); $p->Content = SilverSmithUtil::get_default_content($p->obj('Content'), $seedingLevel); state("New {$className} created..."); $p->Status = "Published"; } if ($parent) { $p->{$parentField} = $parentObj->ID; } state("Seeding..."); $p->write(); state("Adding content..."); SilverSmithUtil::add_default_content($p, $seedingLevel); $p->write(); if ($site_tree) { $p->publish("Stage", "Live"); } state("Done.\n"); if ($verbose) { say("Debug output:"); $fields = array_keys(DataObject::custom_database_fields($className)); foreach (array_merge($p->has_many(), $p->many_many()) as $relation => $class) { $fields[] = $relation; if ($p->{$relation}()->exists()) { $p->{$relation} = implode(',', $p->{$relation}()->column('ID')); } else { $p->{$relation} = "(none)"; } } if ($site_tree) { $fields = array_merge(array('Title'), $fields); } foreach ($fields as $field) { say("{$field}: {$p->{$field}}"); } } } }
/** * @param $className * @param $options * @param null $key * @return Field * @throws Exception */ private function createObjectField($className, $options, $key = null) { $field = new Field(); $field->dataType = $className; if (!is_array($options)) { $options = $this->parseProviderOptions($options); } $field->key = $key ?: $className; $field->options = $options; $object = singleton($className); $ancestry = array(); foreach ($object->getClassAncestry() as $className) { $classObject = singleton($className); $ancestry[] = $classObject; } $field->ancestry = $ancestry; $ignoreFields = $this->getIgnoreFields($field, $options); $ignoreLookup = array(); foreach ($ignoreFields as $ignoreField) { $ignoreLookup[$ignoreField] = $ignoreField; } $properties = isset($options['fields']) ? $options['fields'] : array(); $fields = array(); $hasOneFields = array(); $hasManyFields = array(); $manyManyFields = array(); foreach ($field->ancestry as $classObject) { foreach (\DataObject::custom_database_fields($classObject->ClassName) as $fieldName => $fieldType) { $ignored = isset($ignoreLookup[$fieldName]) && !isset($properties[$fieldName]); if ($fieldType !== 'ForeignKey' && !$ignored) { $fields[$fieldName] = $fieldType; } } foreach ($classObject->has_one() as $fieldName => $className) { $ignored = isset($ignoreLookup[$fieldName]) && !isset($properties[$fieldName]); if (!$ignored && isset($options['fields']) && array_key_exists($fieldName, $options['fields'])) { $hasOneFields[$fieldName] = $className; } } // limit to fields that specify use foreach ($classObject->has_many() as $fieldName => $className) { $ignored = isset($ignoreLookup[$fieldName]) && !isset($properties[$fieldName]); if (!$ignored && isset($options['fields']) && array_key_exists($fieldName, $options['fields'])) { $hasManyFields[$fieldName] = $className; } } // limit to fields that specify use foreach ($classObject->many_many() as $fieldName => $className) { $ignored = isset($ignoreLookup[$fieldName]) && !isset($properties[$fieldName]); if (!$ignored && isset($options['fields']) && array_key_exists($fieldName, $options['fields'])) { $manyManyFields[$fieldName] = $className; } } } $properties = array_merge($this->getDefaultProperties($field), $properties); foreach ($fields as $fieldName => $dataType) { $fieldOptions = isset($properties[$fieldName]) ? $properties[$fieldName] : array(); $fieldObject = $this->createField($dataType, $fieldOptions); $fieldObject->fieldName = $fieldName; $fieldObject->name = $fieldName; $fieldObject->parent = $field; $field->fields[] = $fieldObject; } foreach ($hasOneFields as $fieldName => $className) { $fieldOptions = isset($properties[$fieldName]) ? $properties[$fieldName] : array(); $fieldObject = $this->createObjectField($className, $fieldOptions, $field->key); $fieldObject->fieldType = Field::FT_HAS_ONE; $fieldObject->name = $fieldName; $fieldObject->fieldName = $fieldName . 'ID'; $fieldObject->methodName = $fieldName; $fieldObject->parent = $field; $fieldObject->count = 1; $field->hasOne[] = $fieldObject; } foreach ($hasManyFields as $fieldName => $className) { $fieldOptions = isset($properties[$fieldName]) ? $properties[$fieldName] : array(); $fieldObject = $this->createObjectField($className, $fieldOptions, $field->key); $fieldObject->fieldType = Field::FT_HAS_MANY; $fieldObject->name = $fieldName; $fieldObject->methodName = $fieldName; $fieldObject->parent = $field; if (isset($fieldOptions['count']) && is_int($fieldOptions['count'])) { $fieldObject->count = $fieldOptions['count']; } $field->hasMany[] = $fieldObject; } foreach ($manyManyFields as $fieldName => $className) { $fieldOptions = isset($properties[$fieldName]) ? $properties[$fieldName] : array(); $fieldObject = $this->createObjectField($className, $fieldOptions, $field->key); $fieldObject->fieldType = Field::FT_MANY_MANY; $fieldObject->name = $fieldName; $fieldObject->methodName = $fieldName; $fieldObject->parent = $field; if (isset($fieldOptions['count']) && is_int($fieldOptions['count'])) { $fieldObject->count = $fieldOptions['count']; } $field->manyMany[] = $fieldObject; } $this->setProvider($field, $options); return $field; }
public function __construct($record = null, $isSingleton = false, $model = null) { //check what the constructor was passed $dmsObject = null; if ($record && is_subclass_of($record, 'DMSDocumentInterface')) { $dmsObject = $record; $record = null; //cancel the record creation to just create an empty object } //create the object parent::__construct($record, $isSingleton, $model); //copy the DMSDocument object, if passed into the constructor if ($dmsObject) { foreach (array_keys(DataObject::custom_database_fields($dmsObject->ClassName)) as $key) { $this->{$key} = $dmsObject->{$key}; } } }
/** * Generates a GraphViz dot template * * @return String a dot compatible data format */ public function dot() { $opt = array(); $opt['location'] = $this->paramDefault('location', 'mysite'); $opt['ancestry'] = $this->paramDefault('ancestry', 1, 'numeric'); $opt['relations'] = $this->paramDefault('relations', 1, 'numeric'); $opt['fields'] = $this->paramDefault('fields', 1, 'numeric'); $opt['include_root'] = $this->paramDefault('include-root', 0, 'numeric'); $opt['exclude'] = $this->paramDefault('exclude'); $opt['group'] = $this->paramDefault('group', 0, 'numeric'); $opt['rankdir'] = $this->paramDefault('rankdir'); if (!in_array($opt['rankdir'], array('LR', 'TB', 'BT', 'RL'))) { $opt['rankdir'] = 'TB'; } $renderClasses = array(); //Get all DataObject subclasses $dataClasses = ClassInfo::subclassesFor('DataObject'); //Remove DataObject itself array_shift($dataClasses); //Get all classes in a specific folder(s) $folders = explode(",", $opt['location']); $folderClasses = array(); foreach ($folders as $folder) { if (!empty($folder)) { $folderClasses[$folder] = ClassInfo::classes_for_folder($folder); } } $excludeArray = explode(",", $opt['exclude']); //Get the intersection of the two - grouped by the folder foreach ($dataClasses as $key => $dataClass) { foreach ($folderClasses as $folder => $classList) { foreach ($classList as $folderClass) { if (strtolower($dataClass) == strtolower($folderClass)) { //Remove all excluded classes if (!in_array($dataClass, $excludeArray)) { $renderClasses[$folder][$dataClass] = $dataClass; } } } } } if (count($renderClasses) == 0) { user_error("No classes that extend DataObject found in location: " . Convert::raw2xml($opt['location'])); } $folders = new ArrayList(); foreach ($renderClasses as $folderName => $classList) { $folder = new DataObject(); $folder->Name = $folderName; $folder->Group = $opt['group'] == 1; $classes = new ArrayList(); foreach ($classList as $className) { //Create a singleton of the class, to use for has_one,etc instance methods $singleton = singleton($className); //Create a blank DO to use for rendering on the template $class = new DataObject(); $class->ClassName = $className; //Get all the data fields for the class //fields = 0 - No fields //fields = 1 - only uninherited fields //fields = 2 - inherited fields $fields = new ArrayList(); if ($opt['fields'] > 0) { if ($opt['fields'] > 1) { $dataFields = $singleton->inheritedDatabaseFields(); } else { $dataFields = DataObject::custom_database_fields($className); } $fields = self::formatDataFields($dataFields, $fields); } $class->FieldList = $fields; if ($opt['relations'] > 1) { $config = Config::INHERITED; } else { $config = Config::UNINHERITED; } $hasOneArray = Config::inst()->get($className, 'has_one', $config); $hasManyArray = Config::inst()->get($className, 'has_many', $config); $manyManyArray = Config::inst()->get($className, 'many_many', $config); //TODO - what's the difference between: /* $hasOneArray = Config::inst()->get($className, 'has_one'); $hasManyArray = Config::inst()->get($className, 'has_many'); $manyManyArray = Config::inst()->get($className, 'many_many'); //and $hasOneArray = $singleton->has_one(); $hasManyArray = $singleton->has_many(); $manyManyArray = $singleton->many_many(); //Note - has_() calls are verbose - they retrieve relations all the way down to base class // ?? eg; for SiteTree, BackLinkTracking is a belongs_many_many */ //$belongsToArray = $singleton->belongs_to(); //print_r(ClassInfo::ancestry($className)); //print_r($singleton->getClassAncestry()); //Add parent class to HasOne //Remove the default "Parent" because thats the final parent, rather than the immediate parent unset($hasOneArray["Parent"]); $classAncestry = ClassInfo::ancestry($className); //getClassAncestry returns an array ordered from root to called class - to get parent, reverse and remove top element (called class) $classAncestry = array_reverse($classAncestry); array_shift($classAncestry); $parentClass = reset($classAncestry); $hasOneArray["Parent"] = $parentClass; //Ensure DataObject is not shown if include-root = 0 if ($opt['include_root'] == 0 && $parentClass == "DataObject") { unset($hasOneArray["Parent"]); } //if ancestry = 0, remove the "Parent" relation in has_one if ($opt['ancestry'] == 0 && isset($hasOneArray["Parent"])) { unset($hasOneArray["Parent"]); } //if relations = 0, remove all but the parent relation if ($opt['relations'] == 0) { $parent = isset($hasOneArray["Parent"]) ? $hasOneArray["Parent"] : null; if ($parent) { $hasOneArray = array(); $hasOneArray["Parent"] = $parent; } else { $hasOneArray = null; } $hasManyArray = null; $manyManyArray = null; } $class->HasOneList = self::relationObject($hasOneArray, $excludeArray); $class->HasManyList = self::relationObject($hasManyArray, $excludeArray); $class->ManyManyList = self::relationObject($manyManyArray, $excludeArray, $class->ClassName); $classes->push($class); } $folder->Classes = $classes; $folders->push($folder); } $this->customise(array("Rankdir" => $opt['rankdir'], "Folders" => $folders)); // Defend against source_file_comments Config::nest(); Config::inst()->update('SSViewer', 'source_file_comments', false); // Render the output $output = $this->renderWith("Silvergraph"); // Restore the original configuration Config::unnest(); //Set output as plain text, and strip excess empty lines $this->response->addHeader("Content-type", "text/plain"); $output = preg_replace("/(^[\r\n]*|[\r\n]+)[\\s\t]*[\r\n]+/", "\n", $output); return $output; }