Doplnění dalších komponent

Rudolf Svátek 2017-08-21 11:39

Vrátím se ještě k tvorbě komponent. Spolu jsme si vytvořili komponentu pro výpis uživatelů My ale potřebujeme vypisovat i klienty, typy hesel a hlavně ta hesla. Taky musíme umět přidávat záznamy, mazat je a měnit.

Takže první věc, co uděláme, budou komponenty pro přidávání a úpravy uživatelů.

Nic tak složitého. Ve složce \app\components\Users přidáme soubor IUserAddFactory.php s interface pro generovanou továrničku (nějak se vžil tento název):

namespace App\Components\Users;

interface IUserAddFactory
{

    /**
     * @param \Dibi\Connection $db
     *
     * @return UserAdd
     */
    public function create(\Dibi\Connection $db);
}

Využijeme ji v souboru \app\components\Users\UserAdd.php:

<?php

namespace App\Components\Users;

use App\Forms\FormFactory;
use App\Model\Users\InsertUser;
use Dibi\Connection;
use Nette\Application\UI\Control;
use Nette\Application\UI\Form;
use Nette\Security\Passwords;

/**
 * Class UserAdd
 *
 * @package App\Components
 */
class UserAdd extends Control
{

    /** @var IUserAddFactory @inject */
    public $AddFactory;

    /** @var \Dibi\Connection */
    private $db;

    /** @var FormFactory */
    private $formFactory;

    /** @var \App\Model\Users\InsertUser */
    private $insertUserModel;

    /** @var string */
    private $templateFile = __DIR__ . '/User.add.latte';

    /**
     * UserAdd constructor.
     *
     * @param Connection  $db
     * @param FormFactory $formFactory
     */
    public function __construct(Connection $db, FormFactory $formFactory)
    {
        parent::__construct();
        $this->db = $db;
        $this->formFactory = $formFactory;
        $this->insertUserModel = new InsertUser($this->db);
    }

    /**
     * Method render
     */
    public function render()
    {
        $this->template->setFile($this->templateFile);
        $this->template->render();
    }

    /**
     * Method createComponentAddForm
     *
     * @return \Nette\Application\UI\Form
     */
    public function createComponentAddForm()
    {
        $roles = [
            'registered' => 'Registrovaný uživatel',
            'admin' => 'Administrátor',
            'manager' => 'Manažer',
        ];

        $form = $this->formFactory->create();
        $form->addHidden('id', 'ID');
        $form->addText('username', 'Login')
            ->setRequired(true)
            ->setAttribute('class', 'form-control');
        $form->addPassword('password', 'Heslo (6 - 20 znaků)')
            ->setAttribute('class', 'form-control')
            ->setRequired(true)
            ->addRule(Form::MIN_LENGTH, 'Heslo musí mít alespoň %d znaků', 6);
        $form->addText('name', 'Jméno')
            ->setRequired(true)
            ->setAttribute('class', 'form-control');
        $form->addEmail('email', 'Email')
            ->setRequired(true)
            ->setAttribute('class', 'form-control');
        $form->addSelect('role', 'Role: ', $roles)
            ->setAttribute('class', 'form-control');
        $form->addSubmit('send', 'odeslat')
            ->setAttribute('class', 'btn btn-info pull-right');

        $form->onSuccess[] = function (Form $form, $values) {
            $values->password = Passwords::hash($values->password);
            $this->insertUserModel->insert($values);
        };

        return $form;
    }
}

Komponenta obsahuje definici formuláře pro přidání záznamu do tabulky uživatelů. Pracuje taky s modelem App\Model\Users\InsertUser.

Ještě to potřebujeme někde vykreslit, takže musíme vyrobit šablonu \app\components\Users\User.add.latte. Jde to několika způsoby. Buď jedním řádkem {control addForm}. Nebo si můžeme vykreslit formulář ručně s různou úrovní ruční kontroly. Já to vzal úplně do ruky:

<div class="row" id="snippet--grid">
    <div class="col-sm-12" id="snippet-grid-grid">
        <div class="panel panel-default datagrid datagrid-grid">
            <div class="panel-body">
                <div class="box box-success">
                    <div class="box-header with-border">
                        <h3 class="box-title">Přidání uživatele</h3>
                    </div>
                    <!-- /.box-header -->
                    <!-- form start -->
                    <form class="form-horizontal" n:name="addForm">
                        <div class="box-body">
                            <div class="form-group">
                                <label n:name="username" class="col-sm-2 control-label">Login</label>

                                <div class="col-sm-10">
                                    <input n:name="username">
                                </div>
                            </div>
                            <div class="form-group">
                                <label n:name="password" class="col-sm-2 control-label">Heslo (6 - 20 znaků)</label>

                                <div class="col-sm-10">
                                    <input n:name="password">
                                </div>
                            </div>
                            <div class="form-group">
                                <label n:name="name" class="col-sm-2 control-label">Jméno</label>

                                <div class="col-sm-10">
                                    <input n:name="name">
                                </div>
                            </div>
                            <div class="form-group">
                                <label n:name="email" class="col-sm-2 control-label">Email</label>

                                <div class="col-sm-10">
                                    <input n:name="email">
                                </div>
                            </div>
                            <div class="form-group">
                                <label n:name="role" class="col-sm-2 control-label">Role</label>

                                <div class="col-sm-10">
                                    {input role}
                                </div>
                            </div>
                        </div>
                        <!-- /.box-body -->
                        <div class="box-footer">
                            <button type="submit" n:name="send">Uložit</button>
                        </div>
                        <!-- /.box-footer -->
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

Stejně tak funguje i nová komponenta pro úpravy detailu uživatele. Vypisovat ji tu už nebudu, ale opět je nutné interface, třída s komponentou a formulářem a šablona.

Aby to fungovalo, musíme ještě vyrobit presentery. Jeden pro přidání, druhý pro úpravy detailu:

<?php

namespace App\Presenters;

use App\Components\Users\IUserAddFactory;
use App\Components\Users\UserAdd;

/**
 * Class UserAddPresenter
 *
 * @package App\Presenters
 */
class UserAddPresenter extends BasePresenter
{

    /** @var IUserAddFactory @inject */
    public $addFactory;

    /**
     * Method beforeRender
     */
    public function beforeRender()
    {
        $this->getTemplate()->setFile(__DIR__ . "/templates/add.latte");
    }

    /**
     * @return UserAdd
     */
    protected function createComponentUserAdd()
    {
        $control = $this->addFactory->create($this->db);
        $control['addForm']->onSuccess[] = function () {
            $this->redirect('Users:');
        };

        return $control;
    }
}

Pro úpravy postupuj podobným způsobem. Něco přeci jen musím nechat na tobě :-)

Poslední věcí je, že potřebujeme zaregistrovat do konfigurace ty 2 rozhraní. Abychom měli v konfiguraci pořádek, doporučuji rozdělit soubor \app\config\config.neon na několik:

  • config.neon
  • config.component.neon
  • config.form.neon

Půjde hlavně o sekci "services". Obsah této sekce v config.neon bude nově jen tento:

services:
    - App\Model\UserManager
    router: App\RouterFactory::createRouter
    database: Dibi\Connection(%database%, "mysqli")
    database.panel: Dibi\Bridges\Tracy\Panel
    tracy.bar:
        setup:
            - @database.panel::register(@database)

Soubor config.component.neon obsahuje toto:

services:
    - App\Components\Users\IUsersGridFactory
    - App\Components\Users\IUserDetailFactory
    - App\Components\Users\IUserAddFactory
    - App\Components\Clients\IClientsGridFactory
    - App\Components\PasswordTypes\IPasswordTypesGridFactory
    - App\Components\Passwords\IPasswordsGridFactory

Počítám s tím, že interface se ti povedlo vytvořit pro všechny 4 tabulky :-)

No a obsah souboru config.form.neon je:

services:
    - App\Forms\FormFactory
    - App\Forms\SignInFormFactory
    - App\Forms\SignUpFormFactory

Sem jsme jen přesunuli to, co bylo v tom config.neon a týkalo se formulářů.

Lehkou změnou komponenty pro výpis uživatelů docílíme toho, že uživatel bude možné přidat a editovat. Doplň do metody createComponentGrid v komponentě UsersGrid následující řádky:

        $grid->addAction('UserDetail:', '')
            ->setIcon('pencil')
            ->setTitle('Upravit')
            ->setClass('btn btn-xs btn-info');

        $grid->addToolbarButton('UserAdd:', 'Přidat uživatele')
            ->setClass('btn btn-xs btn-success');

Všimni si, že ve výpisu uživatelů přibyla na každém řádku ikona s tužkou a v horním panelu tlačítko na přidání uživatele.

Ublaboo ale nabízí i jinou možnost úprav a přidání záznamů - inline přidání a inline editaci. Dejme tomu, že chceme přidávat i klienty. Tak to stačí do komponenty ClientsGrid vložit pár řádků:

        $grid->addInlineAdd()->setClass('btn btn-xs btn-success')->onControlAdd[] = function ($container) {
            $container->addText('id', '')->setAttribute('readonly');
            $container->addText('client_name', '');
            $container->addText('client_email', '');
            $container->addText('client_phone', '');
        };

        $p = $this;

        $grid->getInlineAdd()->onSubmit[] = function ($values) use ($p) {
            $insertModel = new InsertClient($this->db);
            $insertModel->insert($values);
            $p->redrawControl('grid');
        };

V případě editace je to o několik řádků navíc, protože ještě musíme předviplnit současná data:

        $grid->addInlineEdit()->setClass('btn btn-xs btn-info')->onControlAdd[] = function ($container) {
            $container->addText('id', '');
            $container->addText('client_name', '');
            $container->addText('client_email', '');
            $container->addText('client_phone', '');
        };

        $grid->getInlineEdit()->onSetDefaults[] = function ($container, $item) {
            $container->setDefaults(
                [
                    'id' => $item->id,
                    'client_name' => $item->client_name,
                    'client_email' => $item->client_email,
                    'client_phone' => $item->client_phone,
                ]
            );
        };

        $grid->getInlineEdit()->onSubmit[] = function ($id, $values) use ($p) {
            $updateModel = new UpdateClient($this->db);
            $updateModel->update($values);
            $p->redirect('this');
        };

Ještě můžeme ošetřit mazání záznamů. To provedeme jen signálem a handle metodou, takže nepotřebujeme žádný další presenter a šablonu. Například v gridu uživatelů jen přidej do definice grigu:

        $grid->addAction('delete', '', 'deleteUser!')
            ->setConfirm('Opravdu chcete smazat uživatele %s?', 'name')
            ->setIcon('trash')
            ->setTitle('Smazat')
            ->setClass('btn btn-xs btn-danger ajax');

A taky metodu, která signál zachytí a zpracuje:

    /**
     * @param integer $id
     */
    public function handleDeleteUser($id)
    {
        $deleteUserModel = new DeleteUser($this->db);
        $deleteUserModel->delete($id);

        if (!$this->presenter->isAjax()) {
            $this->presenter->redirect('this');
        }
        $this->redrawControl('grid');
    }

Opět upozorním, že všude používám modely určené ke konkrétní jedné činnosti, takže třeba DeleteUser, InsertClient atd.

Poslední věc, co si dnes ukážeme, je změna routeru tak, aby místo Homepage používal jako výchozí presenter Users. To je to nejjednodušší. Stačí změnit

$router[] = new Route('<presenter>/<action>', 'Homepage:default');

na

$router[] = new Route('<presenter>/<action>', 'Users:default');

Příště si aplikaci zabezpečíme, aby s ní mohli pracovat jen přihlášení uživatelé. Dnes toho ale bylo tolik, že si možná budeš chtít stáhnout aplikaci tak, jak vypadá k dnešnímu dni: Kapitola 6

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

Vzhled administrace a gridu

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

Aplikace na správu hesel

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

Přihlašování do aplikace

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