Ketika kita bekerja dengan Service di Symfony, aplikasi kita akan mempunyai banyak Service / Object yang saling berkaitan. Kadang kita ingin mengelompokkan beberapa Service dengan behaviour / kegunaan tertentu menjadi satu kelompok. Untuk mengelompokkan Service, kita bisa menggunakan Tags. Ada banyak tags bawaan dari symfony yang bisa anda baca langsung di https://symfony.com/doc/current/reference/dic_tags.html
Membuat Tags
Anggap saya akan membuat perbandingan jarak antar titik. Saya akan menggunakan 2 metode yang berbeda, yaitu menggunakan rumus haversine (lihat di sini) dan satu lagi menggunakan crawling ke google map. Untuk itu saya membuat 2 buah Class yang masing-masing digunakan untuk membuat formula perhitungan jarak yang akan implements ke Interface DistanceCalculatorInterface seperti potongan kode berikut:
<?php // src/DistanceCalculator/DistanceCalculatorInterface.php namespace App\DistanceCalculator; /** * * @author programmer */ interface DistanceCalculatorInterface { public function getDistance(string $latLongA, string $latLongB):float; }
kemudian berikut potongan kode untuk masing-masing Class perhitungan
<?php // src/DistanceCalculator/HaversineCalculator.php namespace App\DistanceCalculator; /** * Description of HaversineCalculator * * @author programmer */ class HaversineCalculator implements DistanceCalculatorInterface { /** * * @var float */ private $pi; /** * * @var float */ const EARTH_RADIUS = 6371; public function __construct() { $this->pi = pi(); } public function getDistance(string $latLongA, string $latLongB): float { $latLongA = $this->split($latLongA); $latLongB = $this->split($latLongB); $radianLatA = $this->getRadians( $latLongA[0] ); $radianLatB = $this->getRadians( $latLongB[0] ); $radianLat = $this->getRadians( $latLongB[0] - $latLongA[0] ); $radianLong = $this->getRadians( $latLongB[1] - $latLongA[1] ); $a = (sin($radianLat/2) * sin($radianLat/2)) + (cos($radianLatA) * cos($radianLatB)) * (sin($radianLong/2) * sin($radianLong/2)); $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); return round(self::EARTH_RADIUS * $c, 2); } protected function split(string $latLong):array { return array_map(function (string $point) { return (float) $point; }, explode(",", $latLong)); } protected function getRadians(float $x):float { return $x * ($this->pi / 180); } }
kemudian perhitungan dari google map
<?php // src/DistanceCalculator/GMapDistanceCalculator.php namespace App\DistanceCalculator; /** * Description of GMapDistanceCalculator * * @author programmer */ class GMapDistanceCalculator implements DistanceCalculatorInterface { public function getDistance(string $latLongA, string $latLongB): float { // contoh script untuk scraping ke google map return 8; } }
kemudian saya buat Class DistanceCalculatorCollection yang akan dipakai untuk memuat semua Service yang implement dari DistanceCalculatorInterface tersebut:
<?php // src/DistanceCalculator/DistanceCalculatorCollection.php namespace App\DistanceCalculator; /** * Description of DistanceCalculatorCollection * * @author programmer */ class DistanceCalculatorCollection { private iterable $calculators; public function __construct(iterable $calculators) { $this->calculators = $calculators; } public function getCalculators():array { return iterator_to_array($this->calculators); } }
kemudian Class Collectionnya saya panggil dari Controller:
<?php // src/Controller/DistanceController.php namespace App\Controller; use Symfony\Component\Routing\Annotation\Route; use App\DistanceCalculator\DistanceCalculatorCollection; /** * Description of DistanceController * @Route("/distance", name="distance_") * @author programmer */ class DistanceController { /** * @Route("/", name="index") */ public function index(DistanceCalculatorCollection $collection) { dump($collection->getCalculators()); exit; } }
sekarang saya sudah punya 2 Class untuk menghitung dengan 2 rumus yang berbeda beserta 1 Class untuk menampung Object dari kedua Class tersebut
Mendaftarkan Service Tags
Untuk mendaftarkan kedua Class yang digunakan untuk menghitung tersebut, tambahkan di file konfigurasi services.yaml yang berada di folder config/services.yaml. Kemudian tambahkan seperti kode berikut:
services: # ..... App\DistanceCalculator\HaversineCalculator: tags: - { name: distance.calculator } App\DistanceCalculator\GMapDistanceCalculator: tags: - { name: distance.calculator }
kode di atas berarti kita mendaftarkan 2 Service dengan nama tag distance.calculator. Kemudian daftarkan juga Class Collection yang berguna untuk tempat berkumpulnya Service tersebut.
services: # ... App\DistanceCalculator\DistanceCalculatorCollection: arguments: $calculators: !tagged distance.calculator
kemudian paggil controller melalui browser maka akan muncul sepeti berikut:
kemudian jika digunakan untuk menghitung seperti potongan kode berikut:
<?php // src/Controller/DistanceController.php namespace App\Controller; use Symfony\Component\Routing\Annotation\Route; use App\DistanceCalculator\DistanceCalculatorCollection; /** * Description of DistanceController * @Route("/distance", name="distance_") * @author programmer */ class DistanceController { /** * @Route("/", name="index") */ public function index(DistanceCalculatorCollection $collection) { $from = '-7.325447718127029, 112.75154637208772'; $to = '-7.365628717636805, 112.75223597318133'; foreach ($collection->getCalculators() as $calc) { $result = $calc->getDistance($from, $to); dump($result); } exit; } }
akan keluar hasil seperti berikut:
Mendaftarkan Berdasarkan Interface
Untuk otomatis semua Class yang merupakan turunan dari interface DistanceCalculatorInterface dengan tag distance.calculator bisa menggunakan keyword _instanceof di file services.yaml:
services: # ... _instanceof: App\DistanceCalculator\DistanceCalculatorInterface: tags: - { name: distance.calculator }
Komentar
Posting Komentar