public function testShowEditLinksWithAdminPermission()
 {
     $this->logInWithPermission('ADMIN');
     $content = new CSSContentParser($this->gridField->FieldHolder());
     $editLinks = $content->getBySelector('.edit-link');
     $this->assertEquals(2, count($editLinks), 'Edit links should show when logged in.');
 }
 /**
  * @covers SilverStripe\Forms\GridField\GridFieldDataColumns::getFieldFormatting
  * @covers SilverStripe\Forms\GridField\GridFieldDataColumns::setFieldFormatting
  */
 public function testFieldFormatting()
 {
     $obj = new GridField('testfield', 'testfield');
     $columns = $obj->getConfig()->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldDataColumns');
     $this->assertEquals(array(), $columns->getFieldFormatting());
     $columns->setFieldFormatting(array("myFieldName" => '<a href=\\"custom-admin/$ID\\">$ID</a>'));
     $this->assertEquals(array("myFieldName" => '<a href=\\"custom-admin/$ID\\">$ID</a>'), $columns->getFieldFormatting());
 }
 /**
  * Retrieves an instance of a GridFieldPaginator attached to the same control
  * @param GridField $gridField The parent gridfield
  * @return GridFieldPaginator The attached GridFieldPaginator, if found.
  * @throws LogicException
  */
 protected function getPaginator($gridField)
 {
     /** @var GridFieldPaginator $paginator */
     $paginator = $gridField->getConfig()->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldPaginator');
     if (!$paginator && $this->config()->get('require_paginator')) {
         throw new LogicException(get_class($this) . " relies on a GridFieldPaginator to be added " . "to the same GridField, but none are present.");
     }
     return $paginator;
 }
 /**
  * @return array
  */
 public function getAttributes()
 {
     // Store state in session, and pass ID to client side.
     $state = array('grid' => $this->getNameFromParent(), 'actionName' => $this->actionName, 'args' => $this->args);
     // Ensure $id doesn't contain only numeric characters
     $id = 'gf_' . substr(md5(serialize($state)), 0, 8);
     Session::set($id, $state);
     $actionData['StateID'] = $id;
     return array_merge(parent::getAttributes(), array('name' => 'action_gridFieldAlterAction' . '?' . http_build_query($actionData), 'data-url' => $this->gridField->Link()));
 }
 public function testThereIsNoPaginatorWhenOnlyOnePage()
 {
     // We set the itemsPerPage to an reasonably big number so as to avoid test broke from small changes
     // on the fixture YML file
     $total = $this->list->count();
     $this->gridField->getConfig()->getComponentByType("SilverStripe\\Forms\\GridField\\GridFieldPaginator")->setItemsPerPage($total);
     $fieldHolder = $this->gridField->FieldHolder();
     $content = new CSSContentParser($fieldHolder);
     // Check that there is no paginator render into the footer
     $this->assertEquals(0, count($content->getBySelector('.datagrid-pagination')));
     // Check that there is still 'View 1 - 4 of 4' part on the left of the paginator
     $this->assertEquals(2, count($content->getBySelector('.pagination-records-number')));
 }
 public function handleAction(GridField $gridField, $actionName, $arguments, $data)
 {
     if (!$this->checkDataType($gridField->getList())) {
         return;
     }
     $state = $gridField->State->GridFieldFilterHeader;
     if ($actionName === 'filter') {
         if (isset($data['filter'][$gridField->getName()])) {
             foreach ($data['filter'][$gridField->getName()] as $key => $filter) {
                 $state->Columns->{$key} = $filter;
             }
         }
     } elseif ($actionName === 'reset') {
         $state->Columns = null;
     }
 }
 /**
  * @param GridField $gridField
  * @param DataObject $record
  * @param string $columnName
  * @return string The HTML for the column
  */
 public function getColumnContent($gridField, $record, $columnName)
 {
     // No permission checks, handled through GridFieldDetailForm,
     // which can make the form readonly if no edit permissions are available.
     $data = new ArrayData(array('Link' => Controller::join_links($gridField->Link('item'), $record->ID, 'edit')));
     $template = SSViewer::get_templates_by_class($this, '', __CLASS__);
     return $data->renderWith($template);
 }
 /**
  * Test getManipulatedData on subclassed dataobjects
  */
 public function testInheritedGetManiplatedData()
 {
     $list = GridFieldSortableHeaderTest_TeamGroup::get();
     $config = new GridFieldConfig_RecordEditor();
     $gridField = new GridField('testfield', 'testfield', $list, $config);
     $state = $gridField->State->GridFieldSortableHeader;
     $compontent = $gridField->getConfig()->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldSortableHeader');
     // Test that inherited dataobjects will work correctly
     $state->SortColumn = 'Cheerleader.Hat.Colour';
     $state->SortDirection = 'asc';
     $relationListA = $compontent->getManipulatedData($gridField, $list);
     $relationListAsql = Convert::nl2os($relationListA->sql(), ' ');
     // Assert that all tables are joined properly
     $this->assertContains('FROM "GridFieldSortableHeaderTest_Team"', $relationListAsql);
     $this->assertContains('LEFT JOIN "GridFieldSortableHeaderTest_TeamGroup" ' . 'ON "GridFieldSortableHeaderTest_TeamGroup"."ID" = "GridFieldSortableHeaderTest_Team"."ID"', $relationListAsql);
     $this->assertContains('LEFT JOIN "GridFieldSortableHeaderTest_Cheerleader" ' . 'ON "GridFieldSortableHeaderTest_Cheerleader"."ID" = "GridFieldSortableHeaderTest_Team"."CheerleaderID"', $relationListAsql);
     $this->assertContains('LEFT JOIN "GridFieldSortableHeaderTest_CheerleaderHat" ' . 'ON "GridFieldSortableHeaderTest_CheerleaderHat"."ID" = "GridFieldSortableHeaderTest_Cheerleader"."HatID"', $relationListAsql);
     // Test sorting is correct
     $this->assertEquals(array('Cologne', 'Auckland', 'Wellington', 'Melbourne'), $relationListA->column('City'));
     $state->SortDirection = 'desc';
     $relationListAdesc = $compontent->getManipulatedData($gridField, $list);
     $this->assertEquals(array('Melbourne', 'Wellington', 'Auckland', 'Cologne'), $relationListAdesc->column('City'));
     // Test subclasses of tables
     $state->SortColumn = 'CheerleadersMom.Hat.Colour';
     $state->SortDirection = 'asc';
     $relationListB = $compontent->getManipulatedData($gridField, $list);
     $relationListBsql = $relationListB->sql();
     // Assert that subclasses are included in the query
     $this->assertContains('FROM "GridFieldSortableHeaderTest_Team"', $relationListBsql);
     $this->assertContains('LEFT JOIN "GridFieldSortableHeaderTest_TeamGroup" ' . 'ON "GridFieldSortableHeaderTest_TeamGroup"."ID" = "GridFieldSortableHeaderTest_Team"."ID"', $relationListBsql);
     // Joined tables are joined basetable first
     $this->assertContains('LEFT JOIN "GridFieldSortableHeaderTest_Cheerleader" ' . 'ON "GridFieldSortableHeaderTest_Cheerleader"."ID" = "GridFieldSortableHeaderTest_Team"."CheerleadersMomID"', $relationListBsql);
     // Then the basetable of the joined record is joined to the specific subtable
     $this->assertContains('LEFT JOIN "GridFieldSortableHeaderTest_Mom" ' . 'ON "GridFieldSortableHeaderTest_Cheerleader"."ID" = "GridFieldSortableHeaderTest_Mom"."ID"', $relationListBsql);
     $this->assertContains('LEFT JOIN "GridFieldSortableHeaderTest_CheerleaderHat" ' . 'ON "GridFieldSortableHeaderTest_CheerleaderHat"."ID" = "GridFieldSortableHeaderTest_Cheerleader"."HatID"', $relationListBsql);
     // Test sorting is correct
     $this->assertEquals(array('Cologne', 'Auckland', 'Wellington', 'Melbourne'), $relationListB->column('City'));
     $state->SortDirection = 'desc';
     $relationListBdesc = $compontent->getManipulatedData($gridField, $list);
     $this->assertEquals(array('Melbourne', 'Wellington', 'Auckland', 'Cologne'), $relationListBdesc->column('City'));
 }
 public function testDeleteActionRemoveRelation()
 {
     $this->logInWithPermission('ADMIN');
     $config = GridFieldConfig::create()->addComponent(new GridFieldDeleteAction(true));
     $gridField = new GridField('testfield', 'testfield', $this->list, $config);
     $form = new Form(new Controller(), 'mockform', new FieldList(array($this->gridField)), new FieldList());
     $stateID = 'testGridStateActionField';
     Session::set($stateID, array('grid' => '', 'actionName' => 'deleterecord', 'args' => array('RecordID' => $this->idFromFixture('GridFieldAction_Delete_Team', 'team1'))));
     $token = SecurityToken::inst();
     $request = new HTTPRequest('POST', 'url', array(), array('action_gridFieldAlterAction?StateID=' . $stateID => true, $token->getName() => $token->getValue()));
     $this->gridField->gridFieldAlterAction(array('StateID' => $stateID), $this->form, $request);
     $this->assertEquals(2, $this->list->count(), 'User should be able to delete records with ADMIN permission.');
 }
 /**
  * Loads the given form data into the underlying dataobject and relation
  *
  * @param array $data
  * @param Form $form
  * @throws ValidationException On error
  * @return DataObject Saved record
  */
 protected function saveFormIntoRecord($data, $form)
 {
     $list = $this->gridField->getList();
     // Check object matches the correct classname
     if (isset($data['ClassName']) && $data['ClassName'] != $this->record->ClassName) {
         $newClassName = $data['ClassName'];
         // The records originally saved attribute was overwritten by $form->saveInto($record) before.
         // This is necessary for newClassInstance() to work as expected, and trigger change detection
         // on the ClassName attribute
         $this->record->setClassName($this->record->ClassName);
         // Replace $record with a new instance
         $this->record = $this->record->newClassInstance($newClassName);
     }
     // Save form and any extra saved data into this dataobject
     $form->saveInto($this->record);
     $this->record->write();
     $extraData = $this->getExtraSavedData($this->record, $list);
     $list->add($this->record, $extraData);
     return $this->record;
 }
 /**
  *
  * @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());
 }
 /**
  * @param GridField $gridField
  * @return array
  */
 public function getHTMLFragments($gridField)
 {
     $templates = SSViewer::get_templates_by_class($this, '', __CLASS__);
     return array('header' => $gridField->renderWith($templates));
 }
 /**
  * Returns a json array of a search results that can be used by for example Jquery.ui.autosuggestion
  *
  * @param GridField $gridField
  * @param HTTPRequest $request
  * @return string
  */
 public function doSearch($gridField, $request)
 {
     $dataClass = $gridField->getModelClass();
     $allList = $this->searchList ? $this->searchList : DataList::create($dataClass);
     $searchFields = $this->getSearchFields() ? $this->getSearchFields() : $this->scaffoldSearchFields($dataClass);
     if (!$searchFields) {
         throw new LogicException(sprintf('GridFieldAddExistingAutocompleter: No searchable fields could be found for class "%s"', $dataClass));
     }
     $params = array();
     foreach ($searchFields as $searchField) {
         $name = strpos($searchField, ':') !== FALSE ? $searchField : "{$searchField}:StartsWith";
         $params[$name] = $request->getVar('gridfield_relationsearch');
     }
     $results = $allList->subtract($gridField->getList())->filterAny($params)->sort(strtok($searchFields[0], ':'), 'ASC')->limit($this->getResultsLimit());
     $json = array();
     Config::nest();
     SSViewer::config()->update('source_file_comments', false);
     $viewer = SSViewer::fromString($this->resultsFormat);
     foreach ($results as $result) {
         $title = html_entity_decode($viewer->process($result));
         $json[] = array('label' => $title, 'value' => $title, 'id' => $result->ID);
     }
     Config::unnest();
     return Convert::array2json($json);
 }
 public function handleAction(GridField $gridField, $actionName, $arguments, $data)
 {
     if (!$this->checkDataType($gridField->getList())) {
         return;
     }
     $state = $gridField->State->GridFieldSortableHeader;
     switch ($actionName) {
         case 'sortasc':
             $state->SortColumn = $arguments['SortColumn'];
             $state->SortDirection = 'asc';
             break;
         case 'sortdesc':
             $state->SortColumn = $arguments['SortColumn'];
             $state->SortDirection = 'desc';
             break;
     }
 }
 public function getEditForm($id = null, $fields = null)
 {
     $list = $this->getList();
     $exportButton = new GridFieldExportButton('buttons-before-left');
     $exportButton->setExportColumns($this->getExportFields());
     $listField = GridField::create($this->sanitiseClassName($this->modelClass), false, $list, $fieldConfig = GridFieldConfig_RecordEditor::create($this->stat('page_length'))->addComponent($exportButton)->removeComponentsByType('SilverStripe\\Forms\\GridField\\GridFieldFilterHeader')->addComponents(new GridFieldPrintButton('buttons-before-left')));
     // Validation
     if (singleton($this->modelClass)->hasMethod('getCMSValidator')) {
         $detailValidator = singleton($this->modelClass)->getCMSValidator();
         /** @var GridFieldDetailForm $detailform */
         $detailform = $listField->getConfig()->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldDetailForm');
         $detailform->setValidator($detailValidator);
     }
     $form = Form::create($this, 'EditForm', new FieldList($listField), new FieldList())->setHTMLID('Form_EditForm');
     $form->addExtraClass('cms-edit-form cms-panel-padded center flexbox-area-grow');
     $form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
     $editFormAction = Controller::join_links($this->Link($this->sanitiseClassName($this->modelClass)), 'EditForm');
     $form->setFormAction($editFormAction);
     $form->setAttribute('data-pjax-fragment', 'CurrentForm');
     $this->extend('updateEditForm', $form);
     return $form;
 }
 /**
  * Return a {@link Form} instance allowing a user to
  * add images and flash objects to the TinyMCE content editor.
  *
  * @return Form
  */
 public function MediaForm()
 {
     // TODO Handle through GridState within field - currently this state set too late to be useful here (during
     // request handling)
     $parentID = $this->getAttachParentID();
     $fileFieldConfig = GridFieldConfig::create()->addComponents(new GridFieldSortableHeader(), new GridFieldFilterHeader(), new GridFieldDataColumns(), new GridFieldPaginator(7), new GridFieldDeleteAction(), new GridFieldDetailForm());
     $fileField = GridField::create('Files', false, null, $fileFieldConfig);
     $fileField->setList($this->getFiles($parentID));
     $fileField->setAttribute('data-selectable', true);
     $fileField->setAttribute('data-multiselect', true);
     /** @var GridFieldDataColumns $columns */
     $columns = $fileField->getConfig()->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldDataColumns');
     $columns->setDisplayFields(array('StripThumbnail' => false, 'Title' => _t('File.Title'), 'Created' => File::singleton()->fieldLabel('Created')));
     $columns->setFieldCasting(array('Created' => 'DBDatetime->Nice'));
     $fromCMS = new CompositeField($select = TreeDropdownField::create('ParentID', "", 'SilverStripe\\Assets\\Folder')->addExtraClass('noborder')->setValue($parentID), $fileField);
     $fromCMS->addExtraClass('content ss-uploadfield htmleditorfield-from-cms');
     $select->addExtraClass('content-select');
     $URLDescription = _t('HTMLEditorField.URLDESCRIPTION', 'Insert videos and images from the web into your page simply by entering the URL of the file. Make sure you have the rights or permissions before sharing media directly from the web.<br /><br />Please note that files are not added to the file store of the CMS but embeds the file from its original location, if for some reason the file is no longer available in its original location it will no longer be viewable on this page.');
     $fromWeb = new CompositeField($description = new LiteralField('URLDescription', '<div class="url-description">' . $URLDescription . '</div>'), $remoteURL = new TextField('RemoteURL', 'http://'), new LiteralField('addURLImage', '<button type="button" class="action ui-action-constructive ui-button field font-icon-plus add-url">' . _t('HTMLEditorField.BUTTONADDURL', 'Add url') . '</button>'));
     $remoteURL->addExtraClass('remoteurl');
     $fromWeb->addExtraClass('content ss-uploadfield htmleditorfield-from-web');
     Requirements::css(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/AssetUploadField.css', '/'));
     $computerUploadField = UploadField::create('AssetUploadField', '');
     $computerUploadField->setConfig('previewMaxWidth', 40);
     $computerUploadField->setConfig('previewMaxHeight', 30);
     $computerUploadField->addExtraClass('toolbar toolbar--content ss-assetuploadfield htmleditorfield-from-computer');
     $computerUploadField->removeExtraClass('ss-uploadfield');
     $computerUploadField->setTemplate('SilverStripe\\Forms\\HTMLEditorField_UploadField');
     $computerUploadField->setFolderName(Upload::config()->get('uploads_folder'));
     $defaultPanel = new CompositeField($computerUploadField, $fromCMS);
     $fromWebPanel = new CompositeField($fromWeb);
     $defaultPanel->addExtraClass('htmleditorfield-default-panel');
     $fromWebPanel->addExtraClass('htmleditorfield-web-panel');
     $allFields = new CompositeField($defaultPanel, $fromWebPanel, $editComposite = new CompositeField(new LiteralField('contentEdit', '<div class="content-edit ss-uploadfield-files files"></div>')));
     $allFields->addExtraClass('ss-insert-media');
     $headings = new CompositeField(new LiteralField('Heading', sprintf('<h3 class="htmleditorfield-mediaform-heading insert">%s</h3>', _t('HTMLEditorField.INSERTMEDIA', 'Insert media from')) . sprintf('<h3 class="htmleditorfield-mediaform-heading update">%s</h3>', _t('HTMLEditorField.UpdateMEDIA', 'Update media'))));
     $headings->addExtraClass('cms-content-header');
     $editComposite->addExtraClass('ss-assetuploadfield');
     $fields = new FieldList($headings, $allFields);
     $form = new Form($this->controller, "{$this->name}/MediaForm", $fields, new FieldList());
     $form->unsetValidator();
     $form->disableSecurityToken();
     $form->loadDataFrom($this);
     $form->addExtraClass('htmleditorfield-form htmleditorfield-mediaform cms-dialog-content');
     // Allow other people to extend the fields being added to the imageform
     $this->extend('updateMediaForm', $form);
     return $form;
 }
 /**
  * @return DataList
  */
 public function getList()
 {
     return $this->grid->getList();
 }
 /**
  * Caution: Only call on instances, not through a singleton.
  * The "root group" fields will be created through {@link SecurityAdmin->EditForm()}.
  *
  * @return FieldList
  */
 public function getCMSFields()
 {
     $fields = new FieldList(new TabSet("Root", new Tab('Members', _t('SecurityAdmin.MEMBERS', 'Members'), new TextField("Title", $this->fieldLabel('Title')), $parentidfield = DropdownField::create('ParentID', $this->fieldLabel('Parent'), Group::get()->exclude('ID', $this->ID)->map('ID', 'Breadcrumbs'))->setEmptyString(' '), new TextareaField('Description', $this->fieldLabel('Description'))), $permissionsTab = new Tab('Permissions', _t('SecurityAdmin.PERMISSIONS', 'Permissions'), $permissionsField = new PermissionCheckboxSetField('Permissions', false, 'SilverStripe\\Security\\Permission', 'GroupID', $this))));
     $parentidfield->setDescription(_t('Group.GroupReminder', 'If you choose a parent group, this group will take all it\'s roles'));
     // Filter permissions
     // TODO SecurityAdmin coupling, not easy to get to the form fields through GridFieldDetailForm
     $permissionsField->setHiddenPermissions((array) Config::inst()->get('SilverStripe\\Admin\\SecurityAdmin', 'hidden_permissions'));
     if ($this->ID) {
         $group = $this;
         $config = GridFieldConfig_RelationEditor::create();
         $config->addComponent(new GridFieldButtonRow('after'));
         $config->addComponents(new GridFieldExportButton('buttons-after-left'));
         $config->addComponents(new GridFieldPrintButton('buttons-after-left'));
         /** @var GridFieldAddExistingAutocompleter $autocompleter */
         $autocompleter = $config->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldAddExistingAutocompleter');
         /** @skipUpgrade */
         $autocompleter->setResultsFormat('$Title ($Email)')->setSearchFields(array('FirstName', 'Surname', 'Email'));
         /** @var GridFieldDetailForm $detailForm */
         $detailForm = $config->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldDetailForm');
         $detailForm->setValidator(Member_Validator::create())->setItemEditFormCallback(function ($form, $component) use($group) {
             /** @var Form $form */
             $record = $form->getRecord();
             $groupsField = $form->Fields()->dataFieldByName('DirectGroups');
             if ($groupsField) {
                 // If new records are created in a group context,
                 // set this group by default.
                 if ($record && !$record->ID) {
                     $groupsField->setValue($group->ID);
                 } elseif ($record && $record->ID) {
                     // TODO Mark disabled once chosen.js supports it
                     // $groupsField->setDisabledItems(array($group->ID));
                     $form->Fields()->replaceField('DirectGroups', $groupsField->performReadonlyTransformation());
                 }
             }
         });
         $memberList = GridField::create('Members', false, $this->DirectMembers(), $config)->addExtraClass('members_grid');
         // @todo Implement permission checking on GridField
         //$memberList->setPermissions(array('edit', 'delete', 'export', 'add', 'inlineadd'));
         $fields->addFieldToTab('Root.Members', $memberList);
     }
     // Only add a dropdown for HTML editor configurations if more than one is available.
     // Otherwise Member->getHtmlEditorConfigForCMS() will default to the 'cms' configuration.
     $editorConfigMap = HTMLEditorConfig::get_available_configs_map();
     if (count($editorConfigMap) > 1) {
         $fields->addFieldToTab('Root.Permissions', new DropdownField('HtmlEditorConfig', 'HTML Editor Configuration', $editorConfigMap), 'Permissions');
     }
     if (!Permission::check('EDIT_PERMISSIONS')) {
         $fields->removeFieldFromTab('Root', 'Permissions');
     }
     // Only show the "Roles" tab if permissions are granted to edit them,
     // and at least one role exists
     if (Permission::check('APPLY_ROLES') && DataObject::get('SilverStripe\\Security\\PermissionRole')) {
         $fields->findOrMakeTab('Root.Roles', _t('SecurityAdmin.ROLES', 'Roles'));
         $fields->addFieldToTab('Root.Roles', new LiteralField("", "<p>" . _t('SecurityAdmin.ROLESDESCRIPTION', "Roles are predefined sets of permissions, and can be assigned to groups.<br />" . "They are inherited from parent groups if required.") . '<br />' . sprintf('<a href="%s" class="add-role">%s</a>', SecurityAdmin::singleton()->Link('show/root#Root_Roles'), _t('Group.RolesAddEditLink', 'Manage roles')) . "</p>"));
         // Add roles (and disable all checkboxes for inherited roles)
         $allRoles = PermissionRole::get();
         if (!Permission::check('ADMIN')) {
             $allRoles = $allRoles->filter("OnlyAdminCanApply", 0);
         }
         if ($this->ID) {
             $groupRoles = $this->Roles();
             $inheritedRoles = new ArrayList();
             $ancestors = $this->getAncestors();
             foreach ($ancestors as $ancestor) {
                 $ancestorRoles = $ancestor->Roles();
                 if ($ancestorRoles) {
                     $inheritedRoles->merge($ancestorRoles);
                 }
             }
             $groupRoleIDs = $groupRoles->column('ID') + $inheritedRoles->column('ID');
             $inheritedRoleIDs = $inheritedRoles->column('ID');
         } else {
             $groupRoleIDs = array();
             $inheritedRoleIDs = array();
         }
         $rolesField = ListboxField::create('Roles', false, $allRoles->map()->toArray())->setDefaultItems($groupRoleIDs)->setAttribute('data-placeholder', _t('Group.AddRole', 'Add a role for this group'))->setDisabledItems($inheritedRoleIDs);
         if (!$allRoles->count()) {
             $rolesField->setAttribute('data-placeholder', _t('Group.NoRoles', 'No roles found'));
         }
         $fields->addFieldToTab('Root.Roles', $rolesField);
     }
     $fields->push($idField = new HiddenField("ID"));
     $this->extend('updateCMSFields', $fields);
     return $fields;
 }
 public function Form()
 {
     // GridField lists categories for a specific person
     $person = GridFieldDetailFormTest_Person::get()->sort('FirstName')->First();
     $detailFields = singleton('GridFieldDetailFormTest_Category')->getCMSFields();
     $detailFields->addFieldsToTab('Root.Main', array(new CheckboxField('ManyMany[IsPublished]'), new TextField('ManyMany[PublishedBy]')));
     $categoriesField = new GridField('testfield', 'testfield', $person->Categories());
     $categoriesField->getConfig()->addComponent($gridFieldForm = new GridFieldDetailForm($this, 'SilverStripe\\Forms\\Form'));
     $gridFieldForm->setFields($detailFields);
     $categoriesField->getConfig()->addComponent(new GridFieldToolbarHeader());
     $categoriesField->getConfig()->addComponent(new GridFieldAddNewButton('toolbar-header-right'));
     $categoriesField->getConfig()->addComponent(new GridFieldEditButton());
     $favGroupsField = new GridField('testgroupsfield', 'testgroupsfield', $person->FavouriteGroups());
     /** @skipUpgrade */
     $favGroupsField->getConfig()->addComponent(new GridFieldDetailForm($this, 'Form'));
     $favGroupsField->getConfig()->addComponent(new GridFieldToolbarHeader());
     $favGroupsField->getConfig()->addComponent(new GridFieldAddNewButton('toolbar-header-right'));
     $favGroupsField->getConfig()->addComponent(new GridFieldEditButton());
     $fields = new FieldList($categoriesField, $favGroupsField);
     /** @skipUpgrade */
     return new Form($this, 'Form', $fields, new FieldList());
 }
 public function getEditForm($id = null, $fields = null)
 {
     // TODO Duplicate record fetching (see parent implementation)
     if (!$id) {
         $id = $this->currentPageID();
     }
     $form = parent::getEditForm($id);
     // TODO Duplicate record fetching (see parent implementation)
     $record = $this->getRecord($id);
     if ($record && !$record->canView()) {
         return Security::permissionFailure($this);
     }
     $memberList = GridField::create('Members', false, Member::get(), $memberListConfig = GridFieldConfig_RecordEditor::create()->addComponent(new GridFieldButtonRow('after'))->addComponent(new GridFieldExportButton('buttons-after-left')))->addExtraClass("members_grid");
     if ($record && method_exists($record, 'getValidator')) {
         $validator = $record->getValidator();
     } else {
         $validator = Member::singleton()->getValidator();
     }
     /** @var GridFieldDetailForm $detailForm */
     $detailForm = $memberListConfig->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldDetailForm');
     $detailForm->setValidator($validator);
     $groupList = GridField::create('Groups', false, Group::get(), GridFieldConfig_RecordEditor::create());
     /** @var GridFieldDataColumns $columns */
     $columns = $groupList->getConfig()->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldDataColumns');
     $columns->setDisplayFields(array('Breadcrumbs' => Group::singleton()->fieldLabel('Title')));
     $columns->setFieldFormatting(array('Breadcrumbs' => function ($val, $item) {
         /** @var Group $item */
         return Convert::raw2xml($item->getBreadcrumbs(' > '));
     }));
     $fields = new FieldList($root = new TabSet('Root', $usersTab = new Tab('Users', _t('SecurityAdmin.Users', 'Users'), new LiteralField('MembersCautionText', sprintf('<div class="alert alert-warning" role="alert">%s</div>', _t('SecurityAdmin.MemberListCaution', 'Caution: Removing members from this list will remove them from all groups and the database'))), $memberList), $groupsTab = new Tab('Groups', singleton('SilverStripe\\Security\\Group')->i18n_plural_name(), $groupList)), new HiddenField('ID', false, 0));
     // Add import capabilities. Limit to admin since the import logic can affect assigned permissions
     if (Permission::check('ADMIN')) {
         $fields->addFieldsToTab('Root.Users', array(new HeaderField('ImportUsersHeader', _t('SecurityAdmin.IMPORTUSERS', 'Import users'), 3), new LiteralField('MemberImportFormIframe', sprintf('<iframe src="%s" id="MemberImportFormIframe" width="100%%" height="330px" frameBorder="0">' . '</iframe>', $this->Link('memberimport')))));
         $fields->addFieldsToTab('Root.Groups', array(new HeaderField('ImportGroupsHeader', _t('SecurityAdmin.IMPORTGROUPS', 'Import groups'), 3), new LiteralField('GroupImportFormIframe', sprintf('<iframe src="%s" id="GroupImportFormIframe" width="100%%" height="330px" frameBorder="0">' . '</iframe>', $this->Link('groupimport')))));
     }
     // Tab nav in CMS is rendered through separate template
     $root->setTemplate('SilverStripe\\Forms\\CMSTabSet');
     // Add roles editing interface
     $rolesTab = null;
     if (Permission::check('APPLY_ROLES')) {
         $rolesField = GridField::create('Roles', false, PermissionRole::get(), GridFieldConfig_RecordEditor::create());
         $rolesTab = $fields->findOrMakeTab('Root.Roles', _t('SecurityAdmin.TABROLES', 'Roles'));
         $rolesTab->push($rolesField);
     }
     $actionParam = $this->getRequest()->param('Action');
     if ($actionParam == 'groups') {
         $groupsTab->addExtraClass('ui-state-active');
     } elseif ($actionParam == 'users') {
         $usersTab->addExtraClass('ui-state-active');
     } elseif ($actionParam == 'roles' && $rolesTab) {
         $rolesTab->addExtraClass('ui-state-active');
     }
     $actions = new FieldList();
     $form = Form::create($this, 'EditForm', $fields, $actions)->setHTMLID('Form_EditForm');
     $form->addExtraClass('cms-edit-form fill-height');
     $form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
     // Tab nav in CMS is rendered through separate template
     if ($form->Fields()->hasTabSet()) {
         $form->Fields()->findOrMakeTab('Root')->setTemplate('SilverStripe\\Forms\\CMSTabSet');
     }
     $form->addExtraClass('ss-tabset cms-tabset ' . $this->BaseCSSClasses());
     $form->setAttribute('data-pjax-fragment', 'CurrentForm');
     $this->extend('updateEditForm', $form);
     return $form;
 }
 /**
  * Casts a field to a string which is safe to insert into HTML
  *
  * @param GridField $gridField
  * @param string $fieldName
  * @param string $value
  * @return string
  */
 protected function castValue($gridField, $fieldName, $value)
 {
     // If a fieldCasting is specified, we assume the result is safe
     if (array_key_exists($fieldName, $this->fieldCasting)) {
         $value = $gridField->getCastedValue($value, $this->fieldCasting[$fieldName]);
     } else {
         if (is_object($value)) {
             // If the value is an object, we do one of two things
             if (method_exists($value, 'Nice')) {
                 // If it has a "Nice" method, call that & make sure the result is safe
                 $value = Convert::raw2xml($value->Nice());
             } else {
                 // Otherwise call forTemplate - the result of this should already be safe
                 $value = $value->forTemplate();
             }
         } else {
             // Otherwise, just treat as a text string & make sure the result is safe
             $value = Convert::raw2xml($value);
         }
     }
     return $value;
 }
 /**
  * @param int $folderID The ID of the folder to display.
  * @return FormField
  */
 protected function getListField($folderID)
 {
     // Generate the folder selection field.
     /** @skipUpgrade */
     $folderField = new TreeDropdownField('ParentID', _t('HTMLEditorField.FOLDER', 'Folder'), 'SilverStripe\\Assets\\Folder');
     $folderField->setValue($folderID);
     // Generate the file list field.
     $config = GridFieldConfig::create();
     $config->addComponent(new GridFieldSortableHeader());
     $config->addComponent(new GridFieldFilterHeader());
     $config->addComponent($colsComponent = new GridFieldDataColumns());
     $colsComponent->setDisplayFields(array('StripThumbnail' => '', 'Title' => File::singleton()->fieldLabel('Title'), 'Created' => File::singleton()->fieldLabel('Created'), 'Size' => File::singleton()->fieldLabel('Size')));
     $colsComponent->setFieldCasting(array('Created' => 'DBDatetime->Nice'));
     // Set configurable pagination for file list field
     $pageSize = Config::inst()->get(get_class($this), 'page_size');
     $config->addComponent(new GridFieldPaginator($pageSize));
     // If relation is to be autoset, we need to make sure we only list compatible objects.
     $baseClass = $this->parent->getRelationAutosetClass();
     // Create the data source for the list of files within the current directory.
     $files = DataList::create($baseClass)->exclude('ClassName', 'SilverStripe\\Assets\\Folder');
     if ($folderID) {
         $files = $files->filter('ParentID', $folderID);
     }
     $fileField = new GridField('Files', false, $files, $config);
     $fileField->setAttribute('data-selectable', true);
     if ($this->parent->getAllowedMaxFileNumber() !== 1) {
         $fileField->setAttribute('data-multiselect', true);
     }
     $selectComposite = new CompositeField($folderField, $fileField);
     return $selectComposite;
 }
 /**
  * Determines arguments to be passed to the template for building this field
  *
  * @param GridField $gridField
  * @return ArrayData If paging is available this will be an ArrayData
  * object of paging details with these parameters:
  * <ul>
  *	<li>OnlyOnePage:				boolean - Is there only one page?</li>
  *  <li>FirstShownRecord:			integer - Number of the first record displayed</li>
  *  <li>LastShownRecord:			integer - Number of the last record displayed</li>
  *  <li>NumRecords:					integer - Total number of records</li>
  *	<li>NumPages:					integer - The number of pages</li>
  *	<li>CurrentPageNum (optional):	integer - If OnlyOnePage is false, the number of the current page</li>
  *  <li>FirstPage (optional):		GridField_FormAction - Button to go to the first page</li>
  *	<li>PreviousPage (optional):	GridField_FormAction - Button to go to the previous page</li>
  *	<li>NextPage (optional):		GridField_FormAction - Button to go to the next page</li>
  *	<li>LastPage (optional):		GridField_FormAction - Button to go to last page</li>
  * </ul>
  */
 public function getTemplateParameters(GridField $gridField)
 {
     if (!$this->checkDataType($gridField->getList())) {
         return null;
     }
     $state = $this->getGridPagerState($gridField);
     // Figure out which page and record range we're on
     $totalRows = $this->totalItems;
     if (!$totalRows) {
         return null;
     }
     $totalPages = (int) ceil($totalRows / $this->itemsPerPage);
     if ($totalPages == 0) {
         $totalPages = 1;
     }
     $firstShownRecord = ($state->currentPage - 1) * $this->itemsPerPage + 1;
     if ($firstShownRecord > $totalRows) {
         $firstShownRecord = $totalRows;
     }
     $lastShownRecord = $state->currentPage * $this->itemsPerPage;
     if ($lastShownRecord > $totalRows) {
         $lastShownRecord = $totalRows;
     }
     // If there is only 1 page for all the records in list, we don't need to go further
     // to sort out those first page, last page, pre and next pages, etc
     // we are not render those in to the paginator.
     if ($totalPages === 1) {
         return new ArrayData(array('OnlyOnePage' => true, 'FirstShownRecord' => $firstShownRecord, 'LastShownRecord' => $lastShownRecord, 'NumRecords' => $totalRows, 'NumPages' => $totalPages));
     } else {
         // First page button
         $firstPage = new GridField_FormAction($gridField, 'pagination_first', 'First', 'paginate', 1);
         $firstPage->addExtraClass('btn btn-secondary btn--no-text font-icon-angle-double-left ss-gridfield-firstpage');
         if ($state->currentPage == 1) {
             $firstPage = $firstPage->performDisabledTransformation();
         }
         // Previous page button
         $previousPageNum = $state->currentPage <= 1 ? 1 : $state->currentPage - 1;
         $previousPage = new GridField_FormAction($gridField, 'pagination_prev', 'Previous', 'paginate', $previousPageNum);
         $previousPage->addExtraClass('btn btn-secondary btn--no-text font-icon-angle-left ss-gridfield-previouspage');
         if ($state->currentPage == 1) {
             $previousPage = $previousPage->performDisabledTransformation();
         }
         // Next page button
         $nextPageNum = $state->currentPage >= $totalPages ? $totalPages : $state->currentPage + 1;
         $nextPage = new GridField_FormAction($gridField, 'pagination_next', 'Next', 'paginate', $nextPageNum);
         $nextPage->addExtraClass('btn btn-secondary btn--no-text font-icon-angle-right ss-gridfield-nextpage');
         if ($state->currentPage == $totalPages) {
             $nextPage = $nextPage->performDisabledTransformation();
         }
         // Last page button
         $lastPage = new GridField_FormAction($gridField, 'pagination_last', 'Last', 'paginate', $totalPages);
         $lastPage->addExtraClass('btn btn-secondary btn--no-text font-icon-angle-double-right ss-gridfield-lastpage');
         if ($state->currentPage == $totalPages) {
             $lastPage = $lastPage->performDisabledTransformation();
         }
         // Render in template
         return new ArrayData(array('OnlyOnePage' => false, 'FirstPage' => $firstPage, 'PreviousPage' => $previousPage, 'CurrentPageNum' => $state->currentPage, 'NumPages' => $totalPages, 'NextPage' => $nextPage, 'LastPage' => $lastPage, 'FirstShownRecord' => $firstShownRecord, 'LastShownRecord' => $lastShownRecord, 'NumRecords' => $totalRows));
     }
 }
 /**
  * Return the columns to export
  *
  * @param GridField $gridField
  *
  * @return array
  */
 protected function getExportColumnsForGridField(GridField $gridField)
 {
     if ($this->exportColumns) {
         return $this->exportColumns;
     }
     /** @var GridFieldDataColumns $dataCols */
     $dataCols = $gridField->getConfig()->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldDataColumns');
     if ($dataCols) {
         return $dataCols->getDisplayFields($gridField);
     }
     return DataObject::singleton($gridField->getModelClass())->summaryFields();
 }
 /**
  * Return the title of the printed page
  *
  * @param GridField
  *
  * @return array
  */
 public function getTitle(GridField $gridField)
 {
     $form = $gridField->getForm();
     $currentController = $gridField->getForm()->getController();
     $title = '';
     if (method_exists($currentController, 'Title')) {
         $title = $currentController->Title();
     } else {
         if ($currentController->Title) {
             $title = $currentController->Title;
         } elseif ($form->getName()) {
             $title = $form->getName();
         }
     }
     if ($fieldTitle = $gridField->Title()) {
         if ($title) {
             $title .= " - ";
         }
         $title .= $fieldTitle;
     }
     return $title;
 }
 /**
  * Handle the actions and apply any changes to the GridField
  *
  * @param GridField $gridField
  * @param string $actionName
  * @param mixed $arguments
  * @param array $data - form data
  * @throws ValidationException
  */
 public function handleAction(GridField $gridField, $actionName, $arguments, $data)
 {
     if ($actionName == 'deleterecord' || $actionName == 'unlinkrelation') {
         /** @var DataObject $item */
         $item = $gridField->getList()->byID($arguments['RecordID']);
         if (!$item) {
             return;
         }
         if ($actionName == 'deleterecord') {
             if (!$item->canDelete()) {
                 throw new ValidationException(_t('GridFieldAction_Delete.DeletePermissionsFailure', "No delete permissions"), 0);
             }
             $item->delete();
         } else {
             if (!$item->canEdit()) {
                 throw new ValidationException(_t('GridFieldAction_Delete.EditPermissionsFailure', "No permission to unlink record"), 0);
             }
             $gridField->getList()->remove($item);
         }
     }
 }
 public function testChainedDataManipulators()
 {
     $config = new GridFieldConfig();
     $data = new ArrayList(array(1, 2, 3, 4, 5, 6));
     $gridField = new GridField('testfield', 'testfield', $data, $config);
     $endList = $gridField->getManipulatedList();
     $this->assertEquals($endList->Count(), 6);
     $config->addComponent(new GridFieldTest_Component2());
     $endList = $gridField->getManipulatedList();
     $this->assertEquals($endList->Count(), 12);
     $config->addComponent(new GridFieldPaginator(10));
     $endList = $gridField->getManipulatedList();
     $this->assertEquals($endList->Count(), 10);
 }