Source of file TileField.php
Size: 9,946 Bytes - Last Modified: 2021-12-23T10:09:42+00:00
/var/www/docs.ssmods.com/process/src/src/Fields/TileField.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 | <?php namespace OP\Fields; use function GuzzleHttp\json_encode; use OP\Forms\TileFieldDetailForm; use OP\Models\Tile; use SilverStripe\Control\Controller; use SilverStripe\Control\HTTPRequest; use SilverStripe\Core\ClassInfo; use SilverStripe\Core\Injector\Injector; use SilverStripe\Forms\FormField; use SilverStripe\Forms\GridField\GridField; use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor; use SilverStripe\Forms\GridField\GridFieldDetailForm; use SilverStripe\ORM\ArrayList; use SilverStripe\ORM\DataObject; use SilverStripe\ORM\SS_List; use SilverStripe\View\Requirements; /** * * Creates a reorderable 2D tile field. For example: * <code> * private static $has_many = [ * 'Tiles' => Tile::class * ]; * private static $owns = [ * 'Tiles' * ]; * * function getCMSFields() { * $fields = parent::getCMSFields(); * $fields->addFieldToTab('Root.Main', TileField::create('Tiles', 'Tiles', $this->Tiles())); * } * </code> */ class TileField extends GridField { private static $allowed_actions = array( 'delete', ); private static $url_handlers = [ 'delete/$Action' => 'delete', ]; protected $widthholder = null; protected $defaultrows = 4; /** * The list of avalible items to select from * @var SS_List */ protected $selectionlist = null; /** * include the required js/css * @param string $name of field * @param string $title the fancy title * @param SS_List $dataList list of tile objects * @param SS_List $selectionlist if you want to restrict the types of tiles. if null it will display all * @param DataObject $widthholder - if set, this object will be saved with the number of rows */ public function __construct($name, $title = null, SS_List $dataList = null, $selectionlist = null, DataObject $widthholder = null) { $this->selectionlist = $selectionlist; $this->widthholder = $widthholder; // set the default tile type $conf = new GridFieldConfig_RecordEditor(); $conf->removeComponentsByType(new GridFieldDetailForm()); $conf->addComponent(new TileFieldDetailForm('DetailForm', Tile::class)); parent::__construct($name, $title, $dataList, $conf); // style and react js Requirements::css('otago/tiles: css/TileField.css'); Requirements::javascript('otago/tiles: client/dist/js/bundle.js'); Requirements::css('symbiote/silverstripe-gridfieldextensions:css/GridFieldExtensions.css'); Requirements::javascript('symbiote/silverstripe-gridfieldextensions:javascript/GridFieldExtensions.js'); } /** * handles a delete request via ajax * @param HTTPRequest $request * @return HTTP * @throws \SilverStripe\Control\HTTPResponse_Exception */ public function delete(HTTPRequest $request) { $tileid = $request->latestParam('Action'); $mytile = Tile::get()->byID($tileid); if ($mytile) { $mytile->delete(); return \SilverStripe\Control\HTTPResponse::create('Tile with ID ' . $tileid . ' has been deleted'); } throw new \SilverStripe\Control\HTTPResponse_Exception('failed to find Tile', 400); } /** * override the gridfield render method. we want to render using TileField.ss * @param type $properties * @return type */ public function FieldHolder($properties = array()) { return FormField::FieldHolder($properties); } /** * returns a list of palatable dataobjects used for the template render * @return \ArrayList */ public function Options() { return Tile::get()->filter(array('ParentID' => $this->form->getRecord()->ID, 'Name' => $this->name)); } /** * Creates a rendered Programme Crawler Field using the .ss template * @param type $properties an array of values to decorate the field * @return type a rendered template */ public function Field($properties = array()) { $obj = ($properties) ? $this->customise($properties) : $this; $obj->Options = $this->Options(); $tmp = $obj->renderWith('TileField'); return $tmp; } /** * will return the link that is used to create new tile objects * @return string url */ public function getAddURL() { return Controller::join_links($this->Link(), 'item', 'new'); } /** * will return the link that is used to edit tile objects * @return string url */ public function getEditURL() { return Controller::join_links($this->Link(), 'item', 'ID', 'edit'); } /** * will return the link that is used to remove tile objects * @return string url */ public function getDeleteURL() { return Controller::join_links($this->Link(), 'delete', 'ID'); } /** * we intercept the request to figure out what tile class we're using. we then * inform the parent gridfield through a custom component (TileFieldDetailForm) * @param HTTPRequest $request * @return html */ public function handleRequest(HTTPRequest $request) { if ($request->requestVar('TileType')) { $record = Injector::inst()->create(str_replace('_', '\\', $request->requestVar('TileType'))); $this->setModelClass($record->ClassName); // replace TileFieldDetailForm $config = $this->getConfig(); $config->removeComponentsByType(new TileFieldDetailForm()); $config->addComponent(new TileFieldDetailForm('', $record->ClassName)); $this->setConfig($config); } return parent::handleRequest($request); } /** * get file types * @return \ArrayList */ public function getTileTypes() { if ($this->selectionlist) { return $this->selectionlist; } $Arraylist = ArrayList::create(); $dataClasses = ClassInfo::subclassesFor(Tile::class); foreach ($dataClasses as $key => $item) { if ($key == "Tile") { continue; } $do = DataObject::create(); $do->Name = $item; $do->NiceName = $item::create()->singular_name(); $Arraylist->push($do); } return $Arraylist; } /** * tiles we're allowed to create * @return json */ public function getTileTypesJson() { $retarray = array(); foreach ($this->getTileTypes() as $item) { $retarray[] = array( 'title' => $item->Name, 'name' => $item->NiceName, ); } return json_encode($retarray); } /** * return the number of rows * @return int */ public function getRows() { if ($this->widthholder) { return $this->widthholder->Rows ?: $this->defaultrows; } return $this->defaultrows; } /** * a list of items inside this area. mapped to react-grid-layout * @return json */ public function getDataListJson() { $retarray = array(); foreach ($this->list as $item) { if ($item instanceof DataObject && $item->hasMethod('generateRawArray')) { $retarray[] = $item->generateRawArray(); } } return json_encode($retarray); } /** * saving the grid structure via clicking 'save' * @param type $value * @param type $data * @return $this */ public function setValue($value, $data = null) { parent::setValue($value, $data); if (is_array($data) && array_key_exists($this->name, $data) && array_key_exists('GridLayout', $data[$this->name])) { if (isset($data[$this->name]['GridLayout'])) { $updatedtiles = $data[$this->name]['GridLayout']; foreach ($updatedtiles as $id => $arraydata) { $tile = Tile::get()->byID($id); if ($tile) { $tile->writeRawArray($arraydata); } } } // write the number of rows to the parent object if (isset($data[$this->name]['Rows'])) { $rows = $data[$this->name]['Rows']; if (is_numeric($rows)) { if ($this->widthholder) { $this->widthholder->Rows = $rows; $this->widthholder->write(); } } } } return $this; } public function RowsEnabled() { return $this->widthholder instanceof DataObject; } public function getAttributesJson() { return json_encode($this->getAttributes()); } /** * Allows customization through an 'updateAttributes' hook on the base class. * Existing attributes are passed in as the first argument and can be manipulated, * but any attributes added through a subclass implementation won't be included. * * @return array */ public function getAttributes() { $attributes = array( 'type' => $this->getInputType(), 'name' => $this->getName(), 'value' => $this->Value(), 'class' => $this->extraClass(), 'id' => $this->ID(), 'disabled' => $this->isDisabled(), 'readonly' => $this->isReadonly(), 'autofocus' => $this->isAutofocus(), ); if ($this->Required()) { $attributes['required'] = 'required'; $attributes['aria-required'] = 'true'; } $attributes = array_merge($attributes, $this->attributes); $this->extend('updateAttributes', $attributes); return $attributes; } } |