Oke lanjut lagi tulisan saya tentang Framework Symfony, kali ini saya lanjutkan membahas tentang penggunaan doctrine untuk melakukan operasi ke database. Untuk membaca tulisan saya sebelumnya mengenai controller, bisa di baca di sini : https://catatan-pemrograman.blogspot.com/2018/09/membuat-halaman-di-symfony-4.html.

Sekilas tentang ORM

ORM / Object Relation Mapping adalah teknik mengkombinasikan / menselaraskan antara database yang RDBMS yang kebanyakan adalah database relasional yang berbasis relasi antar tabel ke dalam pemrograman berbasis objek / Object Oriented atau lebih jelasnya bisa dibaca (di sini). ORM digunakan untuk menjembatani antara pemrograman relasional dengan pemrograman objek. Saat ini ada banyak ORM yang sudah lazim digunakan orang yang biasanya sudah menjadi default framework. Contoh kalau di PHP ada active record yang dipakai sama Code IgniterEloquent yang dipakai sama Laravel, dan Doctrine sama Propel yang dipakai sama Symfony. 

Di Symfony 4, secara default kita belum menginstall ORM berbeda dengan Symfony versi sebelumnya yang secara default kita sudah lengkap dengan ORM Doctrine. Untuk SYmfony 4 kita bisa melakukan instalasi manual menggunakan composer untuk menambahkan doctrine di project symfony 4 yang sedang anda buat. 

Instalasi Doctrine di Symfony 4

untuk melakukan instalasi doctrine, anda bisa menjalankan perintah berikut di dalam folder project symfony anda menggunakan CMD : 

composer require symfony/orm-pack

maka akan keluar perintah sebagai berikut :



sampai disini kita sudah berhasil menambahkan ORM Doctrine di project symfony. selanjutnya koneksi ke database MySQL

Menggunakan Doctrine dengan MySQL

pertama kita buat database baru di mysql, untuk tulisan ini saya coba buat database dengan nama tutorial. Untuk membuat database baru, anda bisa menggunakan perintah di console sebagai berikut :

php bin/console doctrine:database:create

kemudian buka file .env yang berada di folder project symfony. Kira-kira isinya seperti ini


# This file is a "template" of which env vars need to be defined for your application
# Copy this file to .env file for development, create environment variables when deploying to production
# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration

###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=859bdea01e182789f006e295b33275af
#TRUSTED_PROXIES=127.0.0.1,127.0.0.2
#TRUSTED_HOSTS=localhost,example.com
###< symfony/framework-bundle ###

###> doctrine/doctrine-bundle ###
# Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
# Configure your db driver and server_version in config/packages/doctrine.yaml
DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name
###< doctrine/doctrine-bundle ###

kemudian cari kode yang ini

DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name

dan ganti menjadi

DATABASE_URL=mysql://root:@127.0.0.1:3306/tutorial

sampai disini kita sudah berhasil melakukan koneksi ke database MySQL. Mudah bukan ?? selanjutnya kita coba buat tabel.

Membuat Entity

di doctrine, tabel yang ada di database diwaliki dengan sebuah entity. Untuk memudahkan membuat entity, kita bisa menggunakan MakerBundle untuk melakukan generate entity, controller, form dll. Dan untuk pembahasan MakerBundle insya allah saya tulis di kesempatan yang akan datang. Sekarang kita install MakerBundle dengan perintah berikut : 

composer require symfony/maker-bundle --dev

setelah selesai, kita bisa mulai membuat Entity. Untuk membuat entity silahkan jalankan perintah berikut di console: 

php bin/console make:entity

dan ikuti petunjuk yang diberikan.  Di sini saya membuat dua entity yang bernama MNews dan MCategory. Setelah selesai, maka anda akan punya Entity yang disimpan di folder src/Entity dan repository yang disimpan di folder src/Repository seperti berikut.


mudah bukan ??. Entity MNews ada beberapa field antara lain : created_at (datetime), title (string, 255), content (text) dan entity MCategory punya beberapa field antara lain : kode (string, 255), dan name (string, 255). Untuk menambahkan field di entity MNews yang berelasi ke entity MCategory anda bisa menjalankan perintah make:entity di atas dan menuliskan nama entity Mews dan tambahkan field category yang bertipe relation seperti gambar berikut: 


pada gambar diatas saya menggunakan relasi Many to One dengan asumsi setiap news mempunyai category. Maka entity MNews saya menjadi seperti berikut: 


<?php // src/Entity/MMews.php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

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

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

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

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

/**
* @ORM\ManyToOne(targetEntity="App\Entity\MCategory", inversedBy="mNews")
*/
private $category;

public function getId(): ?int
{
return $this->id;
}

public function getCreatedAt(): ?\DateTimeInterface
{
return $this->created_at;
}

public function setCreatedAt(\DateTimeInterface $created_at): self
{
$this->created_at = $created_at;

return $this;
}

public function getTitle(): ?string
{
return $this->title;
}

public function setTitle(string $title): self
{
$this->title = $title;

return $this;
}

public function getContent(): ?string
{
return $this->content;
}

public function setContent(?string $content): self
{
$this->content = $content;

return $this;
}

public function getCategory(): ?MCategory
{
return $this->category;
}

public function setCategory(?MCategory $category): self
{
$this->category = $category;

return $this;
}
}

dan ini entity MCategory


<?php // src/Entity/MCategory.php

namespace App\Entity;

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

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

/**
* @ORM\Column(type="string", length=255)
*/
private $code;

/**
* @ORM\Column(type="string", length=255)
*/
private $name;

/**
* @ORM\OneToMany(targetEntity="App\Entity\MNews", mappedBy="category")
*/
private $mNews;

public function __construct()
{
$this->mNews = new ArrayCollection();
}

public function getId(): ?int
{
return $this->id;
}

public function getCode(): ?string
{
return $this->code;
}

public function setCode(string $code): self
{
$this->code = $code;

return $this;
}

public function getName(): ?string
{
return $this->name;
}

public function setName(string $name): self
{
$this->name = $name;

return $this;
}

/**
* @return Collection|MNews[]
*/
public function getMNews(): Collection
{
return $this->mNews;
}

public function addMNews(MNews $mNews): self
{
if (!$this->mNews->contains($mNews)) {
$this->mNews[] = $mNews;
$mNews->setCategory($this);
}

return $this;
}

public function removeMNews(MNews $mNews): self
{
if ($this->mNews->contains($mNews)) {
$this->mNews->removeElement($mNews);
// set the owning side to null (unless already changed)
if ($mNews->getCategory() === $this) {
$mNews->setCategory(null);
}
}

return $this;
}
}

sampai disini, kita akan melakukan generate entity menjadi tabel di database. silahkan jalankan perintah berikut :

php bin/console make:migration

perintah diatas akan membuatkan satu file migrasi di folder src/Migrations yang berisi kode sql untuk migrasi ke database. Kemudian untuk melakukan migrasi, silahkan jalankan kode berikut :

php bin/console doctrine:migrations:migrate

jika berhasil maka di database akan ada tabel m_news dan m_category seperti berikut :


gimana ? mudah bukan ? dan setiap ada perubahan struktur entity, maka jalankan kedua perintah di atas untuk memasukkannya ke database.

Melakukan Query Menggunakan Doctrine

Setelah sebelumnya kita telah membuat 2 tabel (m_news dan m_category ), maka kali ini kita akan mencoba melakukan operasi ke database seperti insert, update, delete, dan read ke tabel. 

untuk latihan membuat query, pertama kita buat dulu controllernya, untuk membuat controller bisa dibaca di tulisan saya sebelumnya atau mengunakan generator MakerBundle seperti halnya membuat entity. Untuk membuat controller menggunakan MakerBundle, silahkan jalankan perintah berikut di console :

php bin/console make:controller

dan ketik nama controllernya seperti berikut :


dan silahkan cek di folder src/Controller, dan sudah ada controller yang anda buat. Berikut isi controller yang saya buat


<?php // src/COntroller/CategoryController.php

namespace App\Controller;

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

class CategoryController extends AbstractController
{
/**
* @Route("/category", name="category")
*/
public function index()
{
return $this->json([
'message' => 'Welcome to your new controller!',
'path' => 'src/Controller/CategoryController.php',
]);
}
}

dan kita panggil di browser,

 http://localhost/tutorial/public/index.php/category 

maka muncul seperti berikut,


dalam seri tulisan saya kali ini dan kedepan, saya akan menggunakan model api jadi sementara tidak membahas frontend menggunakan twig dan hanya menggunakan output json. Untuk menyimpan data ke database, contohnya seperti berikut.


<?php // src/COntroller/CategoryController.php
namespace App\Controller;

// tambahkan kode berikut untuk melakukan import entity MCategory
use App\Entity\MCategory;

class CategoryController extends AbstractController
{
// buat function beserta routing
/**
* @Route("/category_insert", name="category_insert")
*/
public function insert()
{
// kita definisikan entity manager
$entityManager = $this->getDoctrine()->getManager();
// membuat object category dan set value
$MCategory = new MCategory();
$MCategory->setCode('rt');
$MCategory->setName('Rumah Tangga');
// menyimpan object ke database
$entityManager->persist($MCategory);
$entityManager->flush();

return $this->json(['status' => true, 'messages' => 'saved data successfully.']);
}
}

kemudian panggil di browser, maka akan muncul halaman seperti berikut:


dan kita lihat di database.


mudah bukan ? Untuk menangkap data dari form / inputan user, kita gunakan object dari Request yang telah disediakan oleh symfony, seperti berikut :


<?php // src/COntroller/CategoryController.php

namespace App\Controller;
// tambahkan Class Request
use Symfony\Component\HttpFoundation\Request;

class CategoryController extends AbstractController
{

/**
* @Route("/category_insert", name="category_insert")
*/
public function insert(Request $request)
{
// ambil data dari inputan user
$code = $request->get('code', null);
$name = $request->get('name', null);

// kita definisikan entity manager
$entityManager = $this->getDoctrine()->getManager();
// membuat object category dan set value
$MCategory = new MCategory();
$MCategory->setCode($code);
$MCategory->setName($name);
// menyimpan object ke database
$entityManager->persist($MCategory);
$entityManager->flush();

return $this->json(['status' => true, 'messages' => 'saved data successfully.']);
}
}

dan untuk melakukan  input bisa dengan memanggil url seperti berikut :

http://localhost/tutorial/public/index.php/category_insert?code=test&name=Test

namun function di atas masih bisa dilakukan input melalui method GET, jadi agar sedikit lebih aman kita ganti method yang di izinkan hanya POST seperti berikut:


<?php

namespace App\Controller;
...

class CategoryController extends AbstractController
{
    ......
    // tambahkan method pada routing
/**
* @Route("/category_insert", name="category_insert",methods={"POST"})
*/
public function insert(Request $request)
{
if($request->getMethod() == Request::METHOD_POST){
// ambil data dari inputan user
$code = $request->get('code', null);
$name = $request->get('name', null);

// kita definisikan entity manager
$entityManager = $this->getDoctrine()->getManager();
// membuat object category dan set value
$MCategory = new MCategory();
$MCategory->setCode($code);
$MCategory->setName($name);
// menyimpan object ke database
$entityManager->persist($MCategory);
$entityManager->flush();

return $this->json(['status' => true, 'messages' => 'saved data successfully.']);
}else{
return $this->json(['status' => false, 'messages' => 'method "'.$request->getMethod().'" not allowed.']);
}
}
}

dan silahkan insert data menggunakan POSTMAN atau yg lain untuk pengitim data menggunakan method POST.

berikut contoh cara untuk melakukan query ke database :


<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\MCategory;
use Symfony\Component\HttpFoundation\Request;

class CategoryController extends AbstractController
{
/**
* @Route("/category", name="category")
*/
public function index()
{
// kita definisikan repository
$repository = $this->getDoctrine()->getRepository(MCategory::class);

// mengambil semua isi database
$MCategorys = $repository->findAll();
$data = [];
foreach($MCategorys as $MCategory){
$data[] = [
'id' => $MCategory->getId(),
'code' => $MCategory->getCode(),
'name' => $MCategory->getName()
];
}
return $this->json([
'status' => true,
'data' => $data,
]);
}

}

dan berikut beberapa contoh cara melakukan query ke database :


<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\MCategory;
use Symfony\Component\HttpFoundation\Request;

class CategoryController extends AbstractController
{
/**
* @Route("/category", name="category")
*/
public function index()
{
// kita definisikan repository
$repository = $this->getDoctrine()->getRepository(MCategory::class);

// mengambil berdasarkan id / primary key
$MCategory = $repository->find($id);

// mengambil satu data menggunakan key tertentu
$MCategory = $repository->findOneBy(['name' => 'Test']);
// atau mengambil bedasarkan code dan name
$MCategory = $repository->findOneBy([
'code' => 'test',
'name' => 'Test'
]);

// mengambil banyak data dan melakukan shorting berdasarkan name
$MCategorys = $repository->findBy([], ['name' => 'ASC']);

// mengambil semua isi database
$MCategorys = $repository->findAll();
.....
}

}

cukup sekian dulu tulisan saya kali ini semoga bermanfaat, lain waktu kita lanjutkan membuat CRUD menggunakan API dan POSTMAN. Terima kasih