DEV Community

Mert Simsek
Mert Simsek

Posted on • Edited on

Serializer Component with Symfony

This post leads to use Serialization in our projects. But What's the serialization and who needs that? We will answer these needful questions. They are help us to understand that obviously. Well, let's start.

What's the serialization?

For developers; It's transforming an object to a formatted string. We would have textual, JSON, XML. On the other hand, binary formats. Generally, we develop REST Apis commonly. Whereas, different programming languages and different machines should stay in touch each other by our REST Apis endpoints. At this point, serialization truly works for us.

Who needs serialization?

As a developer, we are able to refer this way. Initially, we send or receive data when we develop a REST Api. It should be strict format to manage all of communication. The most common use case is queue systems. We figure out queue systems with serialization. Other thing might be testing. We are able to detect some changes. Plus, If we want to store data in database instead of having columns with fields. We can have only one field for all data. If I need to give some instances, they might be like Redis, Elasticsearch.

How it works?

Here is the architecture of how it works.

alt text

-- Normalizers --
First of all, there is an object format. Normalizers are obviously classes that to convert objects to an array. Array structure is easily understand and manipulate.

-- Encoders --
These classes are convert from array to the claimed format. Or, claimed formatted to array.

Well, from now on we are able to start writing some codes. I am going to give some tips about that. For this, I installed the component.

composer require symfony/serializer -vvv
Enter fullscreen mode Exit fullscreen mode

After that, I added my configuration lines in framework.yamlfile.

framework:
    serializer:
        enabled: true
        enable_annotations: true
Enter fullscreen mode Exit fullscreen mode

I've adjusted the configuration. Now, I wrote my first code.

<?php

namespace App\Controller;

use App\Entity\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface;

class UserController extends AbstractController
{
    /**
     * @Route("/user", name="user")
     * @param SerializerInterface $serializer
     * @return JsonResponse
     */
    public function index(SerializerInterface $serializer)
    {

        $user = new User();
        $user->setFullname('Mert Simsek')
            ->setCity('İstanbul')
            ->setEmail('mertsmsk0@gmail.com')
            ->setPhone('+90-000-000-00-00')
            ->setCreatedAt(new \DateTime('2019-02-25 00:00:00'));

        $serializedUser = $serializer->serialize($user,'json');

        return JsonResponse::fromJsonString($serializedUser);

    }
}
Enter fullscreen mode Exit fullscreen mode

I implement the serializer interface and I convert the claimed format. The response is going to be like this.

alt text

At the moment, I would like to highlight some features. First of all is groups. Picture that, you've all of these columns; fullname, phone, city etc. But you don't want to provide all of them. At this point, "groups" helps us. How? Like this. You write "groups" line each propery of the entity as below.

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
 */
class User
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @Groups({"phone","web"})
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"phone","web"})
     */
    private $fullname;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"phone","web"})
     */
    private $city;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"phone"})
     */
    private $phone;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"phone","web"})
     */
    private $email;

    /**
     * @ORM\Column(type="datetime")
     * @Groups({"phone","web"})
     */
    private $createdAt;

    // at this point, there are getters and setters...

}
Enter fullscreen mode Exit fullscreen mode

Now, we can serialize with this "groups" defining. As you see, If I serialize with "web" group, the phone property is not going to appear us. Because, the phone property is appearing for only "phone group". Let's see.

$user = new User();
$user->setFullname('Mert Simsek')
    ->setCity('İstanbul')
    ->setEmail('mertsmsk0@gmail.com')
    ->setPhone('+90-000-000-00-00')
    ->setCreatedAt(new \DateTime('2019-02-25 00:00:00'));

$serializedUser = $serializer->serialize($user,'json', ['groups' => ['web']]);

return JsonResponse::fromJsonString($serializedUser);

Enter fullscreen mode Exit fullscreen mode

How my response appears? Here you are.

alt text

As you see, anymore we cannot see the phone property. Now let's check it out the other formats. For instance, xml? I changed the format from json to xml.

$user = new User();
$user->setFullname('Mert Simsek')
    ->setCity('İstanbul')
    ->setEmail('mertsmsk0@gmail.com')
    ->setPhone('+90-000-000-00-00')
    ->setCreatedAt(new \DateTime('2019-02-25 00:00:00'));

$serializedUser = $serializer->serialize($user,'xml', ['groups' => ['web']]);

return JsonResponse::fromJsonString($serializedUser);

Enter fullscreen mode Exit fullscreen mode

Immediately, we make sure the result.

alt text

Or csv... For this thime, of course, I converted to xml to csv.

alt text

I would like to mention about other one feature. It's Name Convertor. If we need to change from camelCase to snake_case, we just add this line into configuration.

framework:
    serializer:
        enabled: true
        enable_annotations: true
        name_converter: serializer.name_converter.camel_case_to_snake_case
Enter fullscreen mode Exit fullscreen mode

From now on, the created at property is going to be snake_case formatted.

alt text

To Sum Up

I would like to thank all of you for reading till this point. Serializer Component has plenty of feature. Specially, when you develop the REST Apis, it truly helps you.

Top comments (9)

Collapse
 
shnby780 profile image
Mehmet Şahin

Merhaba, symfonyde bir konuda kafayı yemek üzereyim. Yardımcı olabilir misiniz?

Collapse
 
_mertsimsek profile image
Mert Simsek

Merhaba,

Tabiki, nedir sorun?

Collapse
 
shnby780 profile image
Mehmet Şahin • Edited

Symfonyde ajax ile veritabanından veri getirmeye çalışıyorum ama bir türlü yapamadım. Yapmak istediğim, kullanıcı profil sayfasına kullanıcının paylaştığı postları ajax ile getirmek.

profile.html.twig

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

{% block title %}User{% endblock %}

{% block body %}

<div class="profile-lasts"></div>

<script>

        $(document).ready(function () {
            $.ajax({
                url: '{{ path('show_user_posts') }}',
                type: 'post',
                dataType: 'json',
                contentType: 'application/json',
                async: true,
                data: {
                    'userid': {{ app.user.id }}
                },
                success: function(data) {
                    $.each(data, function () {
                        $(".profile-lasts").prepend("<table><tr><td>Username</td><td>Content</td><td>Creadted at</td></tr><tr><td>"+this.username+"</td><td>"+this.content+"</td><td>"+this.createdAt+"</td></tr></table>");
                    });
                }
            });
        });
    </script>
{% endblock %}

PostController.php

<?php

namespace App\Controller;

use App\Entity\Post;
use App\Entity\User;
use App\Form\PostType;
use App\Repository\PostRepository;
use App\Repository\UserRepository;
use phpDocumentor\Reflection\Types\Array_;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface;

/**
 * @Route("/post")
 */
class PostController extends AbstractController
{
    /**
     * @Route("/show", name="show_user_posts", methods={"GET","POST"})
     */
    public function show(Request $request, UserRepository $userRepository, PostRepository $postRepository, SerializerInterface $serializer): Response
    {
        if ($request->isXmlHttpRequest()){
            $userid = $_POST['userid'];
            if (!empty($userid)){
                $user = $userRepository->findBy(['id' => $userid]);
                $posts = $postRepository->findBy(['user' => $user[0]]);

                return new JsonResponse($posts);
            }
            return new JsonResponse('userid null');
        }

        return new JsonResponse('not xmlhttprequest');
    }
}

Post.php

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use phpDocumentor\Reflection\Types\Integer;

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

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="posts")
     */
    private $user;

    /**
     * @ORM\Column(type="text", nullable=true)
     */
    private $content;

    /**
     * @ORM\Column(type="string", length=75, nullable=true)
     */
    private $image;

    /**
     * @ORM\Column(type="string", length=10, nullable=true)
     */
    private $likecounter;

    /**
     * @ORM\Column(type="string", length=10, nullable=true)
     */
    private $dislikecounter;

    /**
     * @ORM\Column(type="string", length=10, nullable=true)
     */
    private $commentcounter;

    /**
     * @ORM\Column(type="string", length=10, nullable=true)
     */
    private $status;

    /**
     * @ORM\Column(type="datetime", nullable=true)
     */
    private $created_at;

    /**
     * @ORM\Column(type="datetime", nullable=true)
     */
    private $updated_at;

Bir haftadır bu sorun ile uğraşıyorum, yardımcı olabilirseniz çok sevinirim. Mezun olmadan önce projemi bitirmek istiyorum.

Thread Thread
 
_mertsimsek profile image
Mert Simsek

Sorun ne, hata mı alıyorsun?

Thread Thread
 
shnby780 profile image
Mehmet Şahin

Failed to load resource: the server responded with a status of 500 ()

bu hatayı veriyor

Thread Thread
 
_mertsimsek profile image
Mert Simsek

Bence github'a at, public repo olarak, öyle bakalım. Bu şekilde debug edemeyiz.

Thread Thread
 
shnby780 profile image
Mehmet Şahin

tamam atıyorum.

Thread Thread
 
shnby780 profile image
Mehmet Şahin

aslında github kullanmayı bilmiyorum, denedim ama yapamadım.

Thread Thread
 
shnby780 profile image
Mehmet Şahin

hallettim sorunumu. teşekkür ederim ilgilendiğiniz için.