Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • SensioLabs Professional services to help you with Symfony
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by SensioLabs
  1. Home
  2. Documentation
  3. Best Practices
  4. Organizing Your Business Logic
  • Documentation
  • Book
  • Reference
  • Bundles
  • Cloud

Table of Contents

  • Services: Naming and Configuration
  • Service Format: YAML
  • Using a Persistence Layer
    • Doctrine Mapping Information
    • Data Fixtures
  • Coding Standards

Organizing Your Business Logic

Edit this page

Warning: You are browsing the documentation for Symfony 4.0, which is no longer maintained.

Read the updated version of this page for Symfony 6.2 (the current stable version).

Organizing Your Business Logic

In computer software, business logic or domain logic is "the part of the program that encodes the real-world business rules that determine how data can be created, displayed, stored, and changed" (read full definition).

In Symfony applications, business logic is all the custom code you write for your app that's not specific to the framework (e.g. routing and controllers). Domain classes, Doctrine entities and regular PHP classes that are used as services are good examples of business logic.

For most projects, you should store all your code inside the src/ directory. Inside here, you can create whatever directories you want to organize things:

1
2
3
4
5
6
7
8
9
symfony-project/
├─ config/
├─ public/
├─ src/
│  └─ Utils/
│     └─ MyClass.php
├─ tests/
├─ var/
└─ vendor/

Services: Naming and Configuration

Best Practice

Use autowiring to automate the configuration of application services.

Service autowiring is a feature provided by Symfony's Service Container to manage services with minimal configuration. It reads the type-hints on your constructor (or other methods) and automatically passes the correct services to each method. It can also add service tags to the services needing them, such as Twig extensions, event subscribers, etc.

The blog application needs a utility that can transform a post title (e.g. "Hello World") into a slug (e.g. "hello-world") to include it as part of the post URL. Let's create a new Slugger class inside src/Utils/:

1
2
3
4
5
6
7
8
9
10
// src/Utils/Slugger.php
namespace App\Utils;

class Slugger
{
    public function slugify(string $value): string
    {
        // ...
    }
}

If you're using the default services.yaml configuration, this class is auto-registered as a service whose ID is App\Utils\Slugger (or simply Slugger::class if the class is already imported in your code).

Best Practice

The id of your application's services should be equal to their class name, except when you have multiple services configured for the same class (in that case, use a snake case id).

Now you can use the custom slugger in any other service or controller class, such as the AdminController:

1
2
3
4
5
6
7
8
9
10
11
12
13
use App\Utils\Slugger;

public function create(Request $request, Slugger $slugger)
{
    // ...

    if ($form->isSubmitted() && $form->isValid()) {
        $slug = $slugger->slugify($post->getTitle());
        $post->setSlug($slug);

        // ...
    }
}

Services can also be public or private. If you use the default services.yaml configuration, all services are private by default.

Best Practice

Services should be private whenever possible. This will prevent you from accessing that service via $container->get(). Instead, you will need to use dependency injection.

Service Format: YAML

If you use the default services.yaml configuration, most services will be configured automatically. However, in some edge cases you'll need to configure services (or parts of them) manually.

Best Practice

Use the YAML format to configure your own services.

This is controversial, and in our experience, YAML and XML usage is evenly distributed among developers, with a slight preference towards YAML. Both formats have the same performance, so this is ultimately a matter of personal taste.

We recommend YAML because it's friendly to newcomers and concise. You can of course use whatever format you like.

Using a Persistence Layer

Symfony is an HTTP framework that only cares about generating an HTTP response for each HTTP request. That's why Symfony doesn't provide a way to talk to a persistence layer (e.g. database, external API). You can choose whatever library or strategy you want for this.

In practice, many Symfony applications rely on the independent Doctrine project to define their model using entities and repositories. Just like with business logic, we recommend storing Doctrine entities in the src/Entity/ directory.

The three entities defined by our sample blog application are a good example:

1
2
3
4
5
6
7
symfony-project/
├─ ...
└─ src/
   └─ Entity/
      ├─ Comment.php
      ├─ Post.php
      └─ User.php

Doctrine Mapping Information

Doctrine entities are plain PHP objects that you store in some "database". Doctrine only knows about your entities through the mapping metadata configured for your model classes. Doctrine supports four metadata formats: YAML, XML, PHP and annotations.

Best Practice

Use annotations to define the mapping information of the Doctrine entities.

Annotations are by far the most convenient and agile way of setting up and looking for mapping information:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * @ORM\Entity
 */
class Post
{
    const NUMBER_OF_ITEMS = 10;

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string")
     */
    private $title;

    /**
     * @ORM\Column(type="string")
     */
    private $slug;

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

    /**
     * @ORM\Column(type="string")
     */
    private $authorEmail;

    /**
     * @ORM\Column(type="datetime")
     */
    private $publishedAt;

    /**
     * @ORM\OneToMany(
     *      targetEntity="Comment",
     *      mappedBy="post",
     *      orphanRemoval=true
     * )
     * @ORM\OrderBy({"publishedAt"="ASC"})
     */
    private $comments;

    public function __construct()
    {
        $this->publishedAt = new \DateTime();
        $this->comments = new ArrayCollection();
    }

    // getters and setters ...
}

All formats have the same performance, so this is once again ultimately a matter of taste.

Data Fixtures

As fixtures support is not enabled by default in Symfony, you should execute the following command to install the Doctrine fixtures bundle:

1
$ composer require "doctrine/doctrine-fixtures-bundle"

Then, this bundle is enabled automatically, but only for the dev and test environments:

1
2
3
4
5
6
// config/bundles.php

return [
    // ...
    Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
];

We recommend creating just one fixture class for simplicity, though you're welcome to have more if that class gets quite large.

Assuming you have at least one fixtures class and that the database access is configured properly, you can load your fixtures by executing the following command:

1
2
3
4
5
$ php bin/console doctrine:fixtures:load

Careful, database will be purged. Do you want to continue Y/N ? Y
  > purging database
  > loading App\DataFixtures\ORM\LoadFixtures

Coding Standards

The Symfony source code follows the PSR-1 and PSR-2 coding standards that were defined by the PHP community. You can learn more about the Symfony Coding standards and even use the PHP-CS-Fixer, which is a command-line utility that can fix the coding standards of an entire codebase in a matter of seconds.


Next: Controllers

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version
    We stand with Ukraine.
    Version:
    Code consumes server resources. Blackfire tells you how

    Code consumes server resources. Blackfire tells you how

    Peruse our complete Symfony & PHP solutions catalog for your web development needs.

    Peruse our complete Symfony & PHP solutions catalog for your web development needs.

    Symfony footer

    ↓ Our footer now uses the colors of the Ukrainian flag because Symfony stands with the people of Ukraine.

    Avatar of Manatsawin Hanmongkolchai, a Symfony contributor

    Thanks Manatsawin Hanmongkolchai for being a Symfony contributor

    1 commit • 10 lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • Symfony at a Glance
      • Symfony Components
      • Case Studies
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • SymfonyConnect
      • Support
      • How to be Involved
      • Code of Conduct
      • Events & Meetups
      • Projects using Symfony
      • Downloads Stats
      • Contributors
      • Backers
    • Blog

      • Events & Meetups
      • A week of symfony
      • Case studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Documentation
      • Living on the edge
      • Releases
      • Security Advisories
      • SymfonyInsight
      • Twig
      • SensioLabs
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Deployed on

    Follow Symfony

    Search by Algolia