Symfony workshop p2

 

We will connect our front end.
And make a simple API for note entity.

 

We will need a new Symfony project.

(Preferable v3)

 

app/ - The application configuration, templates and translations.
bin/ - Executable files (e.g. bin/console).
src/ - The project's PHP code.
tests/ - Automatic tests (e.g. Unit tests).
var/ - Generated files (cache, logs, etc.).
vendor/ - The third-party dependencies.
web/ - The web root directory.

 

Symfony installer will generate for us AppBundle, with default index action.

 
/**
* @Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
   return $this->render('default/index.html.twig');
}

Let's create our template in

src/AppBundle/Resources/views/Default/index.html.twig

 
{% extends 'base.html.twig' %}

{% block stylesheets %}
    <link href="{{ asset('bower_components/Materialize/dist/css/materialize.min.css') }}" 
          rel="stylesheet">
{% endblock %}

{% block javascripts %}
    <script src="{{ asset('bower_components/jquery/dist/jquery.min.js') }}"></script>
    <script src="{{ asset('bower_components/materialize/dist/js/materialize.min.js') }}"></script>
    <script src="{{ asset('bower_components/angular/angular.min.js') }}"></script>
    <script src="{{ asset('assets/app.js') }}"></script>
    <script src="{{ asset('assets/templates.js') }}"></script>
{% endblock %}

{% block body %}
    <div ng-app="app" class="grey lighten-3" ng-controller="IndexController">
        <navigation></navigation>
        .......
    </div>
{% endblock %}
/**
 * @Route("/", name="homepage")
 */
public function indexAction()
{
    return $this->render('AppBundle:Default:index.html.twig');
}

And we will change our controller

 

Now we should move our .js files to AppBundle.

 

src/AppBundle/Resources/js

 

We have moved js source files, therefore, we should also change gulp paths

 
var JS_SOURCE_PATH = 'src/AppBundle/Resources/js/';
var DESTINATION = 'web/assets/';

gulp.task('concat:js', function () {
    return gulp.src([
            JS_SOURCE_PATH + '*.module.js',
            JS_SOURCE_PATH + '*.js'
        ])
        .pipe(concat('app.js'))
        .pipe(gulp.dest(DESTINATION))
        ;
});

Don't forget to do the same for templates

 

Now after gulp build, we will be able to see our app again.

 

Let's create our first entity.

You should have, working MySQL server and it should be configured in parameters.yml

 

We will be using a command line interface tool (bin/console)

 

Just simply type in your console:

 
php bin\console doctrine:generate:entity

You will be prompted for some information

name: AppBundle:Note
columns: title, content (strings)

At the end, you will have generated class at src/AppBundle/Entity/Note

 

So what about schema?

 

We can create a database with console tool:

 
php bin\console doctrine:database:create

But we want more, let's use Doctrine Migrations library.

 
 composer require doctrine/doctrine-migrations-bundle
$bundles = array(
    //...        
    new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),    
);

Enable it in app/AppKernel

 

Doctrine migrations?

So what we can do now?

 
doctrine:migrations
  :diff     Generate a migration by comparing your current database to your mapping information.
  :execute  Execute a single migration version up or down manually.
  :generate Generate a blank migration class.
  :migrate  Execute a migration to a specified version or the latest available version.
  :status   View the status of a set of migrations.
  :version  Manually add and delete migration versions from the version table.

That way we will generate a schema for our note table. You can find them in app/DoctrineMigrations folder

 
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate

Check you database you should have note and migration_versions table created.

 

We are ready to go!

Let's create some API!

 
php app/console generate:controller
    (name: AppBundle:Note)
    (Routing format: annotation)

We will put it in a new controller NoteContoller

 

Serializer

 

Serializer is a Symfony component, it helps to normalize objects.

It is shipped with symfony framework so we just need to activate it

1
# app/config/config.yml
framework:
    #......
    serializer:
      enabled: true
public function indexAction()
{
    // ...

    $serializer = $this->get('serializer');
    $notesNormalized = $serializer->normalize($notes);

    // ...
}

Get notes

 
/**
 * @Route("/note", name="note_get_all")
 * @Method("GET")
 */
public function getAllAction()
{
    $noteRepository = $this->getDoctrine()->getManager()
                        ->getRepository(Note::class);

    $notes = $noteRepository->findAll();

    $notesNormalized = $this->get('serializer')->normalize($notes);
    return new JsonResponse($notesNormalized);
}

Create note

 
/**
 * @Route("/note", name="note_create")
 * @Method("POST")
 */
public function createAction(Request $request)
{
    $payload = json_decode($request->getContent(),true);

    $note = new Note();
    $note->setTitle($payload['title']);
    $note->setContent($payload['content']);

    $em = $this->getDoctrine()->getManager();
    $em->persist($note);
    $em->flush();

    $noteNormalized = $this->get('serializer')->normalize($note);
    return new JsonResponse($noteNormalized);
}

Update note

 
/**
 * @Route("/note/{id}", name="note_update")
 * @Method("PUT")
 */
public function updateAction(Request $request, Note $note)
{
    $payload = json_decode($request->getContent(),true);

    $note->setTitle($payload['title']);
    $note->setContent($payload['content']);

    $em = $this->getDoctrine()->getManager();
    $em->persist($note);
    $em->flush();

    $noteNormalized = $this->get('serializer')->normalize($note);
    return new JsonResponse($noteNormalized);
}

Delete note

 
/**
 * @Route("/note/{id}", name="note_delete")
 * @Method("DELETE")
 */
public function deleteAction(Note $note)
{
    $em = $this->getDoctrine()->getManager();

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

    return new JsonResponse([]);
}

Symfony2 workshop week 2

By Semyon Radionov