Customizable/extendable column format parsing
This is a feature request.
Right now we can use "attribute:format:label" to describe the display rule of a column in GridView and DetailView, format declared the formatter to use. Developers can create their own custom formatter class by extending \yii\i18n\Formatter to add custom formatters to fit their needs. Sometimes developers may need to add some extra argument to a formatter to get more flexible control, then we'll need to create an array with a 'format' key instead to pass arguments to the formatter:
// for example:
// from
'testAttr:example:Test Attr',
// to
[
'attribute' => 'testAttr',
'label' => 'Test Attr',
'format' = ['example', false],
]
As a possible solution, I think using something like attribute:format(arg1,arg2):label to define the column display format could be handy, so as long as the arguments are not complex, developers won't need to stop and do the manual convert, so developers could keep focus on what they need to implement. I did a sample implementation to parse such format:
-
'testAttr:example:Test Attr' -
'testAttr:example(true):Test Attr' -
'testAttr:example(true,false,"string",114514):Test Attr'
Sample implementation for Yii2 GridView
DataColumnTrait.php
<?php
namespace backend\traits;
use yii;
use yii\helpers\Html;
use yii\base\InvalidConfigException;
use yii\grid\DataColumn;
trait DataColumnTrait
{
/**
* Creates a [[DataColumn]] object based on a string in the format of "attribute:format:label".
* @param string $text the column specification string
* @return DataColumn the column instance
* @throws InvalidConfigException if the column specification is invalid
*/
protected function createDataColumn($text)
{
if (!preg_match('/^([^:]+)(:(\w*)(\([\w,+_"]*\))?)?(:(.*))?$/', $text, $matches)) {
throw new InvalidConfigException('The column must be specified in the format of "attribute", "attribute:format" or "attribute:format:label"');
}
$formatArr = [
isset($matches[3]) ? $matches[3] : 'text'
];
if (isset($matches[4])) {
$args = array_filter(explode(',', substr(trim($matches[4]), 1, -1)));
foreach ($args as $arg) {
// if (empty($arg)) continue;
$arg = trim($arg);
if ($arg[0] == '"') {
$actualVal = str_replace('"', '', $arg[0]);
array_push($formatArr, $actualVal);
} elseif (is_numeric($arg)) {
array_push($formatArr, intval($arg));
} elseif (in_array($arg, ["false", "true"])) {
array_push($formatArr, $arg == "true");
} else {
throw new InvalidConfigException('Unrecognized argument(s), supported argument type are: true, false, digits(number) and double-quoteed string. Use comma to split multiple arguments');
}
}
}
return Yii::createObject([
'class' => $this->dataColumnClass ?: DataColumn::class,
'grid' => $this,
'attribute' => $matches[1],
'format' => $formatArr,
'label' => isset($matches[6]) ? $matches[6] : null,
]);
}
}
GridView.php
<?php
namespace backend\components;
use backend\traits\DataColumnTrait;
class GridView extends \yii\grid\GridView
{
use DataColumnTrait;
}
But by looking into the implementation from the Yii codebase, it seems the logic of parsing that format string is live in different places and not as extendable as using a custom formatter, so I suggest we could make such thing extendable by extracting that part of logic and allow developer use their own "ColumnFactory" (example name) or make these *View use the same trait to do the column format parse job.