Foto galerie

Rudolf Svátek 2016-07-22 13:32

Jestli chceš, stáhni si celou aplikaci po dnešní kapitola: kapitola14.zip.

Galerie jsou celkem užitečná věc. Vyhledávače pozitivně hodnotí stránky, které kromě kvalitního textu, nabízejí také nějaká multimedia. Uděláme si tedy administraci obrázků a jejich řazení do galerií. Bude to rošku jiné než dosud, protože budeme potřebovat spolupráci dvou tabulek.

Pravidlo je, že do jedné tabulky se ukládají jen data, která spolu souvisí. Jedna tabulka tedy bude ukládat informace o galeriích - jejich název a popis. Samotné obrázky, která chceme do galerie vložit, ale musíme ukládat do jiné tabulky. Tam uložíme název obrázku, popisek a identifikátor galerie, do které patří.

Dnes tedy budeme vytvářet 2 modely. Jeden pro galerie, druhý pro obrázky.

Gallery

Jelikož dědíme od Base tříd a neřešíme nic speciálního, stačí zase základ - Entity a její interface kopíruje pole tabulky Galleries, Mapper a Repository má jen konstruktor

IGalleriesEntity.php

<?php

namespace App\Model;

interface IGalleriesEntity 
{

   public function id();

   public function name();

   public function description();

   public function url();

}

GalleriesEntity.php

<?php

namespace App\Model;

class GalleriesEntity extends \Nette\Object implements IGalleriesEntity
{

   private $id;
   private $name;
   private $description;
   private $url;

    public function id($id = null) {
        if (!is_null($id))
            $this->id = $id;
        return $this->id;
    }

    public function name($name = null) {
        if (!is_null($name))
            $this->name = $name;
        return $this->name;
    }

    public function description($description = null) {
        if (!is_null($description))
            $this->description = $description;
        return $this->description;
    }

    public function url($url = null) {
        if (!is_null($url))
            $this->url = $url;
        return $this->url;
    }

}

GalleriesMapper.php

<?php

namespace App\Model;
 
use Dibi\Connection;

/**
 * Class GalleriesMapper
 * @package App\Model
 */
class GalleriesMapper extends BaseMapper 
{
 
	/**
	 * GalleriesMapper constructor.
	 * @param Connection $db
	 */
	public function __construct(Connection $db) {
		parent::__construct($db);
	}
 
}

GalleriesRepository.php

<?php

namespace App\Model;

/**
 * Class GalleriesRepository
 * @package App\Model
 */
class GalleriesRepository extends BaseRepository 
{

	/** @var GalleriesMapper */
	private $mapper;

	/**
	 * GalleriesRepository constructor.
	 * @param GalleriesMapper $mapper
	 */
	public function __construct(GalleriesMapper $mapper) {
		parent::__construct($mapper);
		$this->mapper = $mapper;
	}

}

Pro vytvoření galerie vytvoříme továrnu formuláře:

<?php

namespace App\Forms;

use App\Model\GalleriesRepository;
use App\Model\GalleriesEntity;
use Nette\Application\UI\Form;
use Nette\Utils\Strings;
use Kdyby\BootstrapFormRenderer\BootstrapRenderer;

/**
 * Class AddGalleriesFormFactory
 * @package App\Forms
 */
class AddGalleriesFormFactory
{

	/** @var FormFactory */
	private $factory;
  
	/** @var GalleriesRepository */
	private $galleriesRepository;
  
	public function __construct(FormFactory $factory, GalleriesRepository $galleriesRepository) {
		$this->factory = $factory;
		$this->galleriesRepository = $galleriesRepository;
	}

	/**
	 * @return Form
	 */
	public function create() {
		$form = $this->factory->create();

		$form->addText('name', 'Název')
			->setAttribute('class', 'form-control input-sm')
			->setAttribute('placeholder', 'Název');
		$form->addText('description', 'Popis')
			->setAttribute('class', 'form-control input-sm')
			->setAttribute('placeholder', 'Popis');
		$form->addSubmit('save', 'Odeslat')
			->setAttribute('class', 'btn btn-primary');

		$form->setRenderer(new BootstrapRenderer);
		$form->getElementPrototype()->class('form-horizontal');

		$form->onSuccess[] = function (Form $form) {
			$this->formSucceeded($form);
		};
		return $form;
	}

	/**
	 * @param Form $form
	 */
	public function formSucceeded(Form $form) {
		$values = $form->getValues();
		$galleries = new GalleriesEntity;
		$galleries->name($values->name);
		$galleries->description($values->description);
		$galleries->url(Strings::webalize($values->name));
		$this->galleriesRepository->save($galleries);
	}

}

Nic překvapivého. Prostě formulář s ošetřením po odeslání. Podobně je to s formulářem pro editaci:

<?php

namespace App\Forms;

use App\Model\GalleriesRepository;
use App\Model\GalleriesEntity;
use Nette\Application\UI\Form;
use Nette\Utils\Strings;
use Kdyby\BootstrapFormRenderer\BootstrapRenderer;

/**
 * Class EditGalleriesFormFactory
 * @package App\Forms
 */
class EditGalleriesFormFactory
{

	/** @var FormFactory */
	private $factory;
  
	/** @var GalleriesRepository */
	private $galleriesRepository;
  
	public function __construct(FormFactory $factory, GalleriesRepository $galleriesRepository) {
		$this->factory = $factory;
		$this->galleriesRepository = $galleriesRepository;
	}

	/**
	 * @return Form
	 */
	public function create() {
		$form = $this->factory->create();

		$form->addHidden('id', 'ID');
		$form->addText('name', 'Název')
			->setAttribute('class', 'form-control input-sm')
			->setAttribute('placeholder', 'Název');
		$form->addText('description', 'Popis')
			->setAttribute('class', 'form-control input-sm')
			->setAttribute('placeholder', 'Popis');
		$form->addSubmit('save', 'Odeslat')
			->setAttribute('class', 'btn btn-primary');

		$form->setRenderer(new BootstrapRenderer);
		$form->getElementPrototype()->class('form-horizontal');

		$form->onSuccess[] = function (Form $form) {
			$this->formSucceeded($form);
		};
		return $form;
	}

	/**
	 * @param Form $form
	 */
	public function formSucceeded(Form $form) {
		$values = $form->getValues();
		/** @var GalleriesEntity $galleries */
		$galleries = $this->galleriesRepository->get($values->id);
		$galleries->name($values->name);
		$galleries->description($values->description);
		$galleries->url(Strings::webalize($values->name));
		$this->galleriesRepository->save($galleries);
	}

}

V presenteru musíme vytvořit komponentu pro výpis galerií s možnostmi vložení nové, plus úpravy a smazání existující galerie. Na začátku presenteru jen načtu repositář a továrny formulářů:

<?php

namespace App\AdminModule\Presenters;

use App\Model\GalleriesRepository;
use Grido\Grid;
use App\Forms\EditGalleriesFormFactory;
use App\Forms\AddGalleriesFormFactory;
use Nette\Utils\Html;

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

	/** @var GalleriesRepository @inject */
	public $galleriesRepository;

	/** @var EditGalleriesFormFactory @inject */
	public $editGalleriesFormFactory;

	/** @var AddGalleriesFormFactory @inject */
	public $addGalleriesFormFactory;

	/**
	 * Inicializace třídních proměnných
	 */
	public function startup() {
		parent::startup();
	}

Grid pro výpis vypadá tak, jak jsme zvyklí. Je tam i odkaz na editaci a mazání galerie. V této chvíli ale ještě nejsou v presenteru metody, které by to ošetřili. Ty přidáme za chvíli, ale teď prostě vlož:

	/**
	 * @param $name
	 * @return Grid
	 * @throws \Grido\Exception
	 */
	protected function createComponentGrid($name) {
		$grid = new Grid($this, $name);
		$grid->translator->lang = 'cs';

		$fluent = $this->galleriesRepository->getAll();
		$grid->model = $fluent;

		$grid->addColumnText('id', 'ID')
			->setSortable();
		$grid->getColumn('id')->headerPrototype->style['width'] = '1%';

		$grid->addColumnText('name', 'Název')
			->setSortable()
			->setFilterText();
		$grid->getColumn('name')->headerPrototype->style['width'] = '25%';

		$grid->addColumnText('description', 'Popis')
			->setSortable()
			->setFilterText();
		$grid->getColumn('description')->headerPrototype->style['width'] = '40%';

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

		$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;
			});

		$grid->setDefaultPerPage(50);
		$grid->filterRenderType = $this->filterRenderType;
		$grid->setExport();

		return $grid;
	}

Ať na to nezapomeneme, tak doplň rovnou ty 2 funkce pro ošetření editace a mazání:

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

	/**
	 * @param $id
	 */
	public function handleDelete($id) {
		$this->galleriesRepository->delete($id);
		$this->flashMessage('Galerie byla smazána.', 'success');
		if (!$this->isAjax())
			$this->redirect('default');
		$this->redrawControl();
	}

Do configu doplň služby. Pro zjednodušení vypíšu i služby druhého modulu Pictures, ať se k tomu už nemusíme vracet:

	- App\Forms\EditGalleriesFormFactory
	- App\Forms\AddGalleriesFormFactory
	- App\Forms\EditPicturesFormFactory
	- App\Forms\AddPicturesFormFactory
	galleriesMapper: App\Model\GalleriesMapper
	- App\Model\GalleriesRepository(@galleriesMapper)
	picturesMapper: App\Model\PicturesMapper
	- App\Model\PicturesRepository(@picturesMapper)

Poslední jsou opět šablony. Pro výpis gridu stačí default.latte:

{block content}
	<div class="row">
		<div class="col-sm-12 form-group">
			<a n:href="Galleries:add" class="btn btn-success btn-sm">
				<span class="glyphicon glyphicon-plus"></span> {_"Přidat galerii"}
			</a>
		</div>
	</div>
	{snippet grid}
		{control grid}
	{/snippet}
{/block}

{block title}{_'Administrace galerií'} |&nbsp;{/block}

Je tam odkaz na přidání galerie. Ovšem metoda, která by připravila formulář pro přidání a také editaci, ještě v presenteru není, takže při zobrazení stránky by to teď hlásilo chybu. Rychle to napravíme. Uprav presenter tak, že přidáš metody pro vytvoření komponent s formuláři:

	/**
	 * @return Form
	 */
	protected function createComponentEditForm() {
		$form = $this->editGalleriesFormFactory->create();
		$form->onSuccess[] = function () {
			$this->flashMessage('Galerie byla upravena.', 'success');
			$this->redirect('default');
		};
		return $form;
	}

	/**
	 * @return Form
	 */
	protected function createComponentAddForm() {
		$form = $this->addGalleriesFormFactory->create();
		$form->onSuccess[] = function () {
			$this->flashMessage('Galerie byla vytvořena.', 'success');
			$this->redirect('default');
		};
		return $form;
	}

Pokud si vytvoříš šablonu pro vložení nové galerie, a rovnou i pro editaci, bude to všechno. Pokud se na to stále ještě necítíš, stáhni si celou aplikaci za dnešek.

Teď už si můžeš přidat nějakou galerii. Jdi na adresu:

http://localhost:8000/admin/galleries/

Klikni si na přidání galerie a vyplň ten jednoduchý formulář. Po odeslání by ses měl vrátit do výpisu a vidíš jednu galerii.

Pictures

Samotné galerie jsou k ničemu, pokud v nich nejsou obrázky. Proto upravíme systém tak, že v editaci galerie budeme mít možnost vypsat, přidat, editovat a mazat obrázky. Takže jdi do editace té přidané galerie a budeme upravovat kódy.

Už je to asi nuda, ale zopakuji to - potřebujeme model, formuláře, služby, presenter a šablony. V modulu opět zatím neřešíme nic speciálního a tak stačí základ:

IPicturesEntity.php

<?php

namespace App\Model;

interface IPicturesEntity 
{

   public function id();

   public function name();

   public function description();

   public function file();

   public function order();

   public function gallery_id();

}

PicturesEntity.php

<?php

namespace App\Model;

class PicturesEntity extends \Nette\Object implements IPicturesEntity
{

   private $id;
   private $name;
   private $description;
   private $file;
   private $order;
   private $gallery_id;

    public function id($id = null) {
        if (!is_null($id))
            $this->id = $id;
        return $this->id;
    }

    public function name($name = null) {
        if (!is_null($name))
            $this->name = $name;
        return $this->name;
    }

    public function description($description = null) {
        if (!is_null($description))
            $this->description = $description;
        return $this->description;
    }

    public function file($file = null) {
        if (!is_null($file))
            $this->file = $file;
        return $this->file;
    }

    public function order($order = null) {
        if (!is_null($order))
            $this->order = $order;
        return $this->order;
    }

    public function gallery_id($gallery_id = null) {
        if (!is_null($gallery_id))
            $this->gallery_id = $gallery_id;
        return $this->gallery_id;
    }

}

PicturesMapper.php

<?php

namespace App\Model;
 
use Dibi\Connection;

/**
 * Class PicturesMapper
 * @package App\Model
 */
class PicturesMapper extends BaseMapper 
{
 
	/**
	 * PicturesMapper constructor.
	 * @param Connection $db
	 */
	public function __construct(Connection $db) {
		parent::__construct($db);
	}
 
}

PicturesRepository.php

<?php

namespace App\Model;

/**
 * Class PicturesRepository
 * @package App\Model
 */
class PicturesRepository extends BaseRepository 
{

	/** @var PicturesMapper */
	private $mapper;

	/**
	 * PicturesRepository constructor.
	 * @param PicturesMapper $mapper
	 */
	public function __construct(PicturesMapper $mapper) {
		parent::__construct($mapper);
		$this->mapper = $mapper;
	}

}

Příště už model, pokud je v základním tvaru, asi nebudu vypisovat. Vidíš, že se vlastně liší jen názvy. Služby v configu už máme, takže další jsou na řadě formuláře pro přidání a úpravy obrázků:

<?php

namespace App\Forms;

use App\Model\PicturesRepository;
use App\Model\PicturesEntity;
use Nette\Application\UI\Form;
use Kdyby\BootstrapFormRenderer\BootstrapRenderer;

/**
 * Class AddPicturesFormFactory
 * @package App\Forms
 */
class AddPicturesFormFactory
{

	/** @var FormFactory */
	private $factory;
  
	/** @var GalleriesRepository */
	private $galleriesRepository;
  
	public function __construct(FormFactory $factory, PicturesRepository $picturesRepository) {
		$this->factory = $factory;
		$this->picturesRepository = $picturesRepository;
	}

	/**
	 * @return Form
	 */
	public function create() {
		$form = $this->factory->create();

		$form->addText('name', 'Název')
			->setAttribute('class', 'form-control input-sm')
			->setAttribute('placeholder', 'Název');
		$form->addText('description', 'Popis')
			->setAttribute('class', 'form-control input-sm')
			->setAttribute('placeholder', 'Popis');
		$form->addText('file', 'Obrázek')
			->setAttribute('class', 'form-control input-sm')
			->setAttribute('placeholder', 'Obrázek')
			->setAttribute('onclick', 'openKCFinder(this)');
		$form->addText('order', 'Pořadí')
			->setAttribute('class', 'form-control input-sm')
			->setAttribute('placeholder', 'Pořadí');
		$form->addHidden('gallery_id');
		$form->addSubmit('save', 'Odeslat')
			->setAttribute('class', 'btn btn-primary');

		$form->setRenderer(new BootstrapRenderer);
		$form->getElementPrototype()->class('form-horizontal');

		$form->onSuccess[] = function (Form $form) {
			$this->formSucceeded($form);
		};
		return $form;
	}

	/**
	 * @param Form $form
	 */
	public function formSucceeded(Form $form) {
		$values = $form->getValues();
		/** @var PicturesEntity $pictures */
		$pictures = new PicturesEntity();
		$pictures->name($values->name);
		$pictures->description($values->description);
		$pictures->file($values->file);
		$pictures->order($values->order);
		$pictures->gallery_id($values->gallery_id);
		$this->picturesRepository->save($pictures);
	}

}

U přidávání obrázku se zmíním jen o políčku gallery_id, které v sobě nese informaci o galerii, do které obrázek bude patřit. Editační formulář je zase velmi podobný:

<?php

namespace App\Forms;

use App\Model\PicturesRepository;
use App\Model\PicturesEntity;
use Nette\Application\UI\Form;
use Kdyby\BootstrapFormRenderer\BootstrapRenderer;

/**
 * Class EditPicturesFormFactory
 * @package App\AdminModule\Presenters
 */
class EditPicturesFormFactory
{

	/** @var FormFactory */
	private $factory;
  
	/** @var PicturesRepository */
	private $picturesRepository;
  
	public function __construct(FormFactory $factory, PicturesRepository $picturesRepository) {
		$this->factory = $factory;
		$this->picturesRepository = $picturesRepository;
	}

	/**
	 * @return Form
	 */
	public function create() {
		$form = $this->factory->create();

		$form->addHidden('id', 'ID');
		$form->addText('name', 'Název')
			->setAttribute('class', 'form-control input-sm')
			->setAttribute('placeholder', 'Název');
		$form->addText('description', 'Popis')
			->setAttribute('class', 'form-control input-sm')
			->setAttribute('placeholder', 'Popis');
		$form->addText('file', 'Obrázek')
			->setAttribute('class', 'form-control input-sm')
			->setAttribute('placeholder', 'Obrázek')
			->setAttribute('onclick', 'openKCFinder(this)');
		$form->addText('order', 'Pořadí')
			->setAttribute('class', 'form-control input-sm')
			->setAttribute('placeholder', 'Pořadí');
		$form->addHidden('gallery_id');
		$form->addSubmit('save', 'Odeslat')
			->setAttribute('class', 'btn btn-primary');

		$form->setRenderer(new BootstrapRenderer);
		$form->getElementPrototype()->class('form-horizontal');

		$form->onSuccess[] = function (Form $form) {
			$this->formSucceeded($form);
		};
		return $form;
	}

	/**
	 * @param Form $form
	 */
	public function formSucceeded(Form $form) {
		$values = $form->getValues();
		/** @var PicturesEntity $pictures */
		$pictures = $this->picturesRepository->get($values->id);
		$pictures->name($values->name);
		$pictures->description($values->description);
		$pictures->file($values->file);
		$pictures->order($values->order);
		$pictures->gallery_id($values->gallery_id);
		$this->picturesRepository->save($pictures);
	}

}

Ale jak do té galerie obrázek dostat? No, upravíme šablonu pro výpis galerií tak, aby se zobrazil další grid s výpisem obrázků. Bude tam i tlačítko pro přidání dalšího obrázku. Samozřejmě to bude předpokládat i úpravu presenteru, kdy definujeme grid obrázků, vytvoříme komponenty formulářů a ošetříme vyplnění výchozích hodnot formuláře. Uprav tedy v pesenteru:

<?php

namespace App\AdminModule\Presenters;

use App\Model\GalleriesRepository;
use App\Model\PicturesRepository;
use Grido\Grid;
use App\Forms\EditGalleriesFormFactory;
use App\Forms\AddGalleriesFormFactory;
use App\Forms\EditPicturesFormFactory;
use App\Forms\AddPicturesFormFactory;
use Nette\Utils\Html;

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

	/** @var GalleriesRepository @inject */
	public $galleriesRepository;

	/** @var PicturesRepository @inject */
	public $picturesRepository;

	/** @var EditGalleriesFormFactory @inject */
	public $editGalleriesFormFactory;

	/** @var AddGalleriesFormFactory @inject */
	public $addGalleriesFormFactory;

	/** @var EditPicturesFormFactory @inject */
	public $editPicturesFormFactory;

	/** @var AddPicturesFormFactory @inject */
	public $addPicturesFormFactory;

Tím importujeme služby a můžeme používat formuláře i repository. Následuje vložení funkcí pro vyplnění výchozích údajů při zobrazení formuláře:

	/**
	 * @param int $id
	 */
	public function renderAddPicture($id = 0) {
		/** @var Form $form */
		$form = $this['addPictureForm'];
		if (!$form->isSubmitted()) {
			$row['gallery_id'] = $id;
			$form->setDefaults($row);
		}
	}

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

Také potřebujeme ale vytvořit komponenty těch dvou formulářů:

	/**
	 * @return Form
	 */
	protected function createComponentEditPictureForm() {
		$form = $this->editPicturesFormFactory->create();
		$form->onSuccess[] = function ($form) {
			$this->flashMessage('Obrázek byl upraven.', 'success');
			$this->redirect('Galleries:edit', $form->values->gallery_id);
		};
		return $form;
	}

	/**
	 * @return Form
	 */
	protected function createComponentAddPictureForm($id) {
		$form = $this->addPicturesFormFactory->create();
		$form->onSuccess[] = function ($form) {
			$this->flashMessage('Obrázek byl vložen.', 'success');
			$this->redirect('Galleries:edit', $form->values->gallery_id);
		};
		return $form;
	}

No a samozřejmě taky ten grid obrázků:

	/**
	 * @param $name
	 * @return Grid
	 * @throws \Grido\Exception
	 */
	protected function createComponentGridPictures($name) {
		$grid = new Grid($this, $name);
		$grid->translator->lang = 'cs';

		$fluent = $this->picturesRepository->getAllWhere(['gallery_id' => $this->getParameter('id')]);
		$grid->model = $fluent;

		$grid->addColumnText('id', 'ID')
			->setSortable();
		$grid->getColumn('id')->headerPrototype->style['width'] = '1%';

		$grid->addColumnText('name', 'Název')
			->setSortable()
			->setFilterText();
		$grid->getColumn('name')->headerPrototype->style['width'] = '25%';

		$grid->addColumnText('file', 'Soubor')
			->setSortable()
			->setFilterText();
		$grid->getColumn('file')->headerPrototype->style['width'] = '40%';

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

		$grid->addActionEvent('deletePicture', '')
			->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("deletePicture!", $item->id))
					->setHtml($i);
				return $el;
			});

		$grid->setDefaultPerPage(50);
		$grid->filterRenderType = $this->filterRenderType;
		$grid->setExport();

		return $grid;
	}

Také obrázek půjde smazat. Metoda, která to zajistí je:

	/**
	 * @param $id
	 */
	public function handleDeletePicture($id) {
		$picture = $this->picturesRepository->get($id);
		$this->picturesRepository->delete($id);
		$this->flashMessage('Obrázek byl odstraněn z galerie.', 'success');
		$this->redirect('Galleries:edit', $picture->gallery_id());
	}

Přemýšlel jsem, jestli budu mazat i přímo soubory, které jsem nahrál na server, když je odstraním z databáze. Ale není to dobrý nápad, protože jeden obrázek mohu používat v několika galeriích, nebo jej použít u nějaké stránky, případně vložit jej do nějakého textu. Při smazání souboru by samozřejmě zmizel odevšad.

Připojení galerie ke stránce

Galerii máme, nějaké obrázky jsi už taky jistě doplnil, takže můžeme si říct, že by bylo fajn u nějaké stránky zobrazit jednu, či více galerií. Proto máme v PagesEntity pole galleriesIds. Sem budeme ukládat identifikátory galerií, které chceme ke stránce vázat. Jo, uvědomuji si, že to jde lépe. Také taková informace by měla být v jiné tabulce a přísahám na holý pupík, že časem to jistě upravím, aby to bylo čistější řešení. Zatím se musíš spokojit s tím, co ti tu předvedu, nebo to udělat samostatně jinak.

Tak začneme tím, že se vrátíme k fromuláři pro editaci stránek, čili EditPageFormFactory.php. Dodáme závislosti na GalleriesRepository tak, že upravíme začátek:

<?php

namespace App\Forms;

use App\Model\PagesEntity;
use App\Model\PagesRepository;
use App\Model\GalleriesRepository;
use Nette\Application\UI\Form;
use Nette\Utils\DateTime;
use Nette\Utils\Strings;
use Kdyby\BootstrapFormRenderer\BootstrapRenderer;

/**
 * Class EditPageFormFactory
 * @package App\Forms
 */
class EditPageFormFactory
{

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

	/** @var PagesEntity */
	private $page;

	/** @var PagesRepository */
	private $pagesRepository;

	/** @var GalleriesRepository */
	private $galleriesRepository;

	public function __construct(FormFactory $factory, 
			PagesRepository $pagesRepository, 
			GalleriesRepository $galleriesRepository) {
		$this->factory = $factory;
		$this->pagesRepository = $pagesRepository;
		$this->galleriesRepository = $galleriesRepository;
	}

Potřebujeme nějak načíst seznam galerií, tak uvnitř funkce create() doplníme:

	public function create(PagesEntity $page) {
		$form = $this->factory->create();

		$galleries = $this->galleriesRepository->getAll()
				->fetchPairs('id', 'name');
		

Získaný seznam galerií pak nabídneme v selectboxu. Přidej tedy definici dalšího pole formuláře:

		$form->addMultiSelect('galleryIds', 'Svázané galerie', $galleries)
				->setAttribute('class', 'form-control input-sm select2')
				->setAttribute('placeholder', 'Galerie');

Zase lehce upozorním na to, že toto pole formuláře dostalo třídu "select2". Je to kvůli tomu, že použijeme javascriptovou knihovnu select2, která příjemně upraví box s výběrem. Poslední věc ve formuláři je, že ve funkci formSubmitted doplníme řádek pro uložení vybraných galerií:

$this->page->galleryIds(json_encode($values->galleryIds));

Ať to má nějaký datový formát, ukládám to v json. Kdybychom zobrazovali šablonu jen jednoduchým makrem s názvem formulářové komponenty, stačilo by to. My ale vykreslujeme šablonu ručně, takže ještě upravíme app\AdminModule\presenters\templates\Pages\edit.latte tak, že dodáme pole s výběrem galerií. Je na tobě kam to dáš. Já to vložil třeba vedle tlačítka pro volby aktivní/neaktivní:

<div class="form-group">
	<div class="col-sm-6">
		<div class="col-lg-12 input-group">
		  <span class="input-group-addon">
			 <a href="javascript:void(0)" title="Galerie" data-toggle="popover"
				 data-trigger="focus"
				 data-content="Ke stránce může být přidružena jedna či více galerií.">
				<i class="glyphicon glyphicon-picture"></i>
			 </a>
		  </span>
			{input galleryIds}
		</div>
	</div>
	<div class="col-sm-2">
		<input type="checkbox" n:name=active data-off-icon-cls="glyphicon-thumbs-down"
				 data-on-icon-cls="glyphicon-thumbs-up" data-group-cls="btn-group-xs">
		<label n:name=active> Aktivní</label>
	</div>

Ještě musíme naučit presenter, aby pracoval s galeriemi. Takže injectneme službu v PagesPresenter.php:

use App\Model\GalleriesRepository;

class PagesPresenter extends BasePresenter
{

	/** @var  GalleriesRepository @inject */
	public $galleriesRepository;

Dál upravíme metodu pro vyplnění editačního formuláře tak, že doplníme vyplnění galerií:

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

No a to je zhruba asi všechno. Jak využít toho, že je ke stránce fotogalerie přiřazena, k tomu se dostaneme, až budu řešit frontend. Zatím budeme ještě chvíli v administraci.

Jestli chceš, stáhni si celou aplikaci po dnešní kapitola: kapitola14.zip.

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

Nastavení aplikace

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

Zapomenutá hesla

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