[Se]   En

Doctrine ORM med PHP Symfony - del 2

  Annice      2021-04-10      PHP, Symfony, MySQL, Doctrine

När man bygger webbsidor med PHP utifrån Symfony-ramverket kan man smidigt interagera med databastabeller med hjälp av t.ex. EntityManagerInterface samt Doctrine ORM (Object Relational Mapper) i koppling till genererade entitetsklasser. Beroende på vilka tabellstrukturer som gäller samt vilka SQL-frågor som ska köras kan man dock behöva gå runt detta ibland.

Säg att man vill sätta in en ny rad i en tabell vars struktur för enkelhetens skull bygger på nedanstående kod med en primärnyckel som autoinkrementeras vid varje ny radinsättning:

CREATE TABLE Person (
    Id INT AUTO_INCREMENT PRIMARY KEY,
    Email VARCHAR(100) UNIQUE,
    Firstname VARCHAR(30),
    Lastname VARCHAR(30)
);

I en Symfony-applikation med Doctrine ORM installerat - samt med en genererad entitetsklass med getters och setters motsvarande ovanstående databastabell och kolumner - kan man då enkelt lägga till en ny rad i tabellen enligt följande exempelkod:

namespace App\Repository;

use App\Entity\Person;
use Doctrine\ORM\EntityManagerInterface;

class PersonRepository
{
    /**
     * Inject dependency to EntityManagerInterface.
     */
    public function createPerson(EntityManagerInterface $em)
    {
        $person = new Person();
        $person->setEmail("jane.doe@mail.com");
        $person->setFirstname("Jane");
        $person->setLastname("Doe");

        $em->persist($person);
        $em->flush();
    }
}

So far so good! Men säg att man istället vill skapa nya tabellrader där en primärnyckel anpassas för varje ny rad, t.ex. baserat på nedanstående tabellstruktur:

CREATE TABLE Person (
    Email VARCHAR(100) PRIMARY KEY,
    Firstname VARCHAR(30),
    Lastname VARCHAR(30)
);

Då får man dock hitta ett annat sätt att hantera detta på då persist()- och flush()-metoderna tenderar att motarbeta en vid dessa typer av radinsättningar. Och ett sätt kan då vara att använda EntityManagerInterface med Doctrine DBAL (DataBase Abstraction Layer):

namespace App\Repository;

use Doctrine\ORM\EntityManagerInterface;

class PersonRepository
{   
    public function createPerson(EntityManagerInterface $em)
    {
        $email = 'jane.doe@mail.com';
        $firstName = 'Jane';
        $lastName = 'Doe';

        // Prevent SQL injections by using placeholders ("?") in the query:
        $sql = 'INSERT INTO Person (Email, Firstname, Lastname) VALUES (?, ?, ?)';

        $em->getConnection()
            ->prepare($sql)
            ->execute(
                [
                    $email,
                    $firstName,
                    $lastName
                 ]
             );
     }
}

Här går man alltså ifrån ORM-principen, men vid just INSERT-frågor är det ofta smidigast att bara utgå ifrån ovanstående typ av persistering vid tillägg av anpassade primärnycklar.