Doulat Meah

0
Recently, accumulating a request for assistance in creating a blog because the earlier instructions based on my perspective obsolete version Nette and also utilizes the database layer Dibi, which beginners may not immediately understand. Since I was little, I would like to offer you instructions on how to create  the same  blog , but in the new version .

I will invent a new bike, so I'll stick to the older operating in terms of functionality and appearance. Therefore, some texts will (with your permission) copied from the author PJK and some adapted to the "new coat". Enough bragging, we begin to form our first blog.

Introduction - How to create a blog



I think represent what a blog and what is not worth it. Everyone knows him or ever heard of him. In order to create a blog using the Nette framework, it is first necessary to download . That precedes the installation of Apache (or other web server), MySQL (or other database) and PHP hopefully not have to mention, their installation perhaps another time. Before we begin Nette library record on the web, it is advisable to find out using the  checker (located in the download package Nette in the Tools / Requirements-Checker /) if our server supports Nette.

We will build the sandbox, which again can be found in the download package Nette. Original content template  default.latte  (directory app / templates / homepage /) so we can safely delete.

Database and model



Let's start with creating the appropriate tables. Their structure is clear from the brief. So run on our database the following commands:


CREATE TABLE `posts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(128) COLLATE utf8_bin NOT NULL,
`body` text COLLATE utf8_bin NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
This will create a table with articles.

CREATE TABLE `comments` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`post_id` INT NOT NULL ,
`author` VARCHAR( 128 ) NOT NULL ,
`body` TEXT NOT NULL ,
`date` DATETIME NOT NULL,
INDEX (post_id),
FOREIGN KEY (post_id) REFERENCES posts(id)
) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_bin;



And this (surprisingly) a table of comments. Just a reminder, as it is clear from the code, it needs to be enabled on your server the ability to create a structure using the InnoDB storage engine (otherwise you this blog will not work).

Now that we have created the database structure, you need to connect it to the net. First we start with the file  config.neon (directory app / config /). To successfully connect, you need to fill in the login information to the database. You fill in the database section:


database:
dsn: 'mysql:host=localhost;dbname=nazevDatabaze'
user: uzivatelskyUcet
password: heslo



Furthermore there is a need for our repository, respectively. models, to register as a service. In the Services section, we already have pre-filled the three services and we will add them to the other two:


services:
authenticator: Authenticator
routerFactory: RouterFactory
router: @routerFactory::createRouter
posts: PostsRepository
comments: CommentsRepository



By our role in the config over and we can move on to creating repositories. First, we can create the ancestor of all other repositories, which will inherit from it and so will need to write over and over again to connect to the database. So let's make a repository called  Repository :


abstract class Repository extends NetteObject {

/** @var NetteDatabaseConnection */
protected $connection;

public function __construct(NetteDatabaseConnection $db) {
$this->connection = $db;
}
}



Next, let's create a repository for both tables from the database:


class PostsRepository extends Repository {

public function fetchAll() {
return $this->connection->table('posts')
->order('date DESC');
}

class CommentsRepository extends Repository {

public function fetchArticleComments($post_id) {
return $this->connection->table('comments')
->where('post_id = ?', $post_id);
}



For clarity, the moment will their methods without undue respects to pull all available data. All three classes definition files saved in the folder / app / model and name them according to the class that contains (Repository.php, PostsRepository.php, CommentsRepository.php).

Presenter



V / app / presenters / is HomepagePresenter. It will serve as a good basis for our efforts. Add to it a method that takes data from the model and passes them to the template to render.

Homepage will look like this:


class HomepagePresenter extends BasePresenter {

/** @var PostsRepository */
private $postsRepository;

/** @var CommentsRepository */
private $commentsRepository;

public function inject(PostsRepository $postsRepository, CommentsRepository $commentsRepository) {
$this->postsRepository = $postsRepository;
$this->commentsRepository = $commentsRepository;
}

public function renderDefault() {
$this->template->posts = $this->postsRepository->fetchAll();
}
}



Perhaps it would be appropriate for me to explain a bit. First you need to create a private variable that will insert links to our repository. Next, using  Dependency Injection  inject method  inject our already registered services to variables. This gave us the opportunity to use all the methods of our repositories, as in the case of method  fetchAll from the repository PostsRepository.

View


The last part of the MVC pattern is the view or the view. He is Nette reprezetován as a template, respectively. Latte template. Now we are in the default view on the variable $ posts, which includes all posts. Let's dump.

In the folder / app / templates is soubor@layout.latte. It contains the basic framework of all the sites that we create. Therefore, I suggest you look at it.

V / app / templates / Homepage default.latte the file that contains the block definition content, the content of which will replace the {include} # content in the layout. List of all articles might look like this:


{block content}
<h1>Můj blogísek</h1>
<div id="posts">
{if count($posts)}
{foreach $posts as $post}
<div>
<h3>{$post['title']}</h3>
<small>Přidáno {$post['date']|date}</small>
<p>{$post['body']|truncate:300}</p>
</div>
{/foreach}
{else}
Zatím nebyl napsán žádný článek.
{/if}
</div>
{/block}


Download test data , load them into the database and try to open the root site in your browser. The result should look like this:

 



Let me spoil the joy obligatory bit of theory:


  • Used commands in curly brackets are called macros Latte filter and the more you learn about them in the documentation.

  • Notice the part {$ post ['date'] | date} . Ono date for the vertical bar (pipe, if you will) is a helper . Helper is a simple function that performs a variable with Danni operations essential for the view.


Comments


It does not even hurt and it took only a few minutes, but the blog is about communicating with people. Therefore, we need to add the ability to comment on posts. The classical approach is that on the front page displays only the beginning of the text referring to the entire text, which is also the opportunity to comment. Let's get to it. As an independent view post has nothing to do with the title page, we add to our preseneru new method:

    public function renderSingle($id) {
$this->template->post = $this->postsRepository->fetchSingle($id);
}

And create an appropriate method PostsRepository:

    public function fetchSingle($id) {
return $this->connection->table('posts')
->where('id = ?', $id)
->fetch();
}

We also need to create a template for this request, so to / app / templates / homepage / single.latte insert:

{block content}
<a n:href="Homepage:">&lt;&lt; home </a>
<div>
<h1>{$post['title']}</h1>
<small>Přidáno {$post['date']|date}</small>
<p>{$post['body']}</p>
</div>

Now you can try to open the browser must be / Homepage/single/2.



Links


To get here and the current user, we need some links from the main page. You can use the macro n: href. Redo therefore view the cover page default.latte to:

{block content}
<h1>Můj blogísek</h1>
<div id="posts">
{if count($posts)}
{foreach $posts as $post}
<div>
<h3>{$post['title']}</h3>
<small>Přidáno {$post['date']|date}</small>
<p>{$post['body']|truncate:300}</p>
<a n:href="Homepage:single $post['id']">Více…</a>
</div>
{/foreach}
{else}
Zatím nebyl napsán žádný článek.
{/if}
</div>
{/block}

Note that instead of HTML href attribute we used n: macros n: href. Its value then there is no URL, as would be the case in the href attribute, but right actions presenter. After clicking on the link will take you to the word method HomepagePresenter :: renderSingle () as a parameter $ id will be passed to the value of $ post ['id'].



In our regular minutovce theory would now like to highlight two things:


  • Note truncate helper: 300 and its effect.

  • URL is re-created to match routám in bootstrap.php and our application is thus on its shape completely independent.


Form


Finally, we come to something "záživnějšímu" - let's create a form to send comments! Nette has several ways to solve a form of hard-coding of the template to a separate processing inputs sophisticated methods such as Form.Class Form offers advantages, many of which are not even dreamed of. Our form will be a separate component. When it comes to creating components using " Tovarnícka "that the production of components in the moment when it is really needed. Do HomepagePresenter add a clause to use two functions:

use NetteApplicationUI;

    public function createComponentCommentForm() {
$form = new UIForm();
$form->addText('author', 'Jméno: ')
->addRule($form::FILLED, 'To se neumíš ani podepsat?!');
$form->addTextArea('body', 'Komentář: ')
->addRule($form::FILLED, 'Komentář je povinný!');
$form->addSubmit('send', 'Odeslat');
$form->onSuccess[] = callback($this, 'commentFormSubmitted');
return $form;
}

public function commentFormSubmitted(UIForm $form) {
$data = $form->getValues();
$data['date'] = new DateTime();
$data['post_id'] = (int) $this->getParam('id');
$id = $this->commentsRepository->insert($data);
$this->flashMessage('Komentář uložen!');
$this->redirect("this");
}

The first of these processes the submitted form (note the redirection to ensure that the user has not posted form multiple times by clicking the Refresh button), the second is referred Tovarnícka.

It is worth calling $ this-> flashMessage (, Comment saved! '). Nette contains the little news flash, which are short messages that inform the user about the current state of the application. By default, are written in, @ layout.latte '.

Do CommentsRepository we need to add the method used:

    public function insert($data) {
$this->connection->table('comments')
->insert($data);
}

And we must not forget to pass on all comments to the appropriate contribution to the template, so renderSingle method in the presenter modify Homepage:

    public function renderSingle($id) {
if (!($post = $this->postsRepository->fetchSingle($id))) {
$this->error('Článek nebyl nalezen'); //pokud clanek neexistuje, presmerujeme uzivatele
}
$this->template->post = $post;
$this->template->comments = $this->commentsRepository->fetchArticleComments($id);
}

The last thing left is to finish our templates single.latte:

{block content}
<a n:href="Homepage:">&lt;&lt; home </a>
<div>
<h1>{$post['title']}</h1>
<small>Přidáno {$post['date']|date}</small>
<p>{$post['body']}</p>
</div>

<h3>Komentáře:</h3>
<div id="comments">
{if $comments}
{foreach $comments as $comment}
<p>{$comment['body']}</p>
<small>{$comment['author']}, {$comment['date']|date}</small>
<hr>
{/foreach}
{else}
Ke článku zatím nebyly napsány žádné komentáře. Buďte první!
{/if}
</div>

{control commentForm}

Note that the form itself finds its way into the template and is drawn. Try sending the form blank. As you can see, Nette brought Javascript validation to our form.But validation takes place on the server side so that Javascript turned off will not affect its functionality.



And that's it, simple huh? I hope I explained everything clearly and you understand some of the basics. If someone was still something unclear, let me hear in the comments.

Complete source code can be downloaded here:https://github.com/Draffix/blog/archive/v1.zip

Post a Comment

 
Top