Řešení formulářů v administrační komponentě

Odo
Člen | 48
+
0
-

Ahoj všem,

potřeboval bych poradit, jak nejlépe vyřešit „administrační“ komponentu. Komponenta zobrazuje seznam položek + tlačítka pro různé akce, které posílají signály (přes AJAX). Stránkování, řazení, apod., je jednoduché, protože se pouze na základě parametrů překreslí snippety. Narážím ale na problém s editačními formuláři, u kterých bych potřeboval něco jako action v presenterech.

Komponenta vypadá (zjednodušeně) takto:

abstract class AdminControl extends Nette\Application\UI\Control
{
	protected $model;

	/** @persistent */
	public $page = 1;

	/** @persistent */
	public $size = 10;

	/** @persistent */
	public $sort = null;

	/** @persistent */
	public $id = null;

	function __construct(Model\AdminManager $model)
	{
		parent::__construct();
		$this->model = $model;
	}

	function render()
	{
		$this->template->data = $this->model->getAll($this->page, $this->size, $this->sort);
		// naplnění dalších parametrů šablony
		$this->template->render(__DIR__.'/templates/AdminControl.latte');
	}

	protected function redrawSnippets()
	{
		$this->redrawControl('flash');
		$this->redrawControl('grid');
		$this->redrawControl('form');
	}

	function handlePaginate($page)
	{
		$this->redrawSnippets();
	}

	function handleResize($size)
	{
		$this->redrawSnippets();
	}

	function handleSort($sort)
	{
		$this->redrawSnippets();
	}

	function handleDelete($id)
	{
		$this->model->deleteItem($id);
		$this->flashMessage('Záznam byl smazán.', 'info');
		$this->redrawSnippets();
	}

	function handleEdit($id) // standardní editační formulář
	{
		$this->redrawControl('flash');
		$this->redrawControl('form');
		$this->template->action = 'edit';
	}

	function handleManage($id) // další editační formulář
	{
		$this->redrawControl('flash');
		$this->redrawControl('form');
		$this->template->action = 'manage';
	}

	protected function createComponentAdminForm()
	{
		$item = $this->model->getItem($this->id);
		$form = new \App\BaseForm;
		$form->getElementPrototype()->class('ajax');
		// přidání prvků do formuláře
		$form->setDefaults($this->item);
		$form->onSuccess[] = [$this, 'adminFormSucceeded'];
		$form->addProtection();
		return $form;
	}

	function adminFormSucceeded($form, $values)
	{
		try {
			$this->model->setItem($this->id, $values);
			$this->flashMessage('Změny byly uloženy.', 'success');
			$this->redrawSnippets();
			return;
		}
		catch (Nette\Database\UniqueConstraintViolationException $e) {
			$form->addError('Chyba! Záznam již v databázi existuje. Zkuste změnit duplicitní údaje.');
		}
		catch (Nette\Database\DriverException $e) {
			$form->addError('Chyba! Záznam se nepodařilo uložit. Zkuste to znovu.');
			bdump($e);
		}
		$this->template->action = 'edit'; // při chybě se formulář znovu zobrazí
		$this->redrawControl('form');
	}

}
{import @layout.latte}
{import $presenter->getTemplate()->getFile()}

<h1>
	{include #"$name-title"}
	<a class="ajax btn btn-success" n:href="edit!,0"><span class="glyphicon glyphicon-plus"></span>&ensp;Přidat</a>
</h1>

{snippet flash}
	{foreach $flashes as $flash}
		{include #alert, type => $flash->type, message => $flash->message}
	{/foreach}
{/snippet}

{snippet form}
	{default $action = ''}
	{if $action == 'edit'}
		{control adminForm}
	{/if}
	{if $action == 'crop'}
		<img id="crop" src="{$image}{date('?YmdHis')}" alt>
		{control cropForm}
	{/if}
	{if $action == 'manage'}
		{include #"$name-manager"}
	{/if}
{/snippet}

{snippet grid}
	<div class="table-responsive">
		<table class="data-grid table table-condensed table-striped table-hover">
			<thead>
				<tr>
{* hlavička *}
				</tr>
			</thead>
			<tbody>
				<tr n:foreach="$data as $item">
					{include #"$name-item", item => $item}
					<td>
						<a class="ajax btn btn-primary"
							n:href="edit!,$item->id"><span class="glyphicon glyphicon-pencil"></span></a>
						<a class="datagrid-delete btn btn-danger"
							n:href="delete!,$item->id"><span class="glyphicon glyphicon-trash"></span></a>
					</td>
				</tr>
			</tbody>
			<tfoot>
				<tr>
{* patička - stránkovač *}
				</tr>
			</tfoot>
		</table>
	</div>
{/snippet}

Komponenty pro konkrétní věci (soubory, videa, uživatelé, apod.) jsou pak od ní odvozené a řeší si pouze zobrazení položek a zpracování formulářů.

U některých komponent potřebuju po zpracování editačního formuláře ještě zpracovat další formulář (třeba ořez náhledu):

	function adminFormSucceeded($form, $values)
	{
		// zpracování formuláře...
		$this->template->action = 'crop';
		$this->redrawControl('form'); // zobrazení nový formulář (cropForm)
	}

Přijde mi, že jsem tím vlastně simuluju metody actionXXX z presenteru, ale v komponentě.
Existuje nějaký správný postup, jak toto řešit?

[Nette 2.4]

Editoval Odo (19. 4. 2020 18:35)