Uczymy się relacji jeden do jednego w Symfony. Kontynuacja lekcji poprzednich, zaleca się dobre przerobienie materiału. Do dzieła.

Ok, musimy utworzyć entity o nazwie Person:

  • name, string, 255, nullable – nie
  • age, integer, nullable – nie

Teraz entity o nazwie PersonAddress:

  • city, string, 255, nullable – nie
  • street, string, 255, nullable – nie
  • person:
    • typ – OneToOne
    • klasa – Person
    • nullable – nie
    • dwukierunkowe – tak
    • nazwa – personAddress

Na tym poziomie zakładam, że umiemy korzystać z makera, robić entity, migracje, migrować. Teraz tworzymy PersonController, jak już mamy sprawdzone, że utworzyło nam w bazie danych tabele.

A właśnie – jak one wyglądają? Person :

# 	Nazwa 	Typ 	           Collation 	Attributes 	Null 	Default 	Comments 	Extra 	
1 	id      Podstawowy int(11) 			                Nie 	Brak 		            AUTO_INCREMENT 		
2 	name 	varchar(255) 	   utf8mb4_unicode_ci 		Nie 	Brak 				
3 	age 	int(11) 			                        Nie 	Brak 				

A teraz PersonAddress:

# 	Nazwa 	     Typ 	                     Collation 	           Attributes 	Null 	Default 	Comments 	Extra 	
1 	id           Podstawowy int(11) 			                                Nie 	Brak 		            AUTO_INCREMENT 		
2 	person_id    Indeks 	int(11) 			                                Nie 	Brak 			
3 	city 	     varchar(255) 	             utf8mb4_unicode_ci 		        Nie 	Brak 				
4 	street 	     varchar(255) 	             utf8mb4_unicode_ci 		        Nie 	Brak 				

Ok, tworzymy PersonController i dokonujemy importów:

use App\Entity\Person;
use App\Entity\PersonAddress;
use App\Repository\PersonRepository;
use Doctrine\ORM\EntityManagerInterface;

Tworzymy testowy route, który ma nam utworzyć i zapisać dane z relacją:

#[Route('/person_test_route', name: 'app_person_test_route')]
    public function testRoute(EntityManagerInterface $entityManager): Response
    {
        $person = new Person();

        $person->setName("Jane Doe");
        $person->setAge(20);

        $addr = new PersonAddress();

        $addr->setCity("London");
        $addr->setStreet("London Street");

        $addr->setPerson($person);

        $entityManager->persist($person);
        $entityManager->persist($addr);

        $entityManager->flush();

        

        return $this->render('person/index.html.twig', [
            'controller_name' => 'PersonController',
        ]);
    }

Teraz sprawdzamy, czy mamy w bazie danych. Za pierwszym razem nie zrobiłem persist na addr, żeby mieć celowo jeden obiekt bez adresu (John Doe, potem zamieniłem na Jane i dałem persist na adresie).

Zaraz wyjaśnię dlaczego, na razie zmienimy indeks:

#[Route('/person', name: 'app_person')]
    public function index(PersonRepository $repository): Response
    {
        return $this->render('person/index.html.twig', [
            'controller_name' => 'PersonController',
            'people' => $repository->findAll()
        ]);
    }

Ok, zmieniamy index.html.twig:

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

{% block title %}Hello PersonController!{% endblock %}

{% block body %}
<style>
    .example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
    .example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
</style>

<div class="example-wrapper">
    <h1>Hello {{ controller_name }}! ✅</h1>

    {% if people|length > 0 %}
    {% for person in people %}
      <h3><a href="#">Name: {{ person.name }}<a/></h3>
      <p>Age: {{person.age}}</p>
       {% if person.personAddress %}
        <p>City: {{person.personAddress.city}}</p>
        <p>Street:{{person.personAddress.street}}</p>
        {% else %}
        <p>Address: unknown</p>
      {% endif %}
    {% endfor %}
  {% else %}
            <p>No people</p>
    {% endif %}
</div>
{% endblock %}

Mamy tutaj obsługę sytuacji, w której jeden rekord (John Doe) nie ma adresu i takiej, w której adres istnieje i jest wyświetlany.

Jak widać proste relacje jeden do jednego są bez ceregieli zaciągane od razu (co nie zawsze dotyczy relacji, w których jest ArrayCollection, czyli wiele rekordów, które nie zawsze chcemy dociągać).