/** * Gets all the core template accessors available to SiteTree templates * and caches the result * @return array */ public function getTemplateAccessors() { if ($this->templateAccessors) { return $this->templateAccessors; } $vars = parent::getTemplateAccessors(); $cc = new ReflectionClass('ContentController'); $site_tree = new ReflectionClass('SiteTree'); $hierarchy = new ReflectionClass('Hierarchy'); $methods = array_merge($site_tree->getMethods(), $cc->getMethods(), $hierarchy->getMethods(), array_keys(singleton('SiteTree')->has_many()), array_keys(singleton('SiteTree')->many_many()), array_keys(singleton('SiteTree')->db()), array_keys(DataObject::config()->fixed_fields)); foreach ($methods as $m) { $name = is_object($m) ? $m->getName() : $m; // We only care about methods that follow the UpperCamelCase convention. if (preg_match("/[A-Z]/", $name[0])) { $vars[] = $name; } } // Just a random exception case $vars[] = "Form"; return $this->templateAccessors = $vars; }
public function run($request) { // Extend time limit set_time_limit(100000); // we may need some proivileges for this to work // without this, running under sake is a problem // maybe sake could take care of it ... Security::findAnAdministrator()->login(); $this->checkInstalled(); $this->withTransaction(function ($task) { Versioned::reading_stage('Stage'); $classes = $task->fluentClasses(); $tables = DB::tableList(); $deleteQueue = array(); foreach ($classes as $class) { // Ensure that a translationgroup table exists for this class $groupTable = strtolower($class . "_translationgroups"); if (isset($tables[$groupTable])) { $groupTable = $tables[$groupTable]; } else { Debug::message("Ignoring class without _translationgroups table {$class}", false); continue; } // Disable filter if ($class::has_extension('FluentFilteredExtension')) { $class::remove_extension('FluentFilteredExtension'); } // Select all instances of this class in the default locale $instances = DataObject::get($class, sprintf('"Locale" = \'%s\'', Convert::raw2sql(Fluent::default_locale()))); foreach ($instances as $instance) { $isPublished = false; if ($instance->hasMethod('isPublished')) { $isPublished = $instance->isPublished(); } if ($instance->ObsoleteClassName) { Debug::message("Skipping {$instance->ClassName} with ID {$instanceID} because it from an obsolete class", false); continue; } $instanceID = $instance->ID; $translatedFields = $task->getTranslatedFields($instance->ClassName); Debug::message("Updating {$instance->ClassName} {$instance->MenuTitle} ({$instanceID})", false); $changed = false; // Select all translations for this $translatedItems = DataObject::get($class, sprintf('"Locale" != \'%1$s\' AND "ID" IN ( SELECT "OriginalID" FROM "%2$s" WHERE "TranslationGroupID" IN ( SELECT "TranslationGroupID" FROM "%2$s" WHERE "OriginalID" = %3$d ) )', Convert::raw2sql(Fluent::default_locale()), $groupTable, $instanceID)); foreach ($translatedItems as $translatedItem) { $locale = DB::query(sprintf('SELECT "Locale" FROM "%s" WHERE "ID" = %d', $class, $translatedItem->ID))->value(); // since we are going to delete the stuff // anyway, no need bothering validating it DataObject::config()->validation_enabled = false; // Unpublish and delete translated record if ($translatedItem->hasMethod('doUnpublish')) { Debug::message(" -- Unpublishing {$locale}", false); if ($translatedItem->doUnpublish() === false) { throw new ConvertTranslatableException("Failed to unpublish"); } } Debug::message(" -- Adding {$translatedItem->ID} ({$locale})", false); foreach ($translatedFields as $field) { $trField = Fluent::db_field_for_locale($field, $locale); if ($translatedItem->{$field}) { Debug::message(" -- Adding {$trField}", false); $instance->{$trField} = $translatedItem->{$field}; $changed = true; } } // for some reason, deleting items here has disruptive effects // as too much stuff gets removed, so lets wait with this until the end of the migration $deleteQueue[] = $translatedItem; } if ($changed) { if (!$isPublished) { $instance->write(); } elseif ($instance->doPublish() === false) { Debug::message(" -- Publishing FAILED", false); throw new ConvertTranslatableException("Failed to publish"); } else { Debug::message(" -- Published", false); } } } } foreach ($deleteQueue as $delItem) { Debug::message(" -- Removing {$delItem->ID}", false); $delItem->delete(); } }); }
/** * Returns the table name in the class hierarchy which contains a given * field column for a {@link DataObject}. If the field does not exist, this * will return null. * * @param string $candidateClass * @param string $fieldName * * @return string */ public static function table_for_object_field($candidateClass, $fieldName) { if (!$candidateClass || !$fieldName || !class_exists($candidateClass) || !is_subclass_of($candidateClass, 'DataObject')) { return null; } //normalise class name $candidateClass = self::class_name($candidateClass); $exists = self::exists($candidateClass); // Short circuit for fixed fields $fixed = DataObject::config()->fixed_fields; if ($exists && isset($fixed[$fieldName])) { return self::baseDataClass($candidateClass); } // Find regular field while ($candidateClass && $candidateClass != 'DataObject' && $exists) { if (DataObject::has_own_table($candidateClass) && DataObject::has_own_table_database_field($candidateClass, $fieldName)) { break; } $candidateClass = get_parent_class($candidateClass); $exists = $candidateClass && self::exists($candidateClass); } if (!$candidateClass || !$exists) { return null; } return $candidateClass; }
/** * Gets the form fields as defined through the metadata * on {@link $obj} and the custom parameters passed to FormScaffolder. * Depending on those parameters, the fields can be used in ajax-context, * contain {@link TabSet}s etc. * * @return FieldList */ public function getFieldList() { $fields = new FieldList(); // tabbed or untabbed if ($this->tabbed) { $fields->push(new TabSet("Root", $mainTab = new Tab("Main"))); $mainTab->setTitle(_t('SiteTree.TABMAIN', "Main")); } // Add logical fields directly specified in db config foreach ($this->obj->config()->db as $fieldName => $fieldType) { // Skip restricted fields if ($this->restrictFields && !in_array($fieldName, $this->restrictFields)) { continue; } // @todo Pass localized title if ($this->fieldClasses && isset($this->fieldClasses[$fieldName])) { $fieldClass = $this->fieldClasses[$fieldName]; $fieldObject = new $fieldClass($fieldName); } else { $fieldObject = $this->obj->dbObject($fieldName)->scaffoldFormField(null, $this->getParamsArray()); } // Allow fields to opt-out of scaffolding if (!$fieldObject) { continue; } $fieldObject->setTitle($this->obj->fieldLabel($fieldName)); if ($this->tabbed) { $fields->addFieldToTab("Root.Main", $fieldObject); } else { $fields->push($fieldObject); } } // add has_one relation fields if ($this->obj->hasOne()) { foreach ($this->obj->hasOne() as $relationship => $component) { if ($this->restrictFields && !in_array($relationship, $this->restrictFields)) { continue; } $fieldName = $component === 'SilverStripe\\ORM\\DataObject' ? $relationship : "{$relationship}ID"; if ($this->fieldClasses && isset($this->fieldClasses[$fieldName])) { $fieldClass = $this->fieldClasses[$fieldName]; $hasOneField = new $fieldClass($fieldName); } else { $hasOneField = $this->obj->dbObject($fieldName)->scaffoldFormField(null, $this->getParamsArray()); } if (empty($hasOneField)) { continue; } // Allow fields to opt out of scaffolding $hasOneField->setTitle($this->obj->fieldLabel($relationship)); if ($this->tabbed) { $fields->addFieldToTab("Root.Main", $hasOneField); } else { $fields->push($hasOneField); } } } // only add relational fields if an ID is present if ($this->obj->ID) { // add has_many relation fields if ($this->obj->hasMany() && ($this->includeRelations === true || isset($this->includeRelations['has_many']))) { foreach ($this->obj->hasMany() as $relationship => $component) { if ($this->tabbed) { $relationTab = $fields->findOrMakeTab("Root.{$relationship}", $this->obj->fieldLabel($relationship)); } $fieldClass = isset($this->fieldClasses[$relationship]) ? $this->fieldClasses[$relationship] : 'GridField'; $grid = Object::create($fieldClass, $relationship, $this->obj->fieldLabel($relationship), $this->obj->{$relationship}(), GridFieldConfig_RelationEditor::create()); if ($this->tabbed) { $fields->addFieldToTab("Root.{$relationship}", $grid); } else { $fields->push($grid); } } } if ($this->obj->manyMany() && ($this->includeRelations === true || isset($this->includeRelations['many_many']))) { foreach ($this->obj->manyMany() as $relationship => $component) { if ($this->tabbed) { $relationTab = $fields->findOrMakeTab("Root.{$relationship}", $this->obj->fieldLabel($relationship)); } $fieldClass = isset($this->fieldClasses[$relationship]) ? $this->fieldClasses[$relationship] : 'GridField'; $grid = Object::create($fieldClass, $relationship, $this->obj->fieldLabel($relationship), $this->obj->{$relationship}(), GridFieldConfig_RelationEditor::create()); if ($this->tabbed) { $fields->addFieldToTab("Root.{$relationship}", $grid); } else { $fields->push($grid); } } } } return $fields; }