/** * @param DataObject $owner * @param string $association_name * @param string $inversed_by */ public function __construct(DataObject $owner, $association_name, $inversed_by = null, QueryObject $target_query = null) { $this->owner = $owner; $this->association_name = $association_name; $this->inversed_by = $inversed_by; $this->target_class = $this->owner->has_one($association_name); $this->snapshot = $this->owner->getComponent($this->association_name); $this->target = $this->snapshot; if (is_null($target_query)) { $target_query = new QueryObject(); } $this->target_query = $target_query; UnitOfWork::getInstance()->loadMany2OneAssociation($this); }
public function saveInto(DataObject $record) { $fieldName = $this->name . 'ID'; $hasOnes = $record->has_one($this->name); if (!$hasOnes) { $hasOnes = $record->has_one($fieldName); } // assume that the file is connected via a has-one if (!$hasOnes || !isset($_FILES[$this->name]) || !$_FILES[$this->name]['name']) { return; } $file = new File(); $file->loadUploaded($_FILES[$this->name]); $record->{$fieldName} = $file->ID; }
/** * Recursivly search for a PlaceholderImage. * * @param DataObject $object * @return Image | null */ protected function getPlaceholderImageRecursive(DataObject $object) { if ($object->has_one('PlaceholderImage')) { $image = $object->getComponent('PlaceholderImage'); if ($image->exists()) { return $image; } } $parentObject = $object->hasMethod('Parent') ? $object->Parent() : null; return isset($parentObject) && $parentObject->exists() ? $this->getPlaceholderImageRecursive($parentObject) : null; }
public function __construct(DataObject $onObject, $relationName, $targetFragment = 'before') { $this->onObject = $onObject; $this->relationName = $relationName; $hasOne = $onObject->has_one($relationName); if (!$hasOne) { user_error('Unable to find a has_one relation named ' . $relationName . ' on ' . $onObject->ClassName, E_USER_WARNING); } $this->targetObject = $hasOne; parent::__construct(false, $targetFragment); }
/** * Return a formfield for the extra field column or an edit button for the actions column * * @param GridField $gridField * @param DataObject $record - Record displayed in this row * @param string $columnName * @return string - HTML for the column. Return NULL to skip. */ public function getColumnContent($gridField, $record, $columnName) { Requirements::javascript('GridFieldAddOns/javascript/GridFieldEditableCells.js'); Requirements::css('GridFieldAddOns/css/GridFieldEditableCells.css'); $name = "{$gridField->Name}_EditableCell[{$record->ID}][{$columnName}]"; $value = $record->has_one($columnName) ? $record->{$columnName . 'ID'} : $record->{$columnName}; $field = clone $this->fields->fieldByName($columnName); $field->setName($name); $field->setValue($value); return $field->Field(); }
public function scaffoldFormField($title = null, $params = null) { $relationName = substr($this->name, 0, -2); $hasOneClass = $this->object->has_one($relationName); if ($hasOneClass && singleton($hasOneClass) instanceof Image) { $field = new UploadField($relationName, $title); $field->getValidator()->setAllowedExtensions(array('jpg', 'jpeg', 'png', 'gif')); } elseif ($hasOneClass && singleton($hasOneClass) instanceof File) { $field = new UploadField($relationName, $title); } else { $titleField = singleton($hasOneClass)->hasField('Title') ? "Title" : "Name"; $list = DataList::create($hasOneClass); // Don't scaffold a dropdown for large tables, as making the list concrete // might exceed the available PHP memory in creating too many DataObject instances if ($list->count() < 100) { $field = new DropdownField($this->name, $title, $list->map('ID', $titleField)); $field->setEmptyString(' '); } else { $field = new NumericField($this->name, $title); } } return $field; }
public function scaffoldFormField($title = null, $params = null) { $relationName = substr($this->name, 0, -2); $hasOneClass = $this->object->has_one($relationName); if ($hasOneClass && singleton($hasOneClass) instanceof Image) { if (isset($params['ajaxSafe']) && $params['ajaxSafe']) { $field = new ImageField($relationName, $title, $this->value); } else { $field = new SimpleImageField($relationName, $title, $this->value); } } elseif ($hasOneClass && singleton($hasOneClass) instanceof File) { if (isset($params['ajaxSafe']) && $params['ajaxSafe']) { $field = new FileIFrameField($relationName, $title, $this->value); } else { $field = new FileField($relationName, $title, $this->value); } } else { $titleField = singleton($hasOneClass)->hasField('Title') ? "Title" : "Name"; $map = new SQLMap(singleton($hasOneClass)->extendedSQL(), "ID", $titleField); $field = new DropdownField($this->name, $title, $map, null, null, ' '); } return $field; }
public function __construct(DataObject $controller, $name, $title = null, $className = null, $source = array(), $addTitle = null, $defaultsProperties = array(), $form = null) { $hasOne = false; if (!$title) { $this->title = self::name_to_label($name); } if (!$className) { if (substr($name, -2) == 'ID') { $name = substr($name, 0, -2); } if (!($hasOne = $className = $controller->has_one($name)) && !($className = $controller->belongs_to($name)) && (($settings = $controller->has_many($name)) || ($settings = $controller->many_many($name)))) { if (is_array($settings)) { $className = $settings[1]; } else { $className = $settings; } $this->fieldType = 'CheckboxSetField'; } if (!$className) { trigger_error('Couldn\'t determine class type from field name "' . $name . '". Please define the class name.'); } if ($hasOne) { $name .= 'ID'; } } else { if ($rels = $controller->has_many() + $controller->many_many()) { foreach ($rels as $rel => $class) { if ($class == $className || ClassInfo::is_subclass_of($class, $className)) { $this->fieldType = 'CheckboxSetField'; break; } } } } if (!class_exists($className)) { trigger_error($className . ' class doesn\'t exist'); } $this->setDefaults($defaultsProperties); $this->className = $className; $this->controller = $controller; parent::__construct($name, $title, $source, null, $form); }
/** * 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 FieldSet */ public function getFieldSet() { $fields = new FieldSet(); // tabbed or untabbed if($this->tabbed) { $fields->push(new TabSet("Root", $mainTab = new Tab("Main"))); $mainTab->setTitle(_t('SiteTree.TABMAIN', "Main")); } // add database fields foreach($this->obj->db() as $fieldName => $fieldType) { 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()); } $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->has_one()) { foreach($this->obj->has_one() as $relationship => $component) { if($this->restrictFields && !in_array($relationship, $this->restrictFields)) continue; $hasOneField = $this->obj->dbObject("{$relationship}ID")->scaffoldFormField(null, $this->getParamsArray()); $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->has_many() && ($this->includeRelations === true || isset($this->includeRelations['has_many']))) { foreach($this->obj->has_many() as $relationship => $component) { if($this->tabbed) { $relationTab = $fields->findOrMakeTab( "Root.$relationship", $this->obj->fieldLabel($relationship) ); } $relationshipFields = singleton($component)->summaryFields(); $foreignKey = $this->obj->getComponentJoinField($relationship); $ctf = new ComplexTableField( $this, $relationship, $component, $relationshipFields, "getCMSFields", "$foreignKey = " . $this->obj->ID ); $ctf->setPermissions(TableListField::permissions_for_object($component)); if($this->tabbed) { $fields->addFieldToTab("Root.$relationship", $ctf); } else { $fields->push($ctf); } } } if($this->obj->many_many() && ($this->includeRelations === true || isset($this->includeRelations['many_many']))) { foreach($this->obj->many_many() as $relationship => $component) { if($this->tabbed) { $relationTab = $fields->findOrMakeTab( "Root.$relationship", $this->obj->fieldLabel($relationship) ); } $relationshipFields = singleton($component)->summaryFields(); $filterWhere = $this->obj->getManyManyFilter($relationship, $component); $filterJoin = $this->obj->getManyManyJoin($relationship, $component); $ctf = new ComplexTableField( $this, $relationship, $component, $relationshipFields, "getCMSFields", $filterWhere, '', $filterJoin ); $ctf->setPermissions(TableListField::permissions_for_object($component)); $ctf->popupClass = "ScaffoldingComplexTableField_Popup"; if($this->tabbed) { $fields->addFieldToTab("Root.$relationship", $ctf); } else { $fields->push($ctf); } } } } return $fields; }
/** * @param ProxyObject $proxy * @param DataObject $dataObject * @param $selectFields */ private function setGroups(ProxyObject $proxy, DataObject $dataObject, $selectFields) { if (empty($this->groups)) { return; } $parentObject = null; foreach ($this->groups as $group) { $fields = explode('.', $group); if (count($fields) !== 2) { // TODO move to validation in ->group() error_log('WARNING: Group must be of format [has_one].[has_one->FieldName]'); break; } $class = $dataObject->has_one($fields[0]); if (!$class) { error_log('WARNING: Group is not a valid has_one'); break; } if (!isset($selectFields[$group])) { error_log('WARNING: Group must have a corresponding column in select'); break; } $values = $this->getProxyFieldValues($proxy, $selectFields[$group]); if (empty($values)) { // warning error_log('WARNING: Group does not have a value'); break; } $field = $fields[1]; $value = $values[0]; $groupObject = $class::get()->filter(array($field => $value))->first(); if (!$groupObject) { $groupObject = new $class(); $groupObject->{$field} = $value; $this->write($groupObject); } $this->savedRecords[$class][] = $groupObject->ID; // add data object to group $hasMany = $groupObject->has_many(); $hasMany = array_flip($hasMany); if (isset($hasMany[$dataObject->ClassName])) { $collection = $hasMany[$dataObject->ClassName]; $groupObject->{$collection}()->add($dataObject); } // set parent group, when multiple groups if ($parentObject) { $hasMany = $parentObject->has_many(); $hasMany = array_flip($hasMany); if (isset($hasMany[$groupObject->ClassName])) { $collection = $hasMany[$groupObject->ClassName]; $parentObject->{$collection}()->add($groupObject); } } $parentObject = $groupObject; } }
/** * @param DataObject $obj * @param array $params * @param int|array $sort * @param int|array $limit * @param string $relationName * @return SQLQuery|boolean */ protected function getObjectRelationQuery($obj, $params, $sort, $limit, $relationName) { if ($obj->hasMethod("{$relationName}Query")) { // @todo HACK Switch to ComponentSet->getQuery() once we implement it (and lazy loading) $query = $obj->{"{$relationName}Query"}(null, $sort, null, $limit); $relationClass = $obj->{"{$relationName}Class"}(); } elseif ($relationClass = $obj->many_many($relationName)) { // many_many() returns different notation $relationClass = $relationClass[1]; $query = $obj->getManyManyComponentsQuery($relationName); } elseif ($relationClass = $obj->has_many($relationName)) { $query = $obj->getComponentsQuery($relationName); } elseif ($relationClass = $obj->has_one($relationName)) { $query = null; } else { return false; } // get all results return $this->getSearchQuery($relationClass, $params, $sort, $limit, $query); }
public function saveInto(DataObject $record) { if (!isset($_FILES[$this->name])) { return false; } $fileClass = File::get_class_for_file_extension(pathinfo($_FILES[$this->name]['name'], PATHINFO_EXTENSION)); if ($this->relationAutoSetting) { // assume that the file is connected via a has-one $hasOnes = $record->has_one($this->name); // try to create a file matching the relation $file = is_string($hasOnes) ? Object::create($hasOnes) : new $fileClass(); } else { $file = new $fileClass(); } $this->upload->loadIntoFile($_FILES[$this->name], $file, $this->folderName); if ($this->upload->isError()) { return false; } $file = $this->upload->getFile(); if ($this->relationAutoSetting) { if (!$hasOnes) { return false; } // save to record $record->{$this->name . 'ID'} = $file->ID; } }
/** * 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 database fields foreach ($this->obj->db() as $fieldName => $fieldType) { 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()); } $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->has_one()) { foreach ($this->obj->has_one() as $relationship => $component) { if ($this->restrictFields && !in_array($relationship, $this->restrictFields)) { continue; } $fieldName = $component === '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->has_many() && ($this->includeRelations === true || isset($this->includeRelations['has_many']))) { foreach ($this->obj->has_many() 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->many_many() && ($this->includeRelations === true || isset($this->includeRelations['many_many']))) { foreach ($this->obj->many_many() 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; }
/** * @param DataObject $obj * @param array $params * @param int|array $sort * @param int|array $limit * @param string $relationName * @return SQLQuery|boolean */ protected function getObjectRelationQuery($obj, $params, $sort, $limit, $relationName) { // The relation method will return a DataList, that getSearchQuery subsequently manipulates if ($obj->hasMethod($relationName)) { if ($relationClass = $obj->has_one($relationName)) { $joinField = $relationName . 'ID'; $list = DataList::create($relationClass)->byIDs(array($obj->{$joinField})); } else { $list = $obj->{$relationName}(); } $apiAccess = singleton($list->dataClass())->stat('api_access'); if (!$apiAccess) { return false; } return $this->getSearchQuery($list->dataClass(), $params, $sort, $limit, $list); } }
public function saveInto(DataObject $record) { if (!isset($_FILES[$this->name])) { return false; } if ($this->relationAutoSetting) { // assume that the file is connected via a has-one $hasOnes = $record->has_one($this->name); // try to create a file matching the relation $file = is_string($hasOnes) ? Object::create($hasOnes) : new File(); } else { $file = new File(); } $this->upload->setAllowedExtensions($this->allowedExtensions); $this->upload->setAllowedMaxFileSize($this->allowedMaxFileSize); $this->upload->loadIntoFile($_FILES[$this->name], $file, $this->folderName); if ($this->upload->isError()) { return false; } $file = $this->upload->getFile(); if ($this->relationAutoSetting) { if (!$hasOnes) { return false; } // save to record $record->{$this->name . 'ID'} = $file->ID; } }
/** * Saves the form data into a record. The {@see $name} property of the object is used * to determine the foreign key on the record, e.g. "SomeFileID". * * @param DataObject $record The record associated with the parent form */ public function saveInto(DataObject $record) { if (isset($_REQUEST[$this->name . "ID"])) { $file_id = (int) $_REQUEST[$this->name . "ID"]; if ($file_class = $record->has_one($this->name)) { if ($f = DataObject::get_by_id("File", $file_id)) { if ($f->ClassName != $file_class) { $file = $f->newClassInstance($file_class); $file->write(); } } } $record->{$this->name . 'ID'} = $_REQUEST[$this->name . "ID"]; } }
/** * @param DataObject $entity * @param $association_name * @param null $inversed_by * @param QueryObject $target_query * @return bool|Many2OneAssociation * @throws Exception */ public function getMany2OneAssociation(DataObject $entity, $association_name, $inversed_by = null, QueryObject $target_query = null) { $class_name = $entity->has_one($association_name); if (!$class_name) { throw new Exception(sprintf("entity %s has not an many-to-one association called %s", get_class($entity), $association_name)); } $old = UnitOfWork::getInstance()->getMany2OneAssociation($entity, $association_name); if ($old) { return $old; } return new Many2OneAssociation($entity, $association_name, $inversed_by, $target_query); }
/** * Update all has_ones that are linked to assets * * @param \DataObject $localObject * @param \ArrayData $remoteObject * @return null */ protected function updateLocaleAssetRelations(\DataObject $localObject, \ArrayData $remoteObject) { // Now update all has_one => file relations $changed = false; $relations = $localObject->has_one(); if (empty($relations)) { $this->task->message(" ** No has_ones on {$localObject->Title}", 2); return; } foreach ($relations as $relation => $class) { $this->task->message(" *** Checking relation name {$relation}", 3); // Link file if (!ImportHelper::is_a($class, 'File')) { $this->task->message(" **** {$relation} is not a File", 4); continue; } // Don't link folders if (ImportHelper::is_a($class, 'Folder')) { $this->task->message(" **** {$relation} is a folder", 4); continue; } // No need to import if found in a previous step $field = $relation . "ID"; if ($localObject->{$field}) { $this->task->message(" **** {$relation} already has value {$localObject->{$field}} on local object", 4); continue; } // If the remote object doesn't have this field then can also skip it $remoteFileID = intval($remoteObject->{$field}); if (empty($remoteFileID)) { $this->task->message(" **** {$relation} has no value on remote object", 4); continue; } // Find remote file with this ID $remoteFile = $this->findRemoteFile(array(sprintf('"ID" = %d', intval($remoteFileID)))); if (!$remoteFile) { $this->task->error("Could not find {$relation} file with id {$remoteFileID}"); continue; } // Ensure that this file has a valid name if (!$this->isValidFile($remoteFile->Name)) { $this->task->error("Remote {$relation} file does not have a valid name '" . $remoteFile->Name . "'"); continue; } // Copy file to filesystem and save $localFile = $this->findOrImportFile($remoteFile); if (!$localFile) { $this->task->error("Failed to import {$relation} file '" . $remoteFile->Name . "'"); continue; } // Save new file $changed = true; $this->task->message(" *** {$relation} assigned local value {$localFile->ID}", 3); $localObject->{$field} = $localFile->ID; } if ($changed) { $localObject->write(); } else { $this->task->message(" ** No changes made to relations on {$localObject->Title}", 2); } }