Name
2
Surname
1
Country
Birthdate W (kg)  
Cornelia Angelo Switzerland 18. 02. 1995 66.5
Maria Antunez France 26. 07. 1984 63.9
Caresse Asselin Spain 04. 04. 1984 49.5
Elly Axelsson Italy 15. 02. 1993 55.2
Nóra Balog Sweden 02. 02. 1984 55.2
Federika Bastašič Germany 10. 09. 1984 59.9
Charli Bastyan Finland 23. 03. 1987 47.8
Antonija Bašić Spain 29. 08. 1994 55.9
Tico Beens Italy 14. 04. 1993 57.5
Aimee Bevan Germany 06. 04. 1976 66.5
Wera Björk Australia 16. 06. 1983 49.3
Mary Black Iceland 15. 12. 1994 49.2

Code

# FullGrid.php


use Nette\Forms\Form;
use TwiGrid\Components\Column;


class FullGrid extends BaseGrid
{

	/** @return void */
	protected function build()
	{
		parent::build();

		$this->setTemplateFile(__DIR__ . '/@full.latte');

		$this->setPrimaryKey('id');
		$this->addColumn('firstname', 'Name')->setSortable();
		$this->addColumn('surname', 'Surname')->setSortable();
		$this->addColumn('country_code', 'Country');
		$this->addColumn('birthday', 'Birthdate')->setSortable();
		$this->addColumn('kilograms', 'W (kg)')->setSortable();

		$this->setFilterFactory([$this, 'createFilterContainer']);
		$this->setDataLoader([$this, 'dataLoader']);
		$this->setPagination(12, [$this, 'itemCounter']);
		$this->setInlineEditing([$this, 'createInlineEditContainer'], [$this, 'processInlineEditForm']);

		$this->addRowAction('delete', 'Delete', [$this, 'deleteRecord'])
			->setConfirmation('Do you really want to delete this record?');

		$this->addGroupAction('delete', 'Delete', [$this, 'deleteMany'])
			->setConfirmation('WARNING! Deleted records cannot be restored! Proceed?');

		$this->setDefaultOrderBy([
			'surname' => Column::ASC,
			'firstname' => Column::DESC,
		]);

		$this->setDefaultFilters([
			'kilograms' => 70,
			'birthday' => [
				'min' => '01. 01. 1970',
				'max' => '28. 11. 1996',
			],
		]);
	}


	/** @return Nette\Forms\Container */
	public function createFilterContainer()
	{
		$container = new Nette\Forms\Container;

		$container->addText('firstname');
		$container->addText('surname');

		$birthday = $container->addContainer('birthday');
		$min = Helpers::addDateInput($birthday, 'min');
		$max = Helpers::addDateInput($birthday, 'max');

		$min->addCondition(Form::FILLED)->addRule(function () use ($min, $max) {
			return !$max->filled
					|| (($minDt = Helpers::parseDate($min->value)) !== FALSE
						&& ($maxDt = Helpers::parseDate($max->value)) !== FALSE
						&& $minDt <= $maxDt);

		}, 'Please select valid date range.');

		$container->addSelect('country_code', 'Country', Helpers::getCountries())
				->setPrompt('---');

		$container->addText('kilograms')->addCondition(Form::FILLED)->addRule(Form::FLOAT);

		return $container;
	}


	/**
	 * @param  Nette\Database\Table\ActiveRow $record
	 * @return Nette\Forms\Container
	 */
	public function createInlineEditContainer(Nette\Database\Table\ActiveRow $record)
	{
		$container = new Nette\Forms\Container;
		$container->addText('firstname')->setRequired();
		$container->addText('surname')->setRequired();
		$container->addSelect('country_code', 'Country', Helpers::getCountries())
				->setRequired()
				->setDefaultValue($record->country_code);

		Helpers::addDateInput($container, 'birthday')->setRequired();
		$container->addText('kilograms')->addRule(Form::FLOAT);
		$defaults = $record->toArray();
		$defaults['birthday'] = (new DateTime($defaults['birthday']))->format('d. m. Y');
		return $container->setDefaults($defaults);
	}


	/**
	 * @param  FullGrid $grid
	 * @param  array $filters
	 * @param  array $order
	 * @param  int $limit
	 * @param  int $offset
	 * @return Nette\Database\Table\Selection
	 */
	public function dataLoader(FullGrid $grid, array $filters, array $order, $limit, $offset)
	{
		// selection factory
		$users = $this->database->table('user');

		// filtering
		static::filterData($users, $filters);

		// order
		static::orderData($users, $order);

		// paginating
		return $users->limit($limit, $offset);
	}


	/**
	 * @param  FullGrid $grid
	 * @param  array $filters
	 * @return int
	 */
	public function itemCounter(FullGrid $grid, array $filters)
	{
		return static::filterData($this->database->table('user'), $filters)
				->count('*');
	}


	/**
	 * @param  NSelection $selection
	 * @param  array $filters
	 * @return NSelection
	 */
	protected static function filterData(Nette\Database\Table\Selection $selection, array $filters)
	{
		foreach ($filters as $column => $value) {
			if ($column === 'gender') {
				$selection->where($column, $value);

			} elseif ($column === 'country_code') {
				$selection->where($column, $value);

			} elseif ($column === 'birthday') {
				isset($value['min']) && $selection->where("$column >= ?", Helpers::parseDate($value['min'])->format('Y-m-d'));
				isset($value['max']) && $selection->where("$column <= ?", Helpers::parseDate($value['max'])->format('Y-m-d'));

			} elseif ($column === 'kilograms') {
				$selection->where("$column <= ?", $value);

			} elseif ($column === 'firstname' || $column === 'surname') {
				$selection->where("$column LIKE ?", "$value%");

			} else {
				$selection->where("$column LIKE ?", "%$value%");
			}
		}

		return $selection;
	}


	/**
	 * @param  NSelection $data
	 * @param  array $order
	 * @return NSelection
	 */
	protected static function orderData(Nette\Database\Table\Selection $data, array $order)
	{
		foreach ($order as $column => $dir) {
			$data->order($column . ($dir === TwiGrid\Components\Column::DESC ? ' DESC' : ''));
		}

		return $data;
	}


	/**
	 * @param  Nette\Database\Table\ActiveRow $record
	 * @return void
	 */
	public function deleteRecord(Nette\Database\Table\ActiveRow $record)
	{
		$this->flashMessage("[DEMO] Deletion request sent for record '{$record->id}'.", 'success');
	}


	/**
	 * @param  Nette\Database\Table\ActiveRow $record
	 * @param  Nette\Utils\ArrayHash $values
	 * @return void
	 */
	public function processInlineEditForm(Nette\Database\Table\ActiveRow $record, Nette\Utils\ArrayHash $values)
	{
		$this->flashMessage("[DEMO] Update request sent for record '{$record->id}'; new values: " . Nette\Utils\Json::encode($values), 'success');
	}


	/**
	 * @param  Nette\Database\Table\ActiveRow[]
	 * @return void
	 */
	public function deleteMany(array $records)
	{
		$ids = [];
		foreach ($records as $record) {
			$ids[] = $record->id;
		}

		$this->flashMessage('[DEMO] Records deletion request : ' . Nette\Utils\Json::encode($ids), 'success');
	}

}
	

# BaseGrid.php


use Nette\Http\Session as NSession;
use Nette\Database\Context as NdbContext;


abstract class BaseGrid extends TwiGrid\DataGrid
{

	/** @var NdbContext */
	protected $database;


	/**
	 * @param  NSession $session
	 * @param  NdbContext $database
	 */
	public function __construct(NSession $session, NdbContext $database)
	{
		parent::__construct($session);
		$this->database = $database;
	}


	/** @return void */
	protected function build()
	{
		parent::build();
		$this->setRecordVariable('user');
	}

}
	

# @full.latte


{extends $defaultTemplate}


{define filter-cell-birthday}
	<th class="birthday nowrap">
		<div>
			<input n:name="filters-criteria-birthday-min" class="form-control date min" placeholder="min">
			<input n:name="filters-criteria-birthday-max" class="form-control date max" placeholder="max">
			&ndash;
		</div>
	</th>
{/define}


{define filter-cell-kilograms}
	<th class="numeric">
		<input n:name="filters-criteria-kilograms" class="form-control">
	</th>
{/define}


{define body-cell-birthday}
	<td class="numeric center">{$user->birthday |date:'d. m. Y'}</td>
{/define}


{define body-cell-birthday-inline}
	<td><input n:name="inline-values-birthday" class="form-control date center"></td>
{/define}


{define body-cell-country_code}
	<td>{$user->ref('country', 'country_code')->title}</td>
{/define}


{define body-cell-kilograms}
	<td class="numeric right">{$user->kilograms}</td>
{/define}


{define body-cell-kilograms-inline}
	<td class="numeric"><input n:name="inline-values-kilograms" class="form-control"></td>
{/define}


{define row-action-delete}
	<a href="{$link}" class="btn btn-danger btn-sm tw-ajax" n:attr="data-tw-confirm => $action->getConfirmation()">
		{$action->getLabel()}
	</a>
{/define}