silverstripe-framework/src/Forms/GridField/GridField_FormAction.php

140 lines
3.3 KiB
PHP

<?php
namespace SilverStripe\Forms\GridField;
use SilverStripe\Control\Controller;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FormAction;
use SilverStripe\Forms\GridField\FormAction\StateStore;
/**
* This class is the base class when you want to have an action that alters the state of the
* {@link GridField}, rendered as a button element.
*/
class GridField_FormAction extends FormAction
{
/**
* A common string prefix for keys generated to store form action "state" against
*/
const STATE_KEY_PREFIX = 'gf_';
/**
* @var GridField
*/
protected $gridField;
/**
* @var array
*/
protected $stateValues;
/**
* @var array
*/
protected $args = [];
/**
* @var string
*/
protected $actionName;
/**
* @var boolean
*/
public $useButtonTag = true;
/**
* @param GridField $gridField
* @param string $name
* @param string $title
* @param string $actionName
* @param array $args
*/
public function __construct(GridField $gridField, $name, $title, $actionName, $args)
{
$this->gridField = $gridField;
$this->actionName = $actionName;
$this->args = $args;
parent::__construct($name, $title);
}
/**
* Encode all non-word characters.
*
* @param string $value
*
* @return string
*/
public function nameEncode($value)
{
return (string)preg_replace_callback('/[^\w]/', [$this, '_nameEncode'], $value ?? '');
}
/**
* @param array $match
*
* @return string
*/
public function _nameEncode($match)
{
return '%' . dechex(ord($match[0] ?? ''));
}
/**
* @return array
*/
public function getAttributes()
{
// Determine the state that goes with this action
$state = [
'grid' => $this->getNameFromParent(),
'actionName' => $this->actionName,
'args' => $this->args,
];
// Generate a key and attach it to the action name
$key = static::STATE_KEY_PREFIX . substr(md5(serialize($state)), 0, 8);
// Note: This field needs to be less than 65 chars, otherwise Suhosin security patch will strip it
$name = 'action_gridFieldAlterAction?StateID=' . $key;
// Define attributes
$attributes = [
'name' => $name,
'data-url' => $this->gridField->Link(),
'type' => "button",
];
// Create a "store" for the "state" of this action
/** @var StateStore $store */
$store = Injector::inst()->create(StateStore::class . '.' . $this->gridField->getName());
// Store the state and update attributes as required
$attributes += $store->save($key, $state);
// Return attributes
return array_merge(
parent::getAttributes(),
$attributes
);
}
/**
* Calculate the name of the gridfield relative to the form.
*
* @return string
*/
protected function getNameFromParent()
{
$base = $this->gridField;
$name = [];
do {
array_unshift($name, $base->getName());
$base = $base->getForm();
} while ($base && !($base instanceof Form));
return implode('.', $name);
}
}