Name Surname Country
Birthdate W (kg)  
Aaya Weerdenburg Italy 04. 05. 1970 67.7
Abe Sneep Finland 01. 03. 1980 69.5
Adaora Eluemuno United Kingdom 18. 06. 1971 52.2
Adaora Ikechukwu Spain 29. 12. 1985 49
Aiglentina Cyr United Kingdom 15. 05. 1981 53.9
Aimee Bevan Germany 06. 04. 1976 66.5
Ajuluchukwu Ibezimako Belgium 01. 07. 1995 58.2
Aki Sarparanta United Kingdom 10. 03. 1994 54
Alexandra Nørgaard Spain 03. 10. 1973 62.4
Alicia Chadwick Finland 23. 07. 1978 60.4
Allie Graham United Kingdom 19. 08. 1972 55.3
Amber Duffy Canada 09. 05. 1991 63

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}