Symfony

Symfony

Instalacja

Wymagania minimalne:

  • PHP 7.1.3
  • composer
composer create-project symfony/skeleton my_project

Title Text

$ > tree my_project
.
├── bin
│   └── console
├── config
│   ├── bundles.php
│   ├── routes.yaml
│   ├── services.yaml
│   └── packages
│       ├── framework.yaml
│       ├── routing.yaml
│       ├── dev
│       │   └── routing.yaml
│       └── test
│           └── framework.yaml
├── public
│   └── index.php
├── src
│   ├── Kernel.php
│   └── Controller
├── var
│   ├── cache
│   └── log
└── vendor

13 directories

bin/ - pliki wykonywalne CLI

config/ - pliki konfiguracyjne z podziałem na bundle i środowiska

public/ - publiczne assety, index.php

src/ - logika biznesowa aplikacji

var/ - przechowywanie plików tymczasowych

var/cache - skompilowane pliki statyczne (routing, di)

vendor/ - biblioteki zależności

$ > composer require annotations
$ > composer require symfony/maker-bundle --dev

Title Text

$ > php bin/console list make

 make:command            Creates a new console command class
 make:controller         Creates a new controller class
 make:entity             Creates a new Doctrine entity class
 [...]

https://symfony.com/doc/current/bundles/SymfonyMakerBundle

Pierwszy Controller

$ > php bin/console make:controller FirstController
> $ vim src/Controller/FirstController.php
<?php                                                                                                
                                                                                                     
namespace App\Controller;                                                                            
                                                                                                     
use Symfony\Component\Routing\Annotation\Route;                                                      
use Symfony\Bundle\FrameworkBundle\Controller\Controller;                                            
                                                                                                     
class FirstController extends Controller                                                             
{                                                                                                    
    /**                                                                                              
     * @Route("/first", name="first")                                                                
     */                                                                                              
    public function index()                                                                          
    {                                                                                                
        return $this->json([                                                                         
            'message' => 'Welcome to your new controller!',                                          
            'path' => 'src/Controller/FirstController.php',                                          
        ]);                                                                                          
    }                                                                                                
}                                                                                                                                                                                    

Controller pod Maską

use Symfony\Bundle\FrameworkBundle\Controller\Controller;                                            
                                                                                                     
class FirstController extends Controller  
// src/Controller/LuckyController.php
namespace App\Controller;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class LuckyController
{
    /**
     * @Route("/lucky/number/{max}", name="app_lucky_number")
     */
    public function number($max): Response
    {
        $number = random_int(0, $max);

        return new Response(
            '<html><body>Lucky number: '.$number.'</body></html>'
        );
    }
}

Controller pod Maską

use Symfony\Component\Routing\Annotation\Route;                                                      
//...                                                                                                    
    /**                                                                                              
     * @Route("/first", name="first")                                                                
     */                                                                                              
//...                                                                                                                                                                              
vendor/symfony/routing/Annotation/Route.php

Routing

    /**
     * @Route(
     *     "/hello/{_locale}/{year}/{slug}.{_format}",
     *     defaults={"_format": "html"},
     *     requirements={
     *         "_locale": "en|fr",
     *         "_format": "html|rss",
     *         "year": "\d+"
     *     }
     * )
     */
    public function hello($_locale, $year, $slug)
    {
    }

http://symfony.com/doc/current/routing.html

Pierwsza Komenda

$ > php bin/console make:command app:first
> $ vim src/Controller/FirstController.php
<?php

namespace App\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

class AppFirstCommand extends Command
{

    protected function configure()
    {
        // ...

    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // ...
    }
}

Komenda pod Maską

    protected static $defaultName = 'app:first';

    protected function configure()
    {
        $this
            ->setDescription('Add a short description for your command')
            ->addArgument('arg1', InputArgument::OPTIONAL, 'Argument description')
            ->addOption('option1', null, InputOption::VALUE_NONE, 'Option description')
        ;
    }

http://symfony.com/doc/current/console.html

http://symfony.com/doc/current/console/input.html

Komenda pod Maską

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $io = new SymfonyStyle($input, $output);
        $arg1 = $input->getArgument('arg1');

        if ($arg1) {
            $io->note(sprintf('You passed an argument: %s', $arg1));
        }

        if ($input->getOption('option1')) {
            // ...
        }

        $io->success('You have a new command! Now make it your own! Pass --help to see your options.');
    }

http://symfony.com/doc/current/console.html

Pierwsza Encja

$ > composer require orm
$ > composer require api
$ > cat .env
# ...
###> doctrine/doctrine-bundle ###
# Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
# Configure your db driver and server_version in config/packages/doctrine.yaml
DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name
###< doctrine/doctrine-bundle ###
$ > php bin/console doctrine:database:create
$ > php bin/console make:entity FirstEntity --api-resource
created: src/Entity/FirstEntity.php
created: src/Repository/FirstEntityRepository.php

Entity generated! Now let's add some fields!
You can always add more fields later manually or by re-running this command.

// Id is already created.
New property name (press <return> to stop adding fields):
> name
Field type (enter ? to see all types) [string]:
> string
Field length [255]:
>
Can this field be null in the database (nullable) (yes/no) [no]:
> no

https://symfony.com/doc/current/doctrine.html

Pierwsza Encja

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ApiResource()
 * @ORM\Entity(repositoryClass="App\Repository\FirstEntityRepository")
 */
class FirstEntity
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $name;

    // Setters ...
}

https://symfony.com/doc/current/doctrine.html

Crud Api

$ > composer require form
$ > bin/console make:crud FirstEntity

 created: src/Controller/FirstEntityController.php
 created: src/Form/FirstEntityType.php
 created: templates/first_entity/_delete_form.html.twig
 created: templates/first_entity/_form.html.twig
 created: templates/first_entity/edit.html.twig
 created: templates/first_entity/index.html.twig
 created: templates/first_entity/new.html.twig
 created: templates/first_entity/show.html.twig


  Success!


 Next: Check your new CRUD by going to /first/entity/

https://api-platform.com/docs/core/getting-started/

Crud pod Maską

$ > cat src/Controller/FirstEntityController.php
[...]
/**
 * @Route("/first/entity")
 */
class FirstEntityController extends Controller
{
    /**
     * @Route("/", name="first_entity_index", methods="GET")
     */
    public function index(FirstEntityRepository $firstEntityRepository): Response
    {
        return $this->render(
            'first_entity/index.html.twig',
             ['first_entities' => $firstEntityRepository->findAll()]
        );
    }

    /**
     * @Route("/new", name="first_entity_new", methods="GET|POST")
     */
    public function new(Request $request): Response
    {
        $firstEntity = new FirstEntity();
        $form = $this->createForm(FirstEntityType::class, $firstEntity);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($firstEntity);
            $em->flush();

            return $this->redirectToRoute('first_entity_index');
        }

        return $this->render('first_entity/new.html.twig', [
            'first_entity' => $firstEntity,
            'form' => $form->createView(),
        ]);
    }

    /**
     * @Route("/{id}", name="first_entity_show", methods="GET")
     */
    public function show(FirstEntity $firstEntity): Response
    {
        return $this->render(
            'first_entity/show.html.twig',
             ['first_entity' => $firstEntity]
        );
    }

    /**
     * @Route("/{id}/edit", name="first_entity_edit", methods="GET|POST")
     */
    public function edit(Request $request, FirstEntity $firstEntity): Response
    {
        $form = $this->createForm(FirstEntityType::class, $firstEntity);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->getDoctrine()->getManager()->flush();

            return $this->redirectToRoute(
                'first_entity_edit', 
                ['id' => $firstEntity->getId()]
            );
        }

        return $this->render('first_entity/edit.html.twig', [
            'first_entity' => $firstEntity,
            'form' => $form->createView(),
        ]);
    }

    /**
     * @Route("/{id}", name="first_entity_delete", methods="DELETE")
     */
    public function delete(Request $request, FirstEntity $firstEntity): Response
    {
        if (
            $this->isCsrfTokenValid('delete'.$firstEntity->getId(),
             $request->request->get('_token'))
        ) {
            $em = $this->getDoctrine()->getManager();
            $em->remove($firstEntity);
            $em->flush();
        }

        return $this->redirectToRoute('first_entity_index');
    }
}

https://api-platform.com/docs/core/getting-started/

Crud pod Maską

$ > cat src/Form/FirstEntityType.php
<?php

namespace App\Form;

use App\Entity\FirstEntity;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class FirstEntityType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name')
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => FirstEntity::class,
        ]);
    }
}

https://api-platform.com/docs/core/getting-started/

Crud pod Maską

$ > curl localhost/api
{"@context":"\/api\/contexts\/Entrypoint","@id":"\/api","@type":"Entrypoint","firstEntity":"\/api\/first_entities"}

https://api-platform.com/docs/core/operations

Własny system Autoryzacji

$ > composer require security
$ > php bin/console make:auth AppCustomAuthenticator
$ > vim config/packages/security.yaml
security:
    # ...

    providers:
        your_db_provider:
            entity:
                class: App\Entity\User
                property: apiKey
   firewalls:
        # ...
        main:
            anonymous: ~
            logout: ~
            guard:
                authenticators:
                    - App\Security\AppCustomAuthenticator

https://symfony.com/doc/current/security/guard_authentication.html

https://security.symfony.com/

Symfony

By Paweł Radzikowski

Symfony

  • 284