/** * Create an object from a string representation. It treats it as a PHP constructor without the * 'new' keyword. It also manages to construct the object without the use of eval(). * * Construction itself is done with Object::create(), so that Object::useCustomClass() calls * are respected. * * `Object::create_from_string("Versioned('Stage','Live')")` will return the result of * `Versioned::create('Stage', 'Live);` * * It is designed for simple, cloneable objects. The first time this method is called for a given * string it is cached, and clones of that object are returned. * * If you pass the $firstArg argument, this will be prepended to the constructor arguments. It's * impossible to pass null as the firstArg argument. * * `Object::create_from_string("Varchar(50)", "MyField")` will return the result of * `Varchar::create('MyField', '50');` * * Arguments are always strings, although this is a quirk of the current implementation rather * than something that can be relied upon. * * @param string $classSpec * @param mixed $firstArg * @return object */ public static function create_from_string($classSpec, $firstArg = null) { if (!isset(self::$_cache_inst_args[$classSpec . $firstArg])) { // an $extension value can contain parameters as a string, // e.g. "Versioned('Stage','Live')" if (strpos($classSpec, '(') === false) { if ($firstArg === null) { self::$_cache_inst_args[$classSpec . $firstArg] = Object::create($classSpec); } else { self::$_cache_inst_args[$classSpec . $firstArg] = Object::create($classSpec, $firstArg); } } else { list($class, $args) = self::parse_class_spec($classSpec); if ($firstArg !== null) { array_unshift($args, $firstArg); } array_unshift($args, $class); self::$_cache_inst_args[$classSpec . $firstArg] = call_user_func_array(array('SilverStripe\\Core\\Object', 'create'), $args); } } return clone self::$_cache_inst_args[$classSpec . $firstArg]; }
/** * @param DataObject|DataObjectInterface $record */ public function saveInto(DataObjectInterface $record) { if (!isset($_FILES[$this->name])) { return; } $fileClass = File::get_class_for_file_extension(File::get_file_extension($_FILES[$this->name]['name'])); /** @var File $file */ if ($this->relationAutoSetting) { // assume that the file is connected via a has-one $objectClass = DataObject::getSchema()->hasOneComponent(get_class($record), $this->name); if ($objectClass === File::class || empty($objectClass)) { // Create object of the appropriate file class $file = Object::create($fileClass); } else { // try to create a file matching the relation $file = Object::create($objectClass); } } else { if ($record instanceof File) { $file = $record; } else { $file = Object::create($fileClass); } } $this->upload->loadIntoFile($_FILES[$this->name], $file, $this->getFolderName()); if ($this->upload->isError()) { return; } if ($this->relationAutoSetting) { if (empty($objectClass)) { return; } $file = $this->upload->getFile(); $record->{$this->name . 'ID'} = $file->ID; } }
/** * Create a DBField object that's not bound to any particular field. * * Useful for accessing the classes behaviour for other parts of your code. * * @param string $className class of field to construct * @param mixed $value value of field * @param string $name Name of field * @param mixed $object Additional parameter to pass to field constructor * @return DBField */ public static function create_field($className, $value, $name = null, $object = null) { /** @var DBField $dbField */ $dbField = Object::create($className, $name, $object); $dbField->setValue($value, null, false); return $dbField; }
/** * Loads the temporary file data into a File object * * @param array $tmpFile Temporary file data * @param string $error Error message * @return AssetContainer File object, or null if error */ protected function saveTemporaryFile($tmpFile, &$error = null) { // Determine container object $error = null; $fileObject = null; if (empty($tmpFile)) { $error = _t('UploadField.FIELDNOTSET', 'File information not found'); return null; } if ($tmpFile['error']) { $error = $tmpFile['error']; return null; } // Search for relations that can hold the uploaded files, but don't fallback // to default if there is no automatic relation if ($relationClass = $this->getRelationAutosetClass(null)) { // Allow File to be subclassed if ($relationClass === 'SilverStripe\\Assets\\File' && isset($tmpFile['name'])) { $relationClass = File::get_class_for_file_extension(File::get_file_extension($tmpFile['name'])); } // Create new object explicitly. Otherwise rely on Upload::load to choose the class. $fileObject = Object::create($relationClass); if (!$fileObject instanceof DataObject || !$fileObject instanceof AssetContainer) { throw new InvalidArgumentException("Invalid asset container {$relationClass}"); } } // Get the uploaded file into a new file object. try { $this->upload->loadIntoFile($tmpFile, $fileObject, $this->getFolderName()); } catch (Exception $e) { // we shouldn't get an error here, but just in case $error = $e->getMessage(); return null; } // Check if upload field has an error if ($this->upload->isError()) { $error = implode(' ' . PHP_EOL, $this->upload->getErrors()); return null; } // return file return $this->upload->getFile(); }
/** * * @param GridField $gridField * @param HTTPRequest $request * @return GridFieldDetailForm_ItemRequest */ public function handleItem($gridField, $request) { // Our getController could either give us a true Controller, if this is the top-level GridField. // It could also give us a RequestHandler in the form of GridFieldDetailForm_ItemRequest if this is a // nested GridField. $requestHandler = $gridField->getForm()->getController(); /** @var DataObject $record */ if (is_numeric($request->param('ID'))) { $record = $gridField->getList()->byID($request->param("ID")); } else { $record = Object::create($gridField->getModelClass()); } $handler = $this->getItemRequestHandler($gridField, $record, $requestHandler); // if no validator has been set on the GridField and the record has a // CMS validator, use that. if (!$this->getValidator() && (method_exists($record, 'getCMSValidator') || $record instanceof Object && $record->hasMethod('getCMSValidator'))) { $this->setValidator($record->getCMSValidator()); } return $handler->handleRequest($request, DataModel::inst()); }
/** * Given a file and filename, ensure that file renaming / replacing rules are satisfied * * If replacing, this method may replace $this->file with an existing record to overwrite. * If renaming, a new value for $filename may be returned * * @param string $filename * @return string $filename A filename safe to write to * @throws Exception */ protected function resolveExistingFile($filename) { // Create a new file record (or try to retrieve an existing one) if (!$this->file) { $fileClass = File::get_class_for_file_extension(File::get_file_extension($filename)); $this->file = Object::create($fileClass); } // Skip this step if not writing File dataobjects if (!$this->file instanceof File) { return $filename; } // Check there is if existing file $existing = File::find($filename); // If replacing (or no file exists) confirm this filename is safe if ($this->replaceFile || !$existing) { // If replacing files, make sure to update the OwnerID if (!$this->file->ID && $this->replaceFile && $existing) { $this->file = $existing; $this->file->OwnerID = Member::currentUserID(); } // Filename won't change if replacing return $filename; } // if filename already exists, version the filename (e.g. test.gif to test-v2.gif, test-v2.gif to test-v3.gif) $renamer = $this->getNameGenerator($filename); foreach ($renamer as $newName) { if (!File::find($newName)) { return $newName; } } // Fail $tries = $renamer->getMaxTries(); throw new Exception("Could not rename {$filename} with {$tries} tries"); }
/** * 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) { $fields->findOrMakeTab("Root.{$relationship}", $this->obj->fieldLabel($relationship)); } $fieldClass = isset($this->fieldClasses[$relationship]) ? $this->fieldClasses[$relationship] : 'SilverStripe\\Forms\\GridField\\GridField'; /** @var GridField $grid */ $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) { $fields->findOrMakeTab("Root.{$relationship}", $this->obj->fieldLabel($relationship)); } $fieldClass = isset($this->fieldClasses[$relationship]) ? $this->fieldClasses[$relationship] : 'SilverStripe\\Forms\\GridField\\GridField'; /** @var GridField $grid */ $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; }