Administrace uživatelů

Rudolf Svátek 2016-06-29 13:15

Celou aplikaci, tak, jak by měla vypadat po dnešní kapitole, si můžeš stáhnout: kapitola6.zip.

Tak dnešní díl bude trochu rozsáhlejší. Takže si udělej kafe, čaj, nebo co máš rád, a jdeme na to.

Redakční systém bude mít několik agend - uživatele, stránky, komentáře apod. Každá agenda bude mít svůj presenter, který bude spouštět různé akce. K nim se mohou vázat formuláře, nebo jiné komponenty, šablony a další dpolňky. V případě agendy uživatelů chceme vypsat existující uživatele v nějakém gridu, umožnit přidání, editaci a odstranění uživatele.

Výpis uživatelů

Tak výpis je nejjednodušší. Nepotřebuje formulář a vypíše se pomocí komponenty o5/grido, kterou jsme si instalovali v druhé kapitole.

Také ale budeme chtít ověřovat u všech agend, že je přihlášen oprávněný uživatel. Proto opět vytvoříme nějaký BasePresenter, ve kterém to ověřování provedeme. Soubor app\AdminModule\presenters\BasePresenter.php:

<?php
 
namespace App\AdminModule\Presenters;
 
use Grido\Components\Filters\Filter;
use Nette\Application\UI\Presenter;
use Nette\Security\User;
 
/**
 * Class BasePresenter
 * @package App\AdminModule\Presenters
 */
abstract class BasePresenter extends Presenter 
{
 
	/** @var string @persistent */
	public $filterRenderType = Filter::RENDER_INNER;
 
	/**
	 *
	 */
	protected function startup() {
		parent::startup();
		if (!$this->getUser()->isLoggedIn()) {
			if ($this->getUser()->logoutReason === User::INACTIVITY) {
				$this->flashMessage('Byli jste odhlášeni z důvodu nečinnosti. Prosím, přihlaste se znovu.');
			} else {
				$this->flashMessage('Prosím, přihlaste se.');
			}
			$this->redirect(':Front:Sign:in', ['backlink' => $this->storeRequest()]);
		}
 
		if (!$this->getUser()->isInRole('admin')) {
			$this->flashMessage('Nemáte oprávnění');
			$this->redirect(':Front:Sign:in', ['backlink' => $this->storeRequest()]);
		}
	}
 
}

Takže vytvoř soubor app\AdminModule\presenters\UsersPresenter.php. Budeme potřebovat repositář (ten máme z minulé kapitoly) a komponentu Grido. Dědíme z BasePresenter.

<?php
  
namespace App\AdminModule\Presenters;
  
use App\Model\UsersRepository;
use Grido\Grid;
use Nette\Security\Passwords;
 
/**
 * Class UsersPresenter
 * @package App\AdminModule\Presenters
 */
class UsersPresenter extends BasePresenter 
{
 
	/** @var UsersRepository @inject */
	public $usersRepository;
 
	public function startup() {
		parent::startup();
	}
  
	/**
	 * @param $name
	 * @return Grid
	 */
	protected function createComponentGrid($name) {
		$grid = new Grid($this, $name);
		$grid->translator->lang = 'cs';
  
		$fluent = $this->usersRepository->getAll();
		$grid->model = $fluent;
  
		$grid->addColumnText('username', 'Username')
				->setSortable()
				->setFilterText();
  
		$grid->addColumnText('name', 'Name')
				->setSortable()
				->setFilterText();
  
		$grid->addColumnText('lastname', 'Lastname')
				->setSortable()
				->setFilterText();
  
		$grid->addColumnText('role', 'Role')
				->setSortable()
				->setFilterText();
  
		$grid->setDefaultPerPage(50);
		$grid->filterRenderType = $this->filterRenderType;
		$grid->setExport();
  
		return $grid;
	}
	 
}

Ohledně O5/Grido si prosím nastuduj jak se používá. Nerad bych tu duplikoval nápovědu.

Dále musíme mít šablonu, která komponentu vykreslí. Opět jednoduché - vytvoř soubor app\AdminModule\presenters\templates\Users\default.latte. Bude obsahovat pár řádků:

{block content}
{control grid}

Už teď se vypíší uživatelé. Zatím to nevypadá nic moc, protože nemáme ještě nahrané styly, obrázky, javascripty apod. Ale už to aspoň funguje.

Editace uživatele

A zase je tu formulář. Tentokrát chceme editovat již existujícího uživatele. Princip bude stejný jako dosud - komponenta s formulářem, jeho zobrazení a zpracování. Ve výpisu si budeme tedy chtít vypsat odkaz na editaci. Grido to udělá samo, jen musíme upravit výpis komponenty Grid:

		$grid->addColumnText('role', 'Role')
				->setSortable()
				->setFilterText();

		$grid->addActionHref('edit', '')
				->setIcon('pencil');

		$grid->setDefaultPerPage(50);

Ale to samozřejmě nestačí. Musíme taky doplnit funkci, která zajistí, že se zobrazený editační formulář vyplní stávajícími údaji:

	/**
	 * @param int $id
	 */
	public function renderEdit($id = 0) {
		/** @var Form $form */
		$form = $this['editForm'];
		if (!$form->isSubmitted()) {
			$item = $this->usersRepository->get($id);
			$row = $this->usersRepository->itemToArray($item);
			if (!$row) {
				throw new PDOException('Záznam nenalezen');
			}
			$form->setDefaults($row);
		}
	}

Na řádku 6 se vytváří formulář pomocí $form = $this['editForm']. Definice formuláře ale ještě neexistuje. Vytvoř tedy soubor app\AdminModule\components\EditUserFormFactory.php s obsahem:

<?php
 
namespace App\Forms;
 
use Nette\Application\UI\Form;
use Kdyby\BootstrapFormRenderer\BootstrapRenderer;
 
/**
 * Class EditUserFormFactory
 * @package App\Forms
 */
class EditUserFormFactory {
 
    /** @var FormFactory */
    private $factory;
 
    public function __construct(FormFactory $factory) {
        $this->factory = $factory;
    }
 
    /**
     * @return Form
     */
    public function create() {
        $form = $this->factory->create();
 
        $roles = [
            'guest' => "Host",
            'user' => "Uživatel",
            'admin' => "Administrátor"
        ];
 
        $form->addHidden('id', 'ID');
        $form->addText('username', "Login")
            ->setAttribute('placeholder', "Login")
            ->setAttribute('class', 'form-control input-sm')
            ->setRequired("Vyplňte prosím Login");
        $form->addPassword('password', 'Heslo')
            ->setAttribute('placeholder', "Heslo")
            ->setAttribute('class', 'form-control input-sm');
        $form->addPassword('password2', 'Heslo pro kontrolu')
            ->addRule(Form::EQUAL, "Vyplňte heslo pro kontrolu", $form['password'])
            ->setAttribute('placeholder', " pro kontrolu")
            ->setAttribute('class', 'form-control input-sm');
        $form->addText('name', "Jméno")
            ->setAttribute('placeholder', "Jméno")
            ->setAttribute('class', 'form-control input-sm');
        $form->addText('lastname', "Příjmení")
            ->setAttribute('placeholder', "Příjmení")
            ->setAttribute('class', 'form-control input-sm');
        $form->addText('email', "email")
            ->setType('email')
            ->addRule(Form::EMAIL, "Vyplňte email ve správném formátu")
            ->setAttribute('placeholder', "Email")
            ->setAttribute('class', 'form-control input-sm');
        $form->addSelect('role', "Role" . ": ", $roles)
            ->setAttribute('class', 'form-control input-sm');
        $form->addSubmit('process', "Odeslat")
            ->setAttribute('class', 'btn btn-primary');
 
        $form->setRenderer(new BootstrapRenderer);
 
        return $form;
    }
 
}

Do presenteru UsersPresenter.php přidáme funkci pro vygenerování komponenty s formulářem a také pro zpracování odeslaného formuláře:

	/**
	 * @return Form
	 */
	protected function createComponentEditForm() {
		$form = $this->editUserFormFactory->create();

		$form->onSuccess[] = function (Form $form) {
			$values = $form->getValues();
			$this->userEntity = $this->usersRepository->get($values->id);
			$error = 0;

			if (!$this->isNonDuplicite('email', $values)) {
				$this->flashMessage('Tento mail používá jiný uživatel.', 'danger');
				$error = 1;
			}

			if (trim($values->password) != '')
				$this->userEntity->password($this->getUser()->authenticator->calculateHash($values->password));

			if ($error == 0) {
				$this->userEntity->name($values->name);
				$this->userEntity->lastname($values->lastname);
				$this->userEntity->email($values->email);
				$this->userEntity->role($values->role);
				$this->usersRepository->save($this->userEntity);
				$this->flashMessage('Změny byly uloženy', 'success');
				$this->redirect('default');
			}
		};
		return $form;
	}

Ještě ale musíme přidat 4 řádky:

<?php
  
namespace App\AdminModule\Presenters;
  
use App\Model\UsersRepository;
use Grido\Grid;
use Nette\Security\Passwords;
use Nette\Forms\Form;
use App\Forms\EditUserFormFactory;
 
/**
 * Class UsersPresenter
 * @package App\AdminModule\Presenters
 */
class UsersPresenter extends BasePresenter 
{
 
	/** @var UsersRepository @inject */
	public $usersRepository;
 
	/** @var EditUserFormFactory @inject */
	public $editUserFormFactory;

	public function startup() {
		parent::startup();
	}
  

Vytvoříme službu pro formulář přidáním řádku do config.neon:

- App\Forms\EditUserFormFactory

Pak už zase jen šablonu app\AdminModule\presenters\Users\edit.latte:

{block content}
{control editForm}

Přidání uživatele

Klasika - továrna formuláře, služba v configu, úprava presenteru, šablona.

Formulář pro přidání uživatele bude ležet v souboru app\AdminModule\components\AddUserFormFactory.php. Bude téměř stejný jako ten pro editaci uživatele. Jen nebudeme znát ID, takže:

<?php
 
namespace App\Forms;
 
use Nette\Application\UI\Form;
use Kdyby\BootstrapFormRenderer\BootstrapRenderer;
 
/**
 * Class AddUserFormFactory
 * @package App\Forms
 */
class AddUserFormFactory {
 
    /** @var FormFactory */
    private $factory;
 
    public function __construct(FormFactory $factory) {
        $this->factory = $factory;
    }
 
    /**
     * @return Form
     */
    public function create() {
        $form = $this->factory->create();
 
        $roles = [
            'guest' => "Host",
            'user' => "Uživatel",
            'admin' => "Administrátor"
        ];
 
        $form->addText('username', "Login")
            ->setAttribute('placeholder', "Login")
            ->setAttribute('class', 'form-control input-sm')
            ->setRequired("Vyplňte prosím Login");
        $form->addPassword('password', 'Heslo')
            ->setAttribute('placeholder', "Heslo")
            ->setAttribute('class', 'form-control input-sm');
        $form->addPassword('password2', 'Heslo pro kontrolu')
            ->addRule(Form::EQUAL, "Vyplňte heslo pro kontrolu", $form['password'])
            ->setAttribute('placeholder', " pro kontrolu")
            ->setAttribute('class', 'form-control input-sm');
        $form->addText('name', "Jméno")
            ->setAttribute('placeholder', "Jméno")
            ->setAttribute('class', 'form-control input-sm');
        $form->addText('lastname', "Příjmení")
            ->setAttribute('placeholder', "Příjmení")
            ->setAttribute('class', 'form-control input-sm');
        $form->addText('email', "email")
            ->setType('email')
            ->addRule(Form::EMAIL, "Vyplňte email ve správném formátu")
            ->setAttribute('placeholder', "Email")
            ->setAttribute('class', 'form-control input-sm');
        $form->addSelect('role', "Role" . ": ", $roles)
            ->setAttribute('class', 'form-control input-sm');
        $form->addSubmit('process', "Odeslat")
            ->setAttribute('class', 'btn btn-primary');
 
        $form->setRenderer(new BootstrapRenderer);
 
        return $form;
    }
 
}

V presenteru musíme opět přidat metodu pro vytvoření komponenty a zpracování odeslaného formuláře:

	/**
	 * @return Form
	 */
	protected function createComponentAddForm() {
		$form = $this->addUserFormFactory->create();

		$form->onSuccess[] = function (Form $form) {
			$values = $form->getValues();
			$error = FALSE;

			if ($this->usersRepository->getOneWhere(['email' => $values->email])) {
				$this->flashMessage($this->translator->translate('messages.users.mail_use'), 'danger');
				$error = TRUE;
			}
			
			if ($this->usersRepository->getOneWhere(['username' => $values->username])) {
				$this->flashMessage('Uživatel s tímto username již existuje.', 'danger');
				$error = TRUE;
			}

			if (!$error) {
				$userEntity = new \App\Model\UsersEntity();
				$userEntity->username($values->username);
				$userEntity->password(Passwords::hash($values->password));
				$userEntity->name($values->name);
				$userEntity->lastname($values->lastname);
				$userEntity->email($values->email);
				$userEntity->role($values->role);
				$this->usersRepository->save($userEntity);
				$this->flashMessage('Záznam byl vytvořen.', 'success');
				$this->redirect('default');
			}
		};
		return $form;
	}

A samozřejmě přidat zase služby:

<?php
  
namespace App\AdminModule\Presenters;
  
use App\Model\UsersRepository;
use Grido\Grid;
use Nette\Security\Passwords;
use Nette\Forms\Form;
use App\Forms\EditUserFormFactory;
use App\Forms\AddUserFormFactory;
 
/**
 * Class UsersPresenter
 * @package App\AdminModule\Presenters
 */
class UsersPresenter extends BasePresenter 
{
 
	/** @var UsersRepository @inject */
	public $usersRepository;
 
	/** @var EditUserFormFactory @inject */
	public $editUserFormFactory;

	/** @var AddUserFormFactory @inject */
	public $addUserFormFactory;

	public function startup() {
		parent::startup();
	}

Vytvoříme další službu pro formulář přidáním řádku do config.neon:

- App\Forms\AddUserFormFactory

No a nakonec vytvoříme šablonu, která formulář vykreslí. Soubor app\AdminModule\presenters\templates\Users\add.latte:

{block content}
{control addForm}

Adresa pro přidání uživatele pak je:

http://localhost:8000/admin/users/add

Smazání uživatele

Prozatím poslední akcí bude smazání uživatele. k tomu není zapotřebí žádný formulář, žádná další služba, jen akce presenteru. Plánujeme, že funkci budeme volat z výpisu uživatelů a provedeme ji pomocí ajaxového požadavku. V presenteru tedy vytvoříme handler:

	/**
	 * @param $id
	 */
	public function handleDelete($id) {
		$this->usersRepository->delete($id);
		$this->flashMessage('Uživatel byl smazán.', 'success');
		$this->redirect('default');
	}

Také do Gridu přidáme vygenerování signálu na handler:

		$grid->addActionEvent('delete', '')
				->setCustomRender(function ($item) {
					$i = Html::el('i', ['class' => 'fa fa-trash']);
					$el = Html::el('a', ['class' => 'btn btn-default btn-xs btn-mini ajax'])
							->href($this->presenter->link("delete!", $item->id))
							->setHtml($i);
					return $el;
				});

Všechno, co jsme dnes chtěli udělat, to máme. Jenže když se podíváš na výpis uživatelů, nevypadá moc hezky. Ani se nevykreslí odkazy na editaci či mazání. Příště tedy budeme pracovat na úpravách vzhledu a na šablonách.

Celou aplikaci, tak, jak by měla vypadat po dnešní kapitole, si můžeš stáhnout: kapitola6.zip.

Redakční systém RS::RS Předchozí kapitola

Model pro tabulku Users

Redakční systém RS::RS Celý seriál

Vývoj redakčního systému v PHP

Redakční systém RS::RS Následující kapitola

Úpravy vzhledu administrace

Komentáře (0)

Přidej svůj komentář

O mně

Jmenuji se Rudolf Svátek. Jsem lektor výpočetní techniky a PHP programátor. Stavím firemní stránky a eshopy. Aby se mi to dělalo pohodlně, vytvořil jsem redakční systém RS::RS, který ti tu nabízím k použití.

Rychlý kontakt na mně

  • Rudolf Svátek
  • Telefon:
    +420 777 828 353
  • Email:
  • Adresa:
    Josefa Hory 1097/5
    736 01 Havířov
    ČR



Tyto stránky používají Cookies. Používáním stránek s tím souhlasíte Další informace