ZetCode

Symfony Service tutorial

last modified July 5, 2020

Symfony service tutorial shows how to create a service in Symfony. The service fetches data from a database.

Symfony

Symfony is a set of reusable PHP components and a PHP framework for web projects. Symfony was published as free software in 2005. The original author of Symfony is Fabien Potencier. Symfony was heavily inspired by the Spring Framework.

Symfony service

The functionality of a Symfony application is divided into smaller chunks called services. A service is a PHP object. Services live in a Symfony service container. There are many built-in services. Services can be autowired in a Symfony application by using type hints.

A list of available services is generated with the php bin/console debug:container command.

# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
    resource: '../src/*'
    exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'

This is a piece of a services.yaml configuration file. The PHP classes in the src directory can be automatically injected into our code via type hints.

Symfony service example

In the following example, we fetch data from a MySQL database. The data retrieval is delegated to a specific application component: a Symfony service.

$ symfony new symservice
$ cd symservice

We create a new Symfony skeleton project and locate to the newly created project directory.

$ composer req annot orm-pack

We install three modules: annotations and orm-pack.

$ composer req maker --dev

We install the the Symfony maker component.

countries_mysql.sql
CREATE TABLE countries(id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, 
    name VARCHAR(100), population INT);

INSERT INTO countries(name, population) VALUES('China', 1382050000);
INSERT INTO countries(name, population) VALUES('India', 1313210000);
INSERT INTO countries(name, population) VALUES('USA', 324666000);
INSERT INTO countries(name, population) VALUES('Indonesia', 260581000);
INSERT INTO countries(name, population) VALUES('Brazil', 207221000);
INSERT INTO countries(name, population) VALUES('Pakistan', 196626000);
INSERT INTO countries(name, population) VALUES('Nigeria', 186988000);
INSERT INTO countries(name, population) VALUES('Bangladesh', 162099000);
INSERT INTO countries(name, population) VALUES('Nigeria', 186988000);
INSERT INTO countries(name, population) VALUES('Russia', 146838000);
INSERT INTO countries(name, population) VALUES('Japan', 126830000);
INSERT INTO countries(name, population) VALUES('Mexico', 122273000);
INSERT INTO countries(name, population) VALUES('Philippines', 103738000);

This is some test data. It creates a small table in MySQL. We can execute the file with the MySQL source command.

config/packages/doctrine.yaml
... 
doctrine:
    dbal:
        # configure these for your database server
        driver: 'pdo_mysql'
        server_version: '5.7'
        charset: utf8mb4
        default_table_options:
            charset: utf8mb4
            collate: utf8mb4_unicode_ci 
...

By default, we have a MySQL database configured for Doctrine DBAL. Doctrine Database Abstraction Layer (DBAL) is an abstraction layer that sits on top of PDO and offers an intuitive and flexible API for communicating with the most popular relational databases.

.env
...
DATABASE_URL=mysql://user12:s$cret@localhost:3306/mydb

In the .env file, we configure the database URL.

$ php bin/console make:controller MyController

A MyController is created with bin/console.

src/Controller/MyController.php
<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use App\Service\CountryService;

class MyController extends AbstractController
{
    /**
     * @Route("/countries", name="countries")
     */
    public function index(CountryService $countryService)
    {
        $countries = $countryService->findAll();
        
        return $this->json([
            'countries' => $countries
        ]);  
    }
}

The MyController returns all rows from the countries table in a JSON format. It uses the CountryService service.

public function index(CountryService $countryService)
{

The CountryService is created via parameter injection.

src/Service/CountryService.php
<?php

namespace App\Service;

use Doctrine\DBAL\Driver\Connection;
use App\Repository\CountryRepository;

class CountryService 
{
    private $countryRepository;

    public function __construct(CountryRepository $countryRepository) 
    {
        $this->countryRepository = $countryRepository;
    }

    /**
     * Finds all countries
     */
    public function findAll() {

        $data = $this->countryRepository->findAll();

        return $data;
    }
}

The CountryService uses the CountryRepository to fetch data.

public function __construct(CountryRepository $countryRepository) 
{
    $this->countryRepository = $countryRepository;
}

We autowire the CountryRepository, from which we retrieve the data.

/**
  * Finds all countries
  */
public function findAll() {

    $data = $this->countryRepository->findAll();

    return $data;
}

We call the CountryRepository findAll() method to retrieve all countries.

src/Repository/CountryRepository.php
<?php

namespace App\Repository;

use Doctrine\DBAL\Driver\Connection;

class CountryRepository
{
    private $conn;

    public function __construct(Connection $conn) 
    {
        $this->conn = $conn;
    }

    /**
     * Finds all countries
     */
    public function findAll() {

        $queryBuilder = $this->conn->createQueryBuilder();
        $queryBuilder->select('*')->from('countries');

        $countries = $queryBuilder->execute()->fetchAll();

        return $countries;
    }
}

CountryRepository cointains a method that retrieves all rows from the countries table. It uses Symfony's DBAL to execute queries.

/**
  * Finds all countries
  */
public function findAll() {

    $queryBuilder = $this->conn->createQueryBuilder();
    $queryBuilder->select('*')->from('countries');

    $countries = $queryBuilder->execute()->fetchAll();

    return $countries;
}

We use DBAL QueryBuilder to fetch all rows from the table. Doctrine DBAL QueryBuilder provides a convenient, fluent interface to creating and running database queries.

$ symfony serve

The web server is started.

$ curl localhost:8000/countries
{"countries":[{"id":"1","name":"China","population":"1382050000"},
{"id":"2","name":"India","population":"1313210000"},
{"id":"3","name":"USA","population":"324666000"},
{"id":"4","name":"Indonesia","population":"260581000"},
{"id":"5","name":"Brazil","population":"207221000"},
{"id":"6","name":"Pakistan","population":"196626000"},
{"id":"7","name":"Nigeria","population":"186988000"},
{"id":"8","name":"Bangladesh","population":"162099000"},
{"id":"9","name":"Nigeria","population":"186988000"},
{"id":"10","name":"Russia","population":"146838000"},
{"id":"11","name":"Japan","population":"126830000"},
{"id":"12","name":"Mexico","population":"122273000"},
{"id":"13","name":"Philippines","population":"103738000"}]}

We create a request with curl command.

In this tutorial we have created a simple service in Symfony. The service fetches data from the database and is autowired in a Symfony controller.

List all Symfony tutorials.