/**
  * 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;
 }