/** * The list of TodoLists * * @param SS_List $lists * @return $this */ public function setLists($lists) { $this->lists = $lists->filterByCallback(function ($item) { return $item->canView(); }); return $this; }
/** * Generate a {@link PHPExcel} for the provided DataObject List * @param SS_List $set List of DataObjects * @return PHPExcel */ public function getPhpExcelObject(SS_List $set) { // Get the first object. We'll need it to know what type of objects we // are dealing with $first = $set->first(); // Get the Excel object $excel = $this->setupExcel($first); $sheet = $excel->setActiveSheetIndex(0); // Make sure we have at lease on item. If we don't, we'll be returning // an empty spreadsheet. if ($first) { // Set up the header row $fields = $this->getFieldsForObj($first); $this->headerRow($sheet, $fields); // Add a new row for each DataObject foreach ($set as $item) { $this->addRow($sheet, $item, $fields); } // Freezing the first column and the header row $sheet->freezePane("B2"); // Auto sizing all the columns $col = sizeof($fields); for ($i = 0; $i < $col; $i++) { $sheet->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($i))->setAutoSize(true); } } return $excel; }
/** * Helper method for processing batch actions. * Returns a set of status-updating JavaScript to return to the CMS. * * @param $objs The SS_List of objects to perform this batch action * on. * @param $helperMethod The method to call on each of those objects. * @return JSON encoded map in the following format: * { * 'modified': { * 3: {'TreeTitle': 'Page3'}, * 5: {'TreeTitle': 'Page5'} * }, * 'deleted': { * // all deleted pages * } * } */ public function batchaction(SS_List $objs, $helperMethod, $successMessage, $arguments = array()) { $status = array('modified' => array(), 'error' => array()); foreach($objs as $obj) { // Perform the action if (!call_user_func_array(array($obj, $helperMethod), $arguments)) { $status['error'][$obj->ID] = ''; } // Now make sure the tree title is appropriately updated $publishedRecord = DataObject::get_by_id($this->managedClass, $obj->ID); if ($publishedRecord) { $status['modified'][$publishedRecord->ID] = array( 'TreeTitle' => $publishedRecord->TreeTitle, ); } $obj->destroy(); unset($obj); } $response = Controller::curr()->getResponse(); if($response) { $response->setStatusCode( 200, sprintf($successMessage, $objs->Count(), count($status['error'])) ); } return Convert::raw2json($status); }
/** * {@inheritdoc} */ public function getColumnContent($gridField, $record, $columnName) { if ($columnName === 'MergeAction' && $record->{$this->childMethod}()->Count() > 0) { $dropdown = new DropdownField('Target', 'Target', $this->records->exclude('ID', $record->ID)->map()); $prefix = strtolower($this->parentMethod . '-' . $this->childMethod); $action = GridFieldFormAction::create($gridField, 'MergeAction' . $record->ID, 'Move', 'merge', array('record' => $record->ID, 'target' => $prefix . '-target-record-' . $record->ID)); $action->setExtraAttributes(array('data-target' => $prefix . '-target-record-' . $record->ID)); return $dropdown->Field() . $action->Field() . '<a title="Move posts to" class="MergeActionReveal">move posts to</a>'; } return null; }
/** * @param SS_List $scope the scope to iterate over - handy if you don't want * to add this extension for a one-off use * @return array */ public static function to_autocomplete_array($scope) { $items = $scope->toArray(); foreach ($items as &$item) { if ($item->hasMethod('toAutocompleteMap')) { $item = $item->toAutocompleteMap(); } else { $item = $item->toMap(); } } return $items; }
/** * Usage [e.g. in getCMSFields] * $field = new PickerField('Authors', 'Selected Authors', $this->Authors(), 'Select Author(s)'); * * @param string $name - Name of field (typically the relationship method) * @param string $title - GridField Title * @param SS_List $dataList - Result of the relationship component method (E.g. $this->Authors()) * @param string $linkExistingTitle - AddExisting Button Title * @param string $sortField - Field to sort on. Be sure it exists in the $many_many_extraFields static */ public function __construct($name, $title = null, SS_List $dataList = null, $linkExistingTitle = null, $sortField = null) { $config = GridfieldConfig::create()->addComponents(new GridFieldButtonRow('before'), new GridFieldToolbarHeader(), new GridFieldDataColumns(), new GridFieldTitleHeader(), new GridFieldPaginator(), new PickerFieldAddExistingSearchButton(), new PickerFieldDeleteAction()); if ($sortField) { $config->addComponent(new GridFieldOrderableRows($sortField)); } if (!$linkExistingTitle) { $linkExistingTitle = $this->isHaveOne() ? 'Select a ' . $dataList->dataClass() : 'Select ' . $dataList->dataClass() . '(s)'; // plural [has_many, many_many] } $config->getComponentByType('PickerFieldAddExistingSearchButton')->setTitle($linkExistingTitle); return parent::__construct($name, $title, $dataList, $config); }
/** * Adds the records to the database and returns a new {@link DataList} * * @param GridField * @param SS_List * @return SS_List */ public function getManipulatedData(GridField $gridField, SS_List $dataList) { $state = $gridField->State->MockDataGenerator; $count = (string) $state->Count; if (!$count) { return $dataList; } $generator = new MockDataBuilder($gridField->getModelClass()); $ids = $generator->setCount($count)->setIncludeRelations($state->IncludeRelations)->setDownloadImages($state->DownloadImages === true)->generate(); foreach ($ids as $id) { $dataList->add($id); } return $dataList; }
/** * @param string $name * @param string $title * @param DataObjectInterface $object * @param string $sort * @param SS_List $source * @param string $titleField */ public function __construct($name, $title, DataObjectInterface $object, $sort = false, SS_List $source = null, $titleField = 'Title') { $this->setSort($sort); if ($object->many_many($name)) { $dataSource = $object->{$name}(); // Check if we're dealing with an UnsavedRelationList $unsaved = $dataSource instanceof UnsavedRelationList; // Store the relation's class name $class = $dataSource->dataClass(); $this->dataClass = $class; // Sort the items if ($this->getSort()) { $dataSource = $dataSource->sort($this->getSort()); } // If we're dealing with an UnsavedRelationList, it'll be empty, so we // can skip this and just use an array of all available items if ($unsaved) { $dataSource = $class::get()->map()->toArray(); } else { // If we've been given a list source, filter on those IDs only. if ($source) { $dataSource = $dataSource->filter('ID', $source->column('ID')); } // Start building the data source from scratch. Currently selected items first, // in the correct sort order $dataSource = $dataSource->map('ID', $titleField)->toArray(); // Get the other items $theRest = $class::get(); // Exclude items that we've already found if (!empty($dataSource)) { $theRest = $theRest->exclude('ID', array_keys($dataSource)); } // If we've been given a list source, filter on those IDs only if ($source) { $theRest = $theRest->filter('ID', $source->column('ID')); } $theRest = $theRest->map('ID', $titleField)->toArray(); // ... we then add the remaining items in whatever order they come $dataSource = $dataSource + $theRest; } } elseif ($source instanceof SS_List) { $dataSource = $source->map('ID', $titleField)->toArray(); } elseif (is_array($source) && ArrayLib::is_associative($source)) { $dataSource = $source; } else { user_error('MultiSelectField::__construct(): MultiSelectField only supports many-to-many relations'); } parent::__construct($name, $title, $dataSource, '', null, true); }
public function getManipulatedData(GridField $gridField, SS_List $dataList) { if (!$gridField->State->GridFieldAddRelation) { return $dataList; } $objectID = Convert::raw2sql($gridField->State->GridFieldAddRelation); if ($objectID) { $object = DataObject::get_by_id($dataList->dataclass(), $objectID); if ($object) { $dataList->add($object); } } $gridField->State->GridFieldAddRelation = null; return $dataList; }
/** * Get the list of extra data from the $record as saved into it by * {@see Form::saveInto()} * * Handles detection of falsey values explicitly saved into the * DataObject by formfields * * @param DataObject $record * @param SS_List $list * @return array List of data to write to the relation */ protected function getExtraSavedData($record, $list) { // Skip extra data if not ManyManyList if (!$list instanceof ManyManyList) { return null; } $data = array(); foreach ($list->getExtraFields() as $field => $dbSpec) { $savedField = "ManyMany[{$field}]"; if ($record->hasField($savedField)) { $data[$field] = $record->getField($savedField); } } return $data; }
public function run(SS_List $pages) { // Sort pages by depth $pageArray = $pages->toArray(); // because of https://bugs.php.net/bug.php?id=50688 foreach ($pageArray as $page) { $page->getPageLevel(); } usort($pageArray, function ($a, $b) { return $a->getPageLevel() - $b->getPageLevel(); }); $pages = new ArrayList($pageArray); // Restore return $this->batchaction($pages, 'doRestoreToStage', _t('CMSBatchActions.RESTORED_PAGES', 'Restored %d pages')); }
/** * @return SS_List */ public function getItems() { $name = $this->getName(); if (!$this->items || !$this->items->exists()) { $record = $this->getRecord(); $this->items = array(); // Try to auto-detect relationship if ($record && $record->exists()) { if ($record->has_many($name) || $record->many_many($name)) { // Ensure relationship is cast to an array, as we can't alter the items of a DataList/RelationList (see below) $this->items = $record->{$name}()->toArray(); } elseif ($record->has_one($name)) { $item = $record->{$name}(); if ($item && $item->exists()) { $this->items = array($record->{$name}()); } } } $this->items = new ArrayList($this->items); // hack to provide $UploadFieldThumbnailURL, $hasRelation and $UploadFieldEditLink in template for each file if ($this->items->exists()) { foreach ($this->items as $i => $file) { $this->items[$i] = $this->customiseFile($file); if (!$file->canView()) { unset($this->items[$i]); } // Respect model permissions } } } return $this->items; }
/** * If an object ID is set, add the object to the list * * @param GridField $gridField * @param SS_List $dataList * @return SS_List */ public function getManipulatedData(GridField $gridField, SS_List $dataList) { if (!$gridField->State->GridFieldAddRelation) { return $dataList; } $objectID = Convert::raw2sql($gridField->State->GridFieldAddRelation); if ($objectID) { $object = DataObject::get_by_id($dataList->dataclass(), $objectID); if ($object) { $virtual = new ElementVirtualLinked(); $virtual->LinkedElementID = $object->ID; $virtual->write(); $dataList->add($virtual); } } $gridField->State->GridFieldAddRelation = null; return $dataList; }
/** * Takes a list of groups and members and return a list of unique member. * * @param SS_List $groups * @param SS_List $members * * @return ArrayList */ public static function merge_owners(SS_List $groups, SS_List $members) { $contentReviewOwners = new ArrayList(); if ($groups->count()) { $groupIDs = array(); foreach ($groups as $group) { $familyIDs = $group->collateFamilyIDs(); if (is_array($familyIDs)) { $groupIDs = array_merge($groupIDs, array_values($familyIDs)); } } array_unique($groupIDs); if (count($groupIDs)) { $groupMembers = DataObject::get("Member")->where("\"Group\".\"ID\" IN (" . implode(",", $groupIDs) . ")")->leftJoin("Group_Members", "\"Member\".\"ID\" = \"Group_Members\".\"MemberID\"")->leftJoin("Group", "\"Group_Members\".\"GroupID\" = \"Group\".\"ID\""); $contentReviewOwners->merge($groupMembers); } } $contentReviewOwners->merge($members); $contentReviewOwners->removeDuplicates(); return $contentReviewOwners; }
/** * Returns a data class that is a DataObject type that this GridField should look like. * * @return string * * @throws LogicException */ public function getModelClass() { if ($this->modelClassName) { return $this->modelClassName; } if ($this->list && method_exists($this->list, 'dataClass')) { $class = $this->list->dataClass(); if ($class) { return $class; } } throw new LogicException('GridField doesn\'t have a modelClassName, so it doesn\'t know the columns of this grid.'); }
/** * If an object ID is set, add the object to the list * * @param GridField $gridField * @param SS_List $dataList * @return SS_List */ public function getManipulatedData(GridField $gridField, SS_List $dataList) { if (!$gridField->State->GridFieldAddRelation) { return $dataList; } $objectID = Convert::raw2sql($gridField->State->GridFieldAddRelation); if ($objectID) { $object = DataObject::get_by_id($dataList->dataclass(), $objectID); if ($object) { if ($this->_item_limit > 0 && $dataList->count() + 1 > $this->_item_limit) { $gridField->getForm()->getController()->getResponse()->addHeader('X-Status', _t('LimitedRelationsGridField.ITEM_LIMIT_REACHED', '_You cannot add any more items, you can only add {count} items. Please remove one then try again.', array('count' => $this->_item_limit))); } else { $dataList->add($object); } } } $gridField->State->GridFieldAddRelation = null; return $dataList; }
/** * If an object ID is set, add the object to the list * * @param GridField $gridField * @param SS_List $dataList * @return SS_List */ public function getManipulatedData(GridField $gridField, SS_List $dataList) { if (!$gridField->State->GridFieldAddRelation) { return $dataList; } $objectID = Convert::raw2sql($gridField->State->GridFieldAddRelation); if ($objectID) { $object = DataObject::get_by_id($dataList->dataclass(), $objectID); if ($object) { // if the object is currently not linked to either a page or another list then we want to link to // the original, otherwise link to a clone if (!$object->ParentID && !$object->ListID) { $dataList->add($object); } else { $virtual = new ElementVirtualLinked(); $virtual->LinkedElementID = $object->ID; $virtual->write(); $dataList->add($virtual); } } } $gridField->State->GridFieldAddRelation = null; return $dataList; }
/** * Loads the related record values into this field. UploadField can be uploaded * in one of three ways: * * - By passing in a list of file IDs in the $value parameter (an array with a single * key 'Files', with the value being the actual array of IDs). * - By passing in an explicit list of File objects in the $record parameter, and * leaving $value blank. * - By passing in a dataobject in the $record parameter, from which file objects * will be extracting using the field name as the relation field. * * Each of these methods will update both the items (list of File objects) and the * field value (list of file ID values). * * @param array $value Array of submitted form data, if submitting from a form * @param array|DataObject|SS_List $record Full source record, either as a DataObject, * SS_List of items, or an array of submitted form data * @return UploadField Self reference */ public function setValue($value, $record = null) { // If we're not passed a value directly, we can attempt to infer the field // value from the second parameter by inspecting its relations $items = new ArrayList(); // Determine format of presented data if (empty($value) && $record) { // If a record is given as a second parameter, but no submitted values, // then we should inspect this instead for the form values if ($record instanceof DataObject && $record->hasMethod($this->getName())) { // If given a dataobject use reflection to extract details $data = $record->{$this->getName()}(); if ($data instanceof DataObject) { // If has_one, add sole item to default list $items->push($data); } elseif ($data instanceof SS_List) { // For many_many and has_many relations we can use the relation list directly $items = $data; } } elseif ($record instanceof SS_List) { // If directly passing a list then save the items directly $items = $record; } } elseif (!empty($value['Files'])) { // If value is given as an array (such as a posted form), extract File IDs from this $class = $this->getRelationAutosetClass(); $items = DataObject::get($class)->byIDs($value['Files']); } // If javascript is disabled, direct file upload (non-html5 style) can // trigger a single or multiple file submission. Note that this may be // included in addition to re-submitted File IDs as above, so these // should be added to the list instead of operated on independently. if ($uploadedFiles = $this->extractUploadedFileData($value)) { foreach ($uploadedFiles as $tempFile) { $file = $this->saveTemporaryFile($tempFile, $error); if ($file) { $items->add($file); } else { throw new ValidationException($error); } } } // Filter items by what's allowed to be viewed $filteredItems = new ArrayList(); $fileIDs = array(); foreach ($items as $file) { if ($file->exists() && $file->canView()) { $filteredItems->push($file); $fileIDs[] = $file->ID; } } // Filter and cache updated item list $this->items = $filteredItems; // Same format as posted form values for this field. Also ensures that // $this->setValue($this->getValue()); is non-destructive $value = $fileIDs ? array('Files' => $fileIDs) : null; // Set value using parent return parent::setValue($value, $record); }
public function Field($properties = array()) { Requirements::css(FRAMEWORK_DIR . '/css/CheckboxSetField.css'); Requirements::javascript(FRAMEWORK_DIR . '/javascript/PermissionCheckboxSetField.js'); $uninheritedCodes = array(); $inheritedCodes = array(); $records = $this->records ? $this->records : new ArrayList(); // Get existing values from the form record (assuming the formfield name is a join field on the record) if (is_object($this->form)) { $record = $this->form->getRecord(); if ($record && (is_a($record, 'Group') || is_a($record, 'PermissionRole')) && !$records->find('ID', $record->ID)) { $records->push($record); } } // Get all 'inherited' codes not directly assigned to the group (which is stored in $values) foreach ($records as $record) { // Get all uninherited permissions $relationMethod = $this->name; foreach ($record->{$relationMethod}() as $permission) { if (!isset($uninheritedCodes[$permission->Code])) { $uninheritedCodes[$permission->Code] = array(); } $uninheritedCodes[$permission->Code][] = _t('PermissionCheckboxSetField.AssignedTo', 'assigned to "{title}"', array('title' => $record->Title)); } // Special case for Group records (not PermissionRole): // Determine inherited assignments if (is_a($record, 'Group')) { // Get all permissions from roles if ($record->Roles()->Count()) { foreach ($record->Roles() as $role) { foreach ($role->Codes() as $code) { if (!isset($inheritedCodes[$code->Code])) { $inheritedCodes[$code->Code] = array(); } $inheritedCodes[$code->Code][] = _t('PermissionCheckboxSetField.FromRole', 'inherited from role "{title}"', 'A permission inherited from a certain permission role', array('title' => $role->Title)); } } } // Get from parent groups $parentGroups = $record->getAncestors(); if ($parentGroups) { foreach ($parentGroups as $parent) { if (!$parent->Roles()->Count()) { continue; } foreach ($parent->Roles() as $role) { if ($role->Codes()) { foreach ($role->Codes() as $code) { if (!isset($inheritedCodes[$code->Code])) { $inheritedCodes[$code->Code] = array(); } $inheritedCodes[$code->Code][] = _t('PermissionCheckboxSetField.FromRoleOnGroup', 'inherited from role "%s" on group "%s"', 'A permission inherited from a role on a certain group', array('roletitle' => $role->Title, 'grouptitle' => $parent->Title)); } } } if ($parent->Permissions()->Count()) { foreach ($parent->Permissions() as $permission) { if (!isset($inheritedCodes[$permission->Code])) { $inheritedCodes[$permission->Code] = array(); } $inheritedCodes[$permission->Code][] = _t('PermissionCheckboxSetField.FromGroup', 'inherited from group "{title}"', 'A permission inherited from a certain group', array('title' => $parent->Title)); } } } } } } $odd = 0; $options = ''; $globalHidden = (array) Config::inst()->get('Permission', 'hidden_permissions'); if ($this->source) { $privilegedPermissions = Permission::config()->privileged_permissions; // loop through all available categorized permissions and see if they're assigned for the given groups foreach ($this->source as $categoryName => $permissions) { $options .= "<li><h5>{$categoryName}</h5></li>"; foreach ($permissions as $code => $permission) { if (in_array($code, $this->hiddenPermissions)) { continue; } if (in_array($code, $globalHidden)) { continue; } $value = $permission['name']; $odd = ($odd + 1) % 2; $extraClass = $odd ? 'odd' : 'even'; $extraClass .= ' val' . str_replace(' ', '', $code); $itemID = $this->id() . '_' . preg_replace('/[^a-zA-Z0-9]+/', '', $code); $checked = $disabled = $inheritMessage = ''; $checked = isset($uninheritedCodes[$code]) || isset($inheritedCodes[$code]) ? ' checked="checked"' : ''; $title = $permission['help'] ? 'title="' . htmlentities($permission['help'], ENT_COMPAT, 'UTF-8') . '" ' : ''; if (isset($inheritedCodes[$code])) { // disable inherited codes, as any saving logic would be too complicate to express in this // interface $disabled = ' disabled="true"'; $inheritMessage = ' (' . join(', ', $inheritedCodes[$code]) . ')'; } elseif ($this->records && $this->records->Count() > 1 && isset($uninheritedCodes[$code])) { // If code assignments are collected from more than one "source group", // show its origin automatically $inheritMessage = ' (' . join(', ', $uninheritedCodes[$code]) . ')'; } // Disallow modification of "privileged" permissions unless currently logged-in user is an admin if (!Permission::check('ADMIN') && in_array($code, $privilegedPermissions)) { $disabled = ' disabled="true"'; } // If the field is readonly, always mark as "disabled" if ($this->readonly) { $disabled = ' disabled="true"'; } $inheritMessage = '<small>' . $inheritMessage . '</small>'; $icon = $checked ? 'accept' : 'decline'; // If the field is readonly, add a span that will replace the disabled checkbox input if ($this->readonly) { $options .= "<li class=\"{$extraClass}\">" . "<input id=\"{$itemID}\"{$disabled} name=\"{$this->name}[{$code}]\" type=\"checkbox\"" . " value=\"{$code}\"{$checked} class=\"checkbox\" />" . "<label {$title}for=\"{$itemID}\">" . "<span class=\"ui-button-icon-primary ui-icon btn-icon-{$icon}\"></span>" . "{$value}{$inheritMessage}</label>" . "</li>\n"; } else { $options .= "<li class=\"{$extraClass}\">" . "<input id=\"{$itemID}\"{$disabled} name=\"{$this->name}[{$code}]\" type=\"checkbox\"" . " value=\"{$code}\"{$checked} class=\"checkbox\" />" . "<label {$title}for=\"{$itemID}\">{$value}{$inheritMessage}</label>" . "</li>\n"; } } } } if ($this->readonly) { return "<ul id=\"{$this->id()}\" class=\"optionset checkboxsetfield{$this->extraClass()}\">\n" . "<li class=\"help\">" . _t('Permissions.UserPermissionsIntro', 'Assigning groups to this user will adjust the permissions they have.' . ' See the groups section for details of permissions on individual groups.') . "</li>" . $options . "</ul>\n"; } else { return "<ul id=\"{$this->id()}\" class=\"optionset checkboxsetfield{$this->extraClass()}\">\n" . $options . "</ul>\n"; } }
/** * Detects and corrects items with a sort column value of 0, by appending them to the bottom of the list * @param GridField $gridField Grid Field Reference * @param SS_List $dataList Data List of items to be checked */ protected function fixSortColumn($gridField, SS_List $dataList) { if (class_exists('UnsavedRelationList') && $dataList instanceof UnsavedRelationList) { return; } $list = clone $dataList; $list = $list->alterDataQuery(function ($query, SS_List $tmplist) { $query->limit(array()); return $query; }); $many_many = $list instanceof ManyManyList; if (!$many_many) { $sng = singleton($gridField->getModelClass()); $fieldType = $sng->db($this->sortColumn); if (!$fieldType || !($fieldType == 'Int' || is_subclass_of('Int', $fieldType))) { if (is_array($fieldType)) { user_error('Sort column ' . $this->sortColumn . ' could not be found in ' . $gridField->getModelClass() . '\'s ancestry', E_USER_ERROR); } else { user_error('Sort column ' . $this->sortColumn . ' must be an Int, column is of type ' . $fieldType, E_USER_ERROR); } exit; } } $max = $list->Max($this->sortColumn); $list = $list->filter($this->sortColumn, 0)->sort("Created,ID"); if ($list->Count() > 0) { $owner = $gridField->Form->getRecord(); $sortColumn = $this->sortColumn; $i = 1; if ($many_many) { list($parentClass, $componentClass, $parentField, $componentField, $table) = $owner->many_many($gridField->getName()); $extraFields = $owner->many_many_extraFields($gridField->getName()); if (!$extraFields || !array_key_exists($this->sortColumn, $extraFields) || !($extraFields[$this->sortColumn] == 'Int' || is_subclass_of('Int', $extraFields[$this->sortColumn]))) { user_error('Sort column ' . $this->sortColumn . ' must be an Int, column is of type ' . $extraFields[$this->sortColumn], E_USER_ERROR); exit; } } else { //Find table containing the sort column $table = false; $class = $gridField->getModelClass(); $db = Config::inst()->get($class, "db", CONFIG::UNINHERITED); if (!empty($db) && array_key_exists($sortColumn, $db)) { $table = $class; } else { $classes = ClassInfo::ancestry($class, true); foreach ($classes as $class) { $db = Config::inst()->get($class, "db", CONFIG::UNINHERITED); if (!empty($db) && array_key_exists($sortColumn, $db)) { $table = $class; break; } } } if ($table === false) { user_error('Sort column ' . $this->sortColumn . ' could not be found in ' . $gridField->getModelClass() . '\'s ancestry', E_USER_ERROR); exit; } $baseDataClass = ClassInfo::baseDataClass($gridField->getModelClass()); } //Start transaction if supported if (DB::getConn()->supportsTransactions()) { DB::getConn()->transactionStart(); } $idCondition = null; if ($this->append_to_top && !$list instanceof RelationList) { $idCondition = '"ID" IN(\'' . implode("','", $dataList->getIDList()) . '\')'; } if ($this->append_to_top) { $topIncremented = array(); } foreach ($list as $obj) { if ($many_many) { if ($this->append_to_top) { //Upgrade all the records (including the last inserted from 0 to 1) DB::query('UPDATE "' . $table . '" SET "' . $sortColumn . '" = "' . $sortColumn . '"+1' . ' WHERE "' . $parentField . '" = ' . $owner->ID . (!empty($topIncremented) ? ' AND "' . $componentField . '" NOT IN(\'' . implode('\',\'', $topIncremented) . '\')' : '')); $topIncremented[] = $obj->ID; } else { //Append the last record to the bottom DB::query('UPDATE "' . $table . '" SET "' . $sortColumn . '" = ' . ($max + $i) . ' WHERE "' . $componentField . '" = ' . $obj->ID . ' AND "' . $parentField . '" = ' . $owner->ID); } } else { if ($this->append_to_top) { //Upgrade all the records (including the last inserted from 0 to 1) DB::query('UPDATE "' . $table . '" SET "' . $sortColumn . '" = "' . $sortColumn . '"+1' . ' WHERE ' . ($list instanceof RelationList ? '"' . $list->foreignKey . '" = ' . $owner->ID : $idCondition) . (!empty($topIncremented) ? ' AND "ID" NOT IN(\'' . implode('\',\'', $topIncremented) . '\')' : '')); //LastEdited DB::query('UPDATE "' . $baseDataClass . '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\'' . ' WHERE ' . ($list instanceof RelationList ? '"' . $list->foreignKey . '" = ' . $owner->ID : $idCondition) . (!empty($topIncremented) ? ' AND "ID" NOT IN(\'' . implode('\',\'', $topIncremented) . '\')' : '')); $topIncremented[] = $obj->ID; } else { //Append the last record to the bottom DB::query('UPDATE "' . $table . '" SET "' . $sortColumn . '" = ' . ($max + $i) . ' WHERE "ID" = ' . $obj->ID); //LastEdited DB::query('UPDATE "' . $baseDataClass . '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\'' . ' WHERE "ID" = ' . $obj->ID); } } $i++; } //End transaction if supported if (DB::getConn()->supportsTransactions()) { DB::getConn()->transactionEnd(); } } }
/** * This method returns a copy of this list that does not contain any DataObjects that exists in $list * * The $list passed needs to contain the same dataclass as $this * * @param SS_List $list * @return DataList * @throws BadMethodCallException */ public function subtract(SS_List $list) { if ($this->dataclass() != $list->dataclass()) { throw new InvalidArgumentException('The list passed must have the same dataclass as this class'); } return $this->alterDataQuery(function ($query) use($list) { $query->subtract($list->dataQuery()); }); }
/** * This method returns a list does not contain any DataObjects that exists in $list * * It does not return the resulting list, it only adds the constraints on the database to exclude * objects from $list. * The $list passed needs to contain the same dataclass as $this * * @param SS_List $list * @return DataList * @throws BadMethodCallException */ public function subtract(SS_List $list) { if ($this->dataclass() != $list->dataclass()) { throw new InvalidArgumentException('The list passed must have the same dataclass as this class'); } $newlist = clone $this; $newlist->dataQuery->subtract($list->dataQuery()); return $newlist; }
/** * Gets list of safe template variables and their values which can be used * in both the static and editable templates. * * {@see ContentReviewAdminHelp.ss} * * @param Member $recipient * @param SiteConfig $config * @param SS_List $pages * @param string $type * * @return array */ protected function getTemplateVariables($recipient = null, $config, $pages) { if ($recipient != null) { return array('Subject' => $config->ReviewSubject, 'PagesCount' => $pages->count(), 'FromEmail' => $config->ReviewFrom, 'ToFirstName' => $recipient->FirstName, 'ToSurname' => $recipient->Surname, 'ToEmail' => $recipient->Email); } else { return array('Subject' => $config->ReviewSubjectReminder, 'FirstReminderPagesCount' => $pages->count(), 'SecondReminderPagesCount' => $pages->count(), 'FromEmail' => $config->ReviewFrom, 'ToEmail' => $config->ReviewReminderEmail); } }
/** * If an object ID is set, add the object to the list * * @param GridField $gridField * @param SS_List $dataList * @return SS_List */ public function getManipulatedData(GridField $gridField, SS_List $dataList) { $objectID = $gridField->State->GridFieldAddRelation(null); if (empty($objectID)) { return $dataList; } $object = DataObject::get_by_id($dataList->dataclass(), $objectID); if ($object) { $dataList->add($object); } $gridField->State->GridFieldAddRelation = null; return $dataList; }
function Field($properties = array()) { Requirements::css(FRAMEWORK_DIR . '/css/CheckboxSetField.css'); Requirements::javascript(FRAMEWORK_DIR . '/javascript/PermissionCheckboxSetField.js'); $uninheritedCodes = array(); $inheritedCodes = array(); $records = ($this->records) ? $this->records : new ArrayList(); // Get existing values from the form record (assuming the formfield name is a join field on the record) if(is_object($this->form)) { $record = $this->form->getRecord(); if( $record && (is_a($record, 'Group') || is_a($record, 'PermissionRole')) && !$records->find('ID', $record->ID) ) { $records->push($record); } } // Get all 'inherited' codes not directly assigned to the group (which is stored in $values) foreach($records as $record) { // Get all uninherited permissions $relationMethod = $this->name; foreach($record->$relationMethod() as $permission) { if(!isset($uninheritedCodes[$permission->Code])) $uninheritedCodes[$permission->Code] = array(); $uninheritedCodes[$permission->Code][] = sprintf( _t('PermissionCheckboxSetField.AssignedTo', 'assigned to "%s"'), $record->Title ); } // Special case for Group records (not PermissionRole): // Determine inherited assignments if(is_a($record, 'Group')) { // Get all permissions from roles if ($record->Roles()->Count()) { foreach($record->Roles() as $role) { foreach($role->Codes() as $code) { if (!isset($inheritedCodes[$code->Code])) $inheritedCodes[$code->Code] = array(); $inheritedCodes[$code->Code][] = sprintf( _t( 'PermissionCheckboxSetField.FromRole', 'inherited from role "%s"', 'A permission inherited from a certain permission role' ), $role->Title ); } } } // Get from parent groups $parentGroups = $record->getAncestors(); if ($parentGroups) { foreach ($parentGroups as $parent) { if (!$parent->Roles()->Count()) continue; foreach($parent->Roles() as $role) { if ($role->Codes()) { foreach($role->Codes() as $code) { if (!isset($inheritedCodes[$code->Code])) $inheritedCodes[$code->Code] = array(); $inheritedCodes[$code->Code][] = sprintf( _t( 'PermissionCheckboxSetField.FromRoleOnGroup', 'inherited from role "%s" on group "%s"', 'A permission inherited from a role on a certain group' ), $role->Title, $parent->Title ); } } } if ($parent->Permissions()->Count()) { foreach($parent->Permissions() as $permission) { if (!isset($inheritedCodes[$permission->Code])) $inheritedCodes[$permission->Code] = array(); $inheritedCodes[$permission->Code][] = sprintf( _t( 'PermissionCheckboxSetField.FromGroup', 'inherited from group "%s"', 'A permission inherited from a certain group' ), $parent->Title ); } } } } } } $odd = 0; $options = ''; if($this->source) { // loop through all available categorized permissions and see if they're assigned for the given groups foreach($this->source as $categoryName => $permissions) { $options .= "<li><h5>$categoryName</h5></li>"; foreach($permissions as $code => $permission) { if(in_array($code, $this->hiddenPermissions)) continue; if(in_array($code, Permission::$hidden_permissions)) continue; $value = $permission['name']; $odd = ($odd + 1) % 2; $extraClass = $odd ? 'odd' : 'even'; $extraClass .= ' val' . str_replace(' ', '', $code); $itemID = $this->id() . '_' . preg_replace('/[^a-zA-Z0-9]+/', '', $code); $checked = $disabled = $inheritMessage = ''; $checked = (isset($uninheritedCodes[$code]) || isset($inheritedCodes[$code])) ? ' checked="checked"' : ''; $title = $permission['help'] ? 'title="' . htmlentities($permission['help'], ENT_COMPAT, 'UTF-8') . '" ' : ''; if (isset($inheritedCodes[$code])) { // disable inherited codes, as any saving logic would be too complicate to express in this interface $disabled = ' disabled="true"'; $inheritMessage = ' (' . join(', ', $inheritedCodes[$code]) . ')'; } elseif($this->records && $this->records->Count() > 1 && isset($uninheritedCodes[$code])) { // If code assignments are collected from more than one "source group", // show its origin automatically $inheritMessage = ' (' . join(', ', $uninheritedCodes[$code]).')'; } // If the field is readonly, always mark as "disabled" if($this->readonly) $disabled = ' disabled="true"'; $inheritMessage = '<small>' . $inheritMessage . '</small>'; $options .= "<li class=\"$extraClass\">" . "<input id=\"$itemID\"$disabled name=\"$this->name[$code]\" type=\"checkbox\" value=\"$code\"$checked class=\"checkbox\" />" . "<label {$title}for=\"$itemID\">$value$inheritMessage</label>" . "</li>\n"; } } } return "<ul id=\"{$this->id()}\" class=\"optionset checkboxsetfield{$this->extraClass()}\">\n$options</ul>\n"; }
public function getManipulatedData(GridField $grid, SS_List $list) { $state = $grid->getState(); $sorted = (bool) (string) $state->GridFieldSortableHeader->SortColumn; // If the data has not been sorted by the user, then sort it by the // sort column, otherwise disable reordering. $state->VersionedGridFieldOrderableRows->enabled = !$sorted; if (!$sorted) { return $list->sort($this->getSortField()); } else { return $list; } }
/** * turns full list into paginated list * @param SS_List * @return PaginatedList */ protected function paginateList(SS_List $list) { if ($list && $list->count()) { if ($this->IsShowFullList()) { $obj = PaginatedList::create($list, $this->request); $obj->setPageLength(EcommerceConfig::get("ProductGroup", "maximum_number_of_products_to_list") + 1); return $obj; } else { $obj = PaginatedList::create($list, $this->request); $obj->setPageLength($this->MyNumberOfProductsPerPage()); return $obj; } } }
/** * This is super-slow. I'm assuming if you're using facets you * probably also ought to be using Solr or something else. Or * maybe you have unlimited time and can refactor this feature * and submit a pull request... * * TODO: If this is going to be used for categories we're going * to have to really clean it up and speed it up. * Suggestion: * - option to turn off counts * - switch order of nested array so we don't go through results unless needed * - if not doing counts, min/max and link facets can be handled w/ queries * - separate that bit out into a new function * NOTE: This is partially done with the "faster_faceting" config * option but more could be done, particularly by covering link facets as well. * * Output - list of ArrayData in the format: * Label - name of the facet * Source - field name of the facet * Type - one of the ShopSearch::FACET_TYPE_XXXX constants * Values - SS_List of possible values for this facet * * @param SS_List $matches * @param array $facetSpec * @param bool $autoFacetAttributes [optional] * @return ArrayList */ public function buildFacets(SS_List $matches, array $facetSpec, $autoFacetAttributes = false) { $facets = $this->expandFacetSpec($facetSpec); if (!$autoFacetAttributes && (empty($facets) || !$matches || !$matches->count())) { return new ArrayList(); } $fasterMethod = (bool) $this->config()->faster_faceting; // fill them in foreach ($facets as $field => &$facet) { if (preg_match(self::config()->attribute_facet_regex, $field, $m)) { $this->buildAttributeFacet($matches, $facet, $m[1]); continue; } // NOTE: using this method range and checkbox facets don't get counts if ($fasterMethod && $facet['Type'] != ShopSearch::FACET_TYPE_LINK) { if ($facet['Type'] == ShopSearch::FACET_TYPE_RANGE) { if (isset($facet['RangeMin'])) { $facet['MinValue'] = $facet['RangeMin']; } if (isset($facet['RangeMax'])) { $facet['MaxValue'] = $facet['RangeMax']; } } continue; } foreach ($matches as $rec) { // If it's a range facet, set up the min/max if ($facet['Type'] == ShopSearch::FACET_TYPE_RANGE) { if (isset($facet['RangeMin'])) { $facet['MinValue'] = $facet['RangeMin']; } if (isset($facet['RangeMax'])) { $facet['MaxValue'] = $facet['RangeMax']; } } // If the field is accessible via normal methods, including // a user-defined getter, prefer that $fieldValue = $rec->relObject($field); if (is_null($fieldValue) && $rec->hasMethod($meth = "get{$field}")) { $fieldValue = $rec->{$meth}(); } // If not, look for a VFI field if (!$fieldValue && $rec->hasExtension('VirtualFieldIndex')) { $fieldValue = $rec->getVFI($field); } // If we found something, process it if (!empty($fieldValue)) { // normalize so that it's iterable if (!is_array($fieldValue) && !$fieldValue instanceof SS_List) { $fieldValue = array($fieldValue); } foreach ($fieldValue as $obj) { if (empty($obj)) { continue; } // figure out the right label if (is_object($obj) && $obj->hasMethod('Nice')) { $lbl = $obj->Nice(); } elseif (is_object($obj) && !empty($obj->Title)) { $lbl = $obj->Title; } elseif (is_numeric($obj) && !empty($facet['LabelFormat']) && $facet['LabelFormat'] === 'Currency' && $facet['Type'] !== ShopSearch::FACET_TYPE_RANGE) { $tmp = Currency::create($field); $tmp->setValue($obj); $lbl = $tmp->Nice(); } else { $lbl = (string) $obj; } // figure out the value for sorting if (is_object($obj) && $obj->hasMethod('getAmount')) { $val = $obj->getAmount(); } elseif (is_object($obj) && !empty($obj->ID)) { $val = $obj->ID; } else { $val = (string) $obj; } // if it's a range facet, calculate the min and max if ($facet['Type'] == ShopSearch::FACET_TYPE_RANGE) { if (!isset($facet['MinValue']) || $val < $facet['MinValue']) { $facet['MinValue'] = $val; $facet['MinLabel'] = $lbl; } if (!isset($facet['RangeMin']) || $val < $facet['RangeMin']) { $facet['RangeMin'] = $val; } if (!isset($facet['MaxValue']) || $val > $facet['MaxValue']) { $facet['MaxValue'] = $val; $facet['MaxLabel'] = $lbl; } if (!isset($facet['RangeMax']) || $val > $facet['RangeMax']) { $facet['RangeMax'] = $val; } } // Tally the value in the facets if (!isset($facet['Values'][$val])) { $facet['Values'][$val] = new ArrayData(array('Label' => $lbl, 'Value' => $val, 'Count' => 1)); } elseif ($facet['Values'][$val]) { $facet['Values'][$val]->Count++; } } } } } // if we're auto-building the facets based on attributes, if ($autoFacetAttributes) { $facets = array_merge($this->buildAllAttributeFacets($matches), $facets); } // convert values to arraylist $out = new ArrayList(); $sortValues = self::config()->sort_facet_values; foreach ($facets as $f) { if ($sortValues) { ksort($f['Values']); } $f['Values'] = new ArrayList($f['Values']); $out->push(new ArrayData($f)); } return $out; }
/** * Remove pages with empty attributes * * @param SS_List $list * @param string $type * @return SS_List */ private function removeEmptyAttributes(SS_List $list, $type) { $pageAttributes = $list->map('ID', $type)->toArray(); $emptyAttributess = array_map(function ($value) { return $value == ''; }, $pageAttributes); if (!count($emptyAttributess)) { return $list; } return $list->filter(array('ID:not' => array_keys(array_filter($emptyAttributess, function ($value) { return $value == 1; })))); }
public function debug() { return $this->list->debug(); }