Symfony 2 podstawa

Jak napisać własną aplikację od zera

Utworzone przez Przemysław Kaczmarczyk / przemas.kaczmarczyk@gmail.com

Ramowy plan

  1. Bundle
  2. Kontrolery - akcje
  3. Routingi
  4. Encje
  5. Formularze
  6. Widoki
  7. Tłumaczenia
  8. Napiszmy tą apke !!!
  9. TESTY !!!

Generowanie Bundla

php app/console generate:bundle

Kontrolery

0 Logiki(w założeniu)

Ściąga dane z serwisów i wysyła je na widok

Listowanie

                            
                                /**
     * @Template
     * @return Response
     */
    public function listAction()
    {
        $paginator = $this->get('knp_paginator');
        /** @var Task[] $pagination */
        $pagination = $paginator->paginate($this->get('doctrine.orm.entity_manager')->getRepository('ToDoListBundle:Task')->findAll(), $this->get('request')->query->get('page', 1), 10);

        return ['pagination' => $pagination];
    }
                            
                        

Edycja

                            
                                /**
     * @Template
     * @ParamConverter("task",class="ToDoListBundle:Task")
     * @param  Request                                                  $request
     * @param  Task                                                     $task
     * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
     */
    public function editAction(Request $request, Task $task)
    {
        $form = $this->createForm(new TaskType(), $task, [
            'action' => $this->generateUrl('to_do_list_add'),
            'method' => 'POST',
        ]);

        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->get('doctrine.orm.entity_manager');
            $em->persist($task);
            $em->flush();

            return $this->redirect($this->generateUrl('to_do_list_list'));
        }

        return ['form' => $form->createView()];
    }
                            
                        

Dodawanie

                            
                                /**
     * @Template("ToDoListBundle:ToDoList:edit.html.twig");
     * @param  Request $request
     * @return array
     */
    public function addAction(Request $request)
    {
        $task = new Task();

        $form = $this->createForm(new TaskType(), $task, [
            'action' => $this->generateUrl('to_do_list_add'),
            'method' => 'POST',
        ]);

        $form->handleRequest($request);
        if ($form->isValid()) {
            $em = $this->get('doctrine.orm.entity_manager');
            $em->persist($task);
            $em->flush();

            return $this->redirect($this->generateUrl('to_do_list_list'));
        }

        return ['form' => $form->createView()];
    }
                            
                        

Usuwanie

                            
                                /**
     * @ParamConverter("task",class="ToDoListBundle:Task")
     * @param  Task                                               $task
     * @return \Symfony\Component\HttpFoundation\RedirectResponse
     */
    public function deleteAction(Task $task)
    {
        $em = $this->get('doctrine.orm.entity_manager');

        $em->getRepository("ToDoListBundle:Task");

        $em->remove($task);
        $em->flush();

        return $this->redirect($this->generateUrl('to_do_list_list'));
    }
                            
                        

Routingi

Odpowiadają na zapytanie z przeglądarki i wywołują akcje na kontrolerze

Resorces/config/routing.yml

                            
                            to_do_list_list:
    pattern: /
    defaults: { _controller: ToDoListBundle:ToDoList:list }

to_do_list_add:
    pattern: /add/
    defaults: { _controller: ToDoListBundle:ToDoList:add }

to_do_list_edit:
    pattern: /edit/{id}
    defaults: { _controller: ToDoListBundle:ToDoList:edit }


to_do_list_delete:
    pattern: /delete/{id}
    defaults: { _controller: ToDoListBundle:ToDoList:delete }
                            
                        

Encje i repozytorium

Encja - obiekt który ma być zrzutowany na bazę danych

Repo - obiekt który odpowiada za przeszukiwanie

Entity/Task.php

                                
                            
namespace Laborka\ToDoListBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use \DateTime;

/**
 * @ORM\Entity(repositoryClass="Laborka\ToDoListBundle\Repository\TaskRepository")
 * @ORM\Table(name="to_do_tasks",indexes={})
 */
class Task
{
    /**
     * @var int $id
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(name="id", type="integer", unique=true)
     */
    protected $id;

    /**
     * @var string $name
     * @ORM\Column(name="name", type="string", length=255, nullable=false)
     */
    protected $name;
    /**
     * @var bool $done
     * @ORM\Column(name="done", type="boolean")
     */
    protected $done;
    /**
     * @var DateTime $completeDate
     * @ORM\Column(name="complete_date", type="datetime")
     */
    protected $completeDate;
    }
                            
                        

Dołóżcie settery i gettery

Formularze

Tworzymy tu formularz który pozwoli nam zadecydować o części encji której modyfikacja jest dostępna dla użytkownika

                            
                                /**
     * @param FormBuilderInterface $builder
     * @param array                $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name','text',[
                    'label' => 'todolist.name'
                ])
            ->add('completeDate', 'datetime',[
                    'label' => 'todolist.complete_date'
            ])
            ->add('done', 'choice', [
                'required' => true,
                'choices'  => [
                    true  => 'todolist.done',
                    false => 'todolist.undone',
                ],
                'expanded' => true,
                'multiple' => false,
                'label' => false
            ])
            ->add('save', 'submit',[
                'label' => 'todolist.save'
            ])
        ;
    }
    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults([
            'data_class' => 'Laborka\ToDoListBundle\Entity\Task',
        ]);
    }
    /**
     * Returns the name of this type.
     *
     * @return string The name of this type
     */
    public function getName()
    {
        return 'to_do_list_task';
    }
                            
                        

Widoki

UI tu tworzymy interfejs użytkownika

list.html.twig

                            
                                {% extends "::base.html.twig" %}

{% block body %}
    
        {% for task in pagination %}
            
                {% if task.done %}
                    
                {% else %}
                    
                {% endif %}
                
        {% endfor %}
        
{{ "todolist.id"|trans }} {{ "todolist.name"|trans }} {{ "todolist.complete_date"|trans }} {{ "todolist.isdone"|trans }} {{ "todolist.edit"|trans }} {{ "todolist.delete"|trans }}
{{ task.id }} {{ task.name }} {{ task.completeDate.format('Y-m-d h:i') }}{{ "todolist.done"|trans }}{{ "todolist.undone"|trans }}{{ "todolist.edit"|trans }} {{ "todolist.delete"|trans }}
{{ knp_pagination_render(pagination) }} {{ "todolist.add"|trans }} {% endblock %}

edit.html.twig

                            
                                {% extends "::base.html.twig" %}

{% extends "::base.html.twig" %}

{% block body %}
    {{ form_start(form) }}
    {{ form_end(form) }}
{% endblock %}

                            
                        

Tłumaczenia

Łatwe tłumacznie podstawowych struktór aplikacji

YML !!

                            
todolist:
    add: Dodaj nowy task
    done: Zrobione
    undone: Niezrobione
    edit: Edytuj
    create: Utwórz
    delete: Usuń
    complete_date: Data ukończenia
    name: Nazwa zadania
    id: id
    isdone: Ukończenie
    save:zapisz

                            
                        

Piszemy apke

Nie ma co dalej opowiadać, zobaczcie to w praktyce

Testy

Łatwe zabezpieczenie żeby ktoś dopisując coś nie zepsuł naszej pracy

Funkcjonalne i jednostkowe

Jednostkowy EntityTest.php

                            
                                namespace Laborka\ToDoListBundle\Tests;

use Laborka\ToDoListBundle\Entity\Task;

class EntityTest extends \PHPUnit_Framework_TestCase
{
    public function testSetGetName()
    {
        $task = new Task();
        $testName = 'test_name';
        $task->setName($testName);
        $this->assertSame($testName, $task->getName());
    }
}
                            
                        

Funkcjonalny Controller/ToDoListControllerTest.php

                            
                                class ToDoListControllerTest extends WebTestCase
{
    /**
     * @var Client $client
     */
    protected $client = null;

    public function setUp()
    {
        $this->client = static::createClient();
    }

    public function testAddAction()
    {
        $crawler = $this->client->request('GET', $this->client->getContainer()->get('router')->generate('to_do_list_add', [], false));

        $this->assertSame($this->client->getResponse()->getStatusCode(), 200);

        $form = $crawler->filter("form[name='to_do_list_task']")->form();
        $form['to_do_list_task[name]'] = 'test_name';
        $form['to_do_list_task[done]'] = 1;
        $this->client->submit($form);
        $crawler = $this->client->followRedirect();
        $this->assertGreaterThanOrEqual($crawler->filter('test_name')->count(), 1);
    }
}
                            
                        

A na koniec konkurs ;)