Instalace Nette Frameworku

Nastavení webového serveru

Vyvýjený web bys měl někde provozovat. Pokud nemáš nějaký server jako třeba Apache, je nejjednodušší ve složce se staženou aplikací spustit vlastní server příkazem:

php -S localhost:8000​

Po zadání adresy `http://localhost:8000` do prohlížeče pak uvidíš úvodní stranu. Ovšem ukazuje se, že v některých případech se stránky chovají jinak, než na normálním webservru, takže doporučuji spíš vytvořit nový virtuální hosting na svém lokálním webovém serveru.

Pokud Apache nebo jiný webový server provozuješ, asi víš, jak přidat další web, nebo virtualhost.

Já třeba používám Windows a balík Wamp a tam je to otázkou několika kliknutí myší.

Instalace Nette

Nejsnadnější způsob instalace Nette je pomocí composeru. Pokud ho nemáš, pořiď si ho. Pro stažení vzorového projektu by stačilo (ale nedělej to) zadat příkaz:

composer create-project nette/web-project rsrs.loc

Ve složce, ve které jsi, se vytvoří složka rsrs.loc a do ní se zkopíruje vzorový projekt Nette. Nicméně s tím, jak se nainstaloval spokojeni nebudeme. V tuto chvíli je venku Nette 3.0, ale moc si nerozumí s Doctrine 2. Zůstaneme tedu zatím u verze 2.4. Navíc vzorový projekt není modulární, což my bychom chtěli mít. Výhodou modulárnosti je, že můžeš vyvinout jednou nějaký modul a jednoduše pak zkopírovat celou složku do jiného projektu a všechno funguje.

Čili všechno si nataháme a nakonfigurujeme ručně. Bude to sice víc práce, ale aspoň pochopíme hned od začátku celý princip a všechny vzájemné souvislosti.

Takže předpokládám, že máš složku, na kterou ukazuje Apache server jako na hlavní složku webu. Já mám složku rsrs.loc a tak budu používat v celém seriálu tento název.

Nahrajeme si nette příkazem:

composer require nette/nette 2.4

Dotáhneme balík pro práci s Doctrine 2. Tady poděkuji tvůrcům balíku Kdyby. Čili následuje příkaz:

composer require kdyby/doctrine

Vytvoříme si doporučenou strukturu složek:

rsrs.loc/
├── app/
│   ├── config/
│   ├── router/
├── log/
├── src/
├── temp/
├── vendor/
└── www/

Ve složce "config" vytvoříme postupně 2 soubory. První bude sloužit pro obecnou konfiguraci a bude se jmenovat common.neon:

parameters:

application:
	errorPresenter: Error
	mapping:
		Error: App\Presenters\*Presenter
		*: *Module\*Presenter

session:
	expiration: 14 days

services:
    routerFactory: App\RouterFactory(%createdRoutes%)
    router: @routerFactory::createRouter

extensions:
    console: Kdyby\Console\DI\ConsoleExtension
    events: Kdyby\Events\DI\EventsExtension
    annotations: Kdyby\Annotations\DI\AnnotationsExtension
    doctrine: Kdyby\Doctrine\DI\OrmExtension
    base: BaseModule\DI\BaseExtension
    homepage: HomepageModule\DI\HomepageExtension

console:
    url: http://www.kdyby.org

doctrine:
    user: user
    password: '***'
    dbname: project
    metadata:
        App: %appDir%
        Src: %appDir%/../src

Za zmínku stojí sekce mapping. Tam nastavíme pravidla, která později použijeme pro mapování prezenterů. Pak už je to celkem klasika - registrace rozšíření pro Doctrine, konfigurace doctrine a tak.

Pak ještě druhý konfigurační soubor s názvem local.neon. Ten bude obsahovat konfiguraci toho, co je pro projekt individuální. Bude to zejména připojení k databázi:

doctrine:
    host: localhost
    user: root
    password: tajneheslo
    dbname: rsrs
    metadata:
        App: %appDir%
        Src: %appDir%/../src

Samozřejmě, že si nejprve vytvoříš databázi rsrs a pokud máš jiné heslo pro uživatele root, tak si dej do své konfigurace to své :-). Navíc tento soubor nebude součástí archivů, které si budeš moci postupně stahovat. Počítej s tím.

Dalším krokem je vytvoření souboru Booting.php ve složce app. Měl by vypadat takto:

<?php

declare(strict_types=1);

namespace App;

use Nette\Configurator;

class Booting
{
    public static function boot(): Configurator
    {
        $configurator = new Configurator;

        //$configurator->setDebugMode(false); // enable for your remote IP
        $configurator->enableTracy(__DIR__ . '/../log');

        $configurator->setTimeZone('Europe/Prague');
        $configurator->setTempDirectory(__DIR__ . '/../temp');

        $configurator->createRobotLoader()
            ->addDirectory(__DIR__)
            ->addDirectory(__DIR__ . '/../src')
            ->register();

        $configurator->addConfig(__DIR__ . '/config/common.neon');
        $configurator->addConfig(__DIR__ . '/config/local.neon');

        return $configurator;
    }
}

Je to vlastně skoro identický obsah, jaký je ve vzorovém Nette projektu. Jen jsem tam přidal řádek, který ve funkci createRobotLoader() prochází i složku "src". Jinak asi žádné překvapení.Teď je na řadě výroba routeru. V configu říkáme, kde se má router hledat, ale zatím ho nemáme, takže ve složce router vyrob soubor RouterFactory.php s obsahem:

<?php

declare(strict_types=1);

namespace App;

use Nette;
use Nette\Application\Routers\RouteList;

class RouterFactory
{
    /**
     * @var RouteList
     */
    private $router;

    /**
     * RouterFactory constructor.
     *
     * @param array $createdRoutes
     */
    public function __construct($createdRoutes)
    {
        $this->router = new RouteList();

        foreach ($createdRoutes as $routeList) {
            $this->addRouteList($routeList);
        }
    }

    /**
     * Add routelist to router
     *
     * @param RouteList $routeList
     */
    private function addRouteList($routeList)
    {
        $this->router[] = $routeList;
    }

    /**
     * @return Nette\Application\IRouter
     */
    public function createRouter()
    {
        $router = $this->getRouter();
        return $router;
    }

    /**
     * Returns current router
     *
     * @return RouteList
     */
    public function getRouter()
    {
        return $this->router;
    }
}

Jde o továrnu, kterou budeme využívat při psaní jednotlivých modulů k tomu, abychom doplnili potřebná pravidla pro routování. V tuto chvíli vlastně nemusíme vědět, kolik a jaké moduly budeme používat - stránky, příspěvky, komentáže apod. Routy tedy budeme přidávat až ve chvíli, kdy budeme vědět jaké budou zapotřebí.

Dnes ještě vytvoříme 2 moduly a rozchodíme základní aplikaci. Prvním modulem bude Base Modul, ze kterého budou ostatní dědit. Napíšeme ho jako rozšíření, takže bude dědit z CompilerExtension. Takže ve složce src vytvoř složku BaseModule. Prozatím v ní budeme potřebovat jen složku DI a v ní pak vytvoříme soubor BaseExtension.php. Máme v plánu vytvořit metodu, která k už známým routám doplní další. Obsahem BaseModule.php tedy bude:

<?php

namespace BaseModule\DI;

use Nette;

class BaseExtension extends Nette\DI\CompilerExtension
{

    /**
     * Inserts route list to current router
     *
     * @param string $routelist
     * @param string $routemask
     * @param string $destination
     */
    protected function appendRoute($routelist, $routemask, $destination)
    {

        $newRouteList = new Nette\Application\Routers\RouteList($routelist);
        $newRoute = new Nette\Application\Routers\Route($routemask, $destination);
        $newRouteList[] = $newRoute;

        $builder = $this->getContainerBuilder();
        $builder->parameters['createdRoutes'][] = $newRouteList;
    }
}

Metoda je celkem jednoduchá a pochopit se snad dá z toho, jak je napsaná. Máme tedy základní třídu, ze které další moduly budou dědit. Prvním modulem bude Homepage Modul. Bude mít na starosti vytvoření routy pro zobrazení homepage a také namapování jejího prezenteru.

Zase tě tedy čeká vytvoření složky HomepageModule ve složce src. Až jí vyrobíš, opět v ní vytvoř složku DI. Uvnitř DI pak soubor HomepageExtension.php, který bude vypadat takto:

<?php

namespace HomepageModule\DI;

use BaseModule\DI\BaseExtension;
use Nette;

class HomepageExtension extends BaseExtension
{

    public function loadConfiguration()
    {
        $this->appendRoute('Homepage:Front', '<presenter>/<action>', 'Homepage:default');
    }

    /**
     * Method beforeCompile
     *
     * @throws \Nette\DI\ServiceCreationException
     */
    public function beforeCompile()
    {
        $builder = $this->getContainerBuilder();
        $builder->getDefinition($builder->getByType(Nette\Application\IPresenterFactory::class))->addSetup(
            'setMapping',
            [['Homepage' => 'HomepageModule\*Module\Presenters\*Presenter']]
        );
    }
}

Na vysvětlení: metoda loadConfiguration() se spouští automaticky. V ní tedy vytvoříme novou routu, která bude ukazovat na prezenter Homepage. Důležité je, že aplikaci ještě plánujeme rozdělit na část Front a Admin. Namespace prezenterů tedy bude třeba:

namespace HomepageModule\FrontModule\Presenters;

V základním configu nevíme, jaký modul bude či nebude existovat, takže tam mapovat konkrétní prezenter nemůžeme. Proto je tu další metoda beforeCompile(), ve které nastavíme mapování konkrétního prezenteru. Elegantní řešení, které nám umožní vzít celý modul a zkopírovat jej do jiného projektu. Všechno pak funguje "samo"

Tedy ne úplně - musíme samozřejmě zaregistrovat rozšíření, které jsme právě vyrobili. Stačí přidat do config.neon 2 řádky do sekce extensions:

    base: BaseModule\DI\BaseExtension
    homepage: HomepageModule\DI\HomepageExtension

Potřebujeme ještě ten Homepage presenter, jeho šablonu default.latte a taky šablonu @layout.latte. Všechno si to můžeš půjčit ze vzorového nette projektu a prostě zkopírovat složku app/Presenters do složky HomepageModule. Jen pak musíš nastavit tu namespace v presenteru na

namespace HomepageModule\FrontModule\Presenters;

Předposlední věc je nahrát soubor Booting.php při startu aplikace. Požádáme autoload, aby to udělal za nás. Stačí upravit soubor composer.json a přidat sekci autoload takto:

{
    "require": {
        "nette/nette": "2.4",
        "kdyby/doctrine": "^3.3"
    },
    "autoload": {
        "classmap": [
            "app/Booting.php"
        ]
    }
}

Následuje příkaz, kterým vše aktulizujeme a upravíme ten autoload:

composer update

Poslední věc je vytvoření souboru index.php ve složce www:

<?php

declare(strict_types=1);

require __DIR__ . '/../vendor/autoload.php';

App\Booting::boot()
    ->createContainer()
    ->getByType(Nette\Application\Application::class)
    ->run();

Ten už jen nahraje autoload a spustí celou aplikaci.

Aby to fungovalo, musí apache ukazovat na složku www jako na DocumentRoot. V mém případě třeba:

DocumentRoot "c:/wamp64/www/rsrs.loc/www"

A to je dnes vše. Pokud jsi postupoval krok za krokem, měl bys v prohlížeči vidět úvodní stránku Nette projektu.

Příště si vyrobíme databázi a připojíme se k ní. Upravíme taky tu homepage tak, aby se už něco dělo.

A kdyby se ti dnes něco nepovedlo, stáhni si celou aplikaci: rsrs-kapitola-1

Celý seriál o vývoji redakčního systému

Komentáře

O mně

Jmenuji se Rudolf Svátek - lektor výpočetní techniky, trochu PHP programátor a SEO konzultant na volné noze.

Adresa

Příčná 326/3
736 01 Havířov

Kontakty

Email: office@rudolfsvatek.cz
Telefon: +420 777 828 353
Skype: svatekr