Kadang-kadang kita perlu menempatkan logika aplikasi di suatu tempat di luar pengontrol atau model, biasanya itu disebut layanan. Tetapi ada beberapa cara untuk menggunakannya – sebagai “pembantu” statis, seperti objek, atau dengan injeksi ketergantungan. Mari kita lihat kapan masing -masing sesuai.
Masalah terbesar yang pernah saya lihat dalam topik ini – ada banyak artikel tentang BAGAIMANA untuk menggunakan injeksi dan layanan ketergantungan, tetapi hampir tidak ada penjelasan tentang MENGAPA Anda harus menggunakannya dan KAPAN Ini sebenarnya bermanfaat. Jadi mari selami contoh -contoh, dengan beberapa teori di sepanjang jalan.
Dalam artikel ini, kami akan membahas satu contoh pelaporan dengan menggunakan berbagai teknik untuk memindahkan kode dari pengontrol ke layanan:
- Cara pertama: dari pengontrol ke layanan statis “pembantu”
- Cara Kedua: Buat Objek Layanan dengan Metode Non-Statis
- Cara Ketiga: Objek Layanan dengan Parameter
- Jalan Keempat: Injeksi Ketergantungan – Kasus Sederhana
- Jalan Kelima: Injeksi Ketergantungan dengan Antarmuka – Penggunaan Lanjutan
Contoh Awal: Laporan di Pengontrol
Katakanlah kita sedang membangun laporan bulanan, sesuatu seperti ini:
Dan jika kita memasukkan semuanya ke dalam pengontrol, itu akan terlihat seperti ini:
// ... use statements
class ClientReportController extends Controller
{
public function index(Request $request)
{
$q = Transaction::with('project')
->with('transaction_type')
->with('income_source')
->with('currency')
->orderBy('transaction_date', 'desc');
if ($request->has('project')) {
$q->where('project_id', $request->project);
}
$transactions = $q->get();
$entries = [];
foreach ($transactions as $row) {
// ... Another 50 lines of code to fill in $entries by month
}
return view('report', compact('entries'));
}
}
Sekarang, Anda melihat permintaan DB itu, dan juga 50 baris kode yang tersembunyi – mungkin terlalu banyak untuk pengontrol, jadi kita perlu menyimpannya di suatu tempat, kan?
Cara pertama: dari pengontrol ke layanan statis “pembantu”
Cara paling populer untuk memisahkan logika dari pengontrol adalah dengan membuat kelas yang terpisah, biasanya disebut a Melayani. Dengan kata lain, itu bisa disebut “penolong” atau sekadar “fungsi”.
Melihat: Kelas layanan bukan bagian dari Laravel itu sendiri, tidak ada Buat: Layanan Komando Pengrajin. Ini hanya kelas PHP sederhana untuk perhitungan, dan “layanan” hanyalah nama khas untuk itu.
Jadi, kami membuat file Aplikasi/Layanan/ReportService.php:
namespace App\Services;
use App\Transaction;
use Carbon\Carbon;
class ReportService {
public static function getTransactionReport(int $projectId = NULL)
{
$q = Transaction::with('project')
->with('transaction_type')
->with('income_source')
->with('currency')
->orderBy('transaction_date', 'desc');
if (!is_null($projectId)) {
$q->where('project_id', $projectId);
}
$transactions = $q->get();
$entries = [];
foreach ($transactions as $row) {
// ... Same 50 lines of code copied from Controller to here
}
return $entries;
}
}
Dan sekarang, kita bisa memanggil fungsi itu dari pengontrol, seperti ini:
// ... other use statements
use App\Services\ReportService;
class ClientReportController extends Controller
{
public function index(Request $request)
{
$entries = ReportService::getTransactionReport($request->input('project'));
return view('report', compact('entries'));
}
}
Itu saja, pengontrol sekarang banyak pembersih, kan?
Seperti yang Anda lihat, kami gunakan statis metode dan menyebutnya dengan :: Sintaks, jadi tidak benar -benar membuat objek untuk kelas layanan itu.
Kapan menggunakan ini?
Biasanya, ketika Anda akan dengan mudah menggantinya dengan fungsi sederhana, tanpa kelas. Ini seperti penolong global, tetapi duduk di dalam Laporan Laporan Kelas hanya demi tetap dengan kode berorientasi objek, dan untuk menjaga pesanan-dengan ruang nama dan folder.
Juga, perlu diingat bahwa metode dan kelas statis tanpa kewarganegaraan. Ini berarti bahwa metode ini dipanggil hanya untuk satu kali, dan tidak menyimpan data apa pun di dalam kelas itu sendiri.
Tetapi jika Anda ingin menyimpan beberapa data di dalam layanan itu…
Cara Kedua: Buat Objek Layanan dengan Metode Non-Statis
Cara lain untuk memulai kelas itu adalah dengan membuat metode itu non-statis, dan membuat objek:
Aplikasi/Layanan/ReportService.php:
class ReportService {
// Just "public", but no "static"
public function getTransactionReport(int $projectId = NULL)
{
// ... Absolutely the same code as in static version
return $entries;
}
}
ClientReportController:
// ... other use statements
use App\Services\ReportService;
class ClientReportController extends Controller
{
public function index(Request $request)
{
$entries = (new ReportService())->getTransactionReport($request->input('project'));
return view('report', compact('entries');
}
}
Atau, jika Anda tidak suka satu kalimat panjang:
$reportService = new ReportService();
$entries = $reportService->getTransactionReport($request->input('project'));
Tidak membuat banyak perbedaan dari metode statis, bukan?
Itu karena, untuk kasus sederhana ini, sebenarnya tidak ada bedanya.
Tetapi ini berguna jika Anda memiliki beberapa metode di dalam layanan dan Anda ingin “rantai” mereka, menelepon segera satu demi satu, sehingga setiap metode akan mengembalikan instance layanan yang sama. Anda dapat menonton video 8 menit saya tentang hal itu, atau, sebagai contoh sederhana, lihat di sini:
class ReportService {
private $year;
public function setYear($year)
{
$this->year = $year;
return $this;
}
public function getTransactionReport(int $projectId = NULL)
{
$q = Transaction::with('project')
->with('transaction_type')
->with('income_source')
->with('currency')
->whereYear('transaction_date', $this->year)
->orderBy('transaction_date', 'desc');
// ... Other code
Dan kemudian di Controller, Anda melakukan ini:
public function index(Request $request)
{
$entries = (new ReportService())
->setYear(2020)
->getTransactionReport($request->input('project'));
// ... Other code
Kapan menggunakan ini?
Sejujurnya, dalam kasus yang jarang terjadi, sebagian besar untuk metode rantai seperti pada contoh di atas.
Jika layanan Anda tidak menerima parameter apa pun saat membuat objeknya Laporan Laporan Baru ()lalu gunakan saja metode statis. Anda tidak perlu membuat objek sama sekali.
Cara Ketiga: Objek Layanan dengan Parameter
Tetapi bagaimana jika Anda ingin membuat layanan itu dengan parameter? Seperti, Anda ingin memiliki laporan tahunan dan memulai kelas itu, melewati yang sebenarnya $ tahunitu akan diterapkan pada semua metode di dalam layanan itu.
APP/LAYANAN/TAHUNAN REPORTSERVICE.PHP:
class YearlyReportService {
private $year;
public function __construct(int $year)
{
$this->year = $year;
}
public function getTransactionReport(int $projectId = NULL)
{
// Notice the ->whereYear('transaction_date', $this->year)
$q = Transaction::with('project')
->with('transaction_type')
->with('income_source')
->with('currency')
->whereYear('transaction_date', $this->year)
->orderBy('transaction_date', 'desc');
$entries = [];
foreach ($transactions as $row) {
// ... Same 50 line of code
}
return $entries;
}
// Another report that uses the same $this->year
public function getIncomeReport(int $projectId = NULL)
{
// Notice the ->whereYear('transaction_date', $this->year)
$q = Transaction::with('project')
->with('transaction_type')
->with('income_source')
->with('currency')
->whereYear('transaction_date', $this->year)
->where('transaction_type', 'income')
->orderBy('transaction_date', 'desc');
$entries = [];
// ... Some more logic
return $entries;
}
}
Terlihat sedikit lebih rumit, bukan?
Tapi sekarang, sebagai akibat dari ini, inilah yang bisa kita lakukan di pengontrol.
// ... other use statements
use App\Services\YearlyReportService;
class ClientReportController extends Controller
{
public function index(Request $request)
{
$year = $request->input('year', date('Y')); // default to current year
$reportService = new YearlyReportService($year);
$fullReport = $reportService->getTransactionReport($request->input('project'));
$incomeReport = $reportService->getIncomeReport($request->input('project'));
}
}
Dalam contoh ini, kedua metode layanan akan menggunakan parameter tahun yang sama yang kami lewati saat membuat objek.
Sekarang, masuk akal untuk benar -benar membuat objek itu, alih -alih menggunakan metode statis. Karena sekarang layanan kami memang memiliki keadaan aktual dan tergantung pada satu tahun.
Kapan menggunakan ini?
Ketika layanan Anda memiliki parameter dan Anda ingin membuat objeknya melewati beberapa nilai parameter yang akan digunakan kembali saat memanggil semua metode layanan untuk objek layanan itu.
Jalan Keempat: Injeksi Ketergantungan – Kasus Sederhana
kalau sudah beberapa metode Di pengontrol dan ingin menggunakan kembali layanan yang sama di semuanya, Anda juga dapat menyuntikkannya pada konstruktor pengontrol, sebagai parameter yang diisi tipe, seperti ini:
class ClientReportController extends Controller
{
private $reportService;
public function __construct(ReportService $service)
{
$this->reportService = $service;
}
public function index(Request $request)
{
$entries = $this->reportService->getTransactionReport($request->input('project'));
// ...
}
public function income(Request $request)
{
$entries = $this->reportService->getIncomeReport($request->input('project'));
// ...
}
}
Apa yang sebenarnya terjadi di sini?
- Kami membuat properti pribadi dari pengontrol yang dipanggil $ Reportservice;
- Kami melewati parameter Laporan Laporan ketik ke __membangun() metode;
- Di dalam konstruktor, kami menetapkan parameter itu ke properti pribadi itu;
- Kemudian, di semua pengontrol kami, kami dapat menggunakan $ this-> Reportservice dan semua metodenya.
Ini didukung oleh Laravel itu sendiri, jadi Anda tidak perlu khawatir tentang benar -benar membuat objek kelas itu, Anda hanya perlu meneruskan jenis parameter yang benar ke konstruktor.
Kapan menggunakan ini?
Ketika Anda memiliki beberapa metode di pengontrol Anda yang ingin menggunakan layanan yang sama, dan ketika layanan tidak memerlukan parameter apa pun (seperti $ tahun dalam contoh di atas). Dengan cara ini hanya untuk menghemat waktu Anda sehingga Anda tidak perlu melakukannya Laporan Laporan Baru () dalam setiap metode pengontrol.
Tapi tunggu, ada lebih banyak suntikan jenis itu-Anda bisa melakukannya metode apa puntidak hanya pengontrol. Itu disebut a Injeksi metode.
Seperti ini:
class ClientReportController extends Controller
{
public function index(Request $request, ReportService $reportService)
{
$entries = $reportService->getTransactionReport($request->input('project'));
// ...
}
Seperti yang Anda lihat, tidak ada konstruktor atau properti pribadi yang diperlukan, Anda hanya menyuntikkan variabel tipe yang dijalankan, dan menggunakannya di dalam metode. Laravel menciptakan objek itu “dengan sihir”.
Tapi, jujur saja, untuk contoh persis kami itu tidak bermanfaat, suntikan ini datang dengan menulis lebih banyak kode daripada hanya membuat layanan, bukan? Jadi apa sebenarnya keuntungan menggunakan injeksi ketergantungan?
Jalan Kelima: Injeksi Ketergantungan dengan Antarmuka – Penggunaan Lanjutan
Dalam contoh sebelumnya, kami memberikan parameter ke pengontrol dan Laravel “secara ajaib” menyelesaikan parameter itu untuk membuat objek layanan di belakang layar.
Bagaimana jika kita bisa mengontrol nilai variabel itu? Bagaimana jika, misalnya, kita dapat melewati beberapa layanan untuk fase pengujian, dan layanan lain untuk penggunaan langsung nyata?
Untuk itu, kami akan membuat Antarmuka dan dua kelas itu Melayani Itu akan menerapkan antarmuka itu. Ini seperti kontrak – antarmuka akan menentukan sifat dan metode yang harus ada di semua kelas yang menerapkan antarmuka itu. Mari kita bangun contoh.
Ingat kedua layanan itu dalam contoh di atas Laporan Laporan Dan Laporan tahunan? Mari kita buat mereka menerapkan antarmuka yang sama.
Kami membuat file baru APP/INTERFACES/REPANSTERVICETInterface.php:
namespace App\Interfaces;
interface ReportServiceInterface {
public function getTransactionReport(int $projectId = NULL);
}
Dan hanya itu, kita tidak perlu melakukan apa pun di sini – antarmuka hanyalah seperangkat aturan, tanpa “tubuh” metode. Jadi, di sini, kami mendefinisikan bahwa setiap kelas yang mengimplementasikan antarmuka itu, harus memilikinya getTransactionReport () metode.
Sekarang, Aplikasi/Layanan/ReportService.php:
use App\Interfaces\ReportServiceInterface;
class ReportService implements ReportServiceInterface {
public function getTransactionReport(int $projectId = NULL)
{
// ... same old code
Juga, APP/LAYANAN/TAHUNAN REPORTSERVICE.PHP:
use App\Interfaces\ReportServiceInterface;
class YearlyReportService implements ReportServiceInterface {
private $year;
public function __construct(int $year = NULL)
{
$this->year = $year;
}
public function getTransactionReport(int $projectId = NULL)
{
// Again, same old code with $year as a parameter
Sekarang, bagian utama-kelas mana yang kita ketik ke dalam pengontrol? Laporan Laporan atau Laporan Tahunan?
Faktanya, kami tidak mengetik kelas lagi- Kami mengetikkan antarmuka.
use App\Interfaces\ReportServiceInterface;
class ClientReportController extends Controller
{
private $reportService;
public function __construct(ReportServiceInterface $reportService)
{
$this->reportService = $reportService;
}
public function index(Request $request)
{
$entries = $this->reportService->getTransactionReport($request->input('project'));
// ... Same old code
Bagian utama di sini adalah __construct (ReportserviceInterface $ Reportservice). Sekarang, kita dapat melampirkan dan menukar kelas apa pun yang mengimplementasikan antarmuka itu.
Tapi, secara default, kita kehilangan Laravel “suntikan sihir”, karena kerangka kerja tidak tahu kelas mana yang akan digunakan. Jadi jika Anda membiarkannya seperti ini, Anda akan mendapatkan kesalahan:
Illuminate \ Contracts \ Container \ BindingResolutionException
Target [App\Interfaces\ReportServiceInterface] tidak dapat dibangun saat membangun [App\Http\Controllers\Admin\ClientReportController].
Dan itu sangat benar, kami tidak mengatakan kelas mana yang menjadi instantiate.
Kita perlu melakukannya APP/PENYEDIA/APPSERVICEPROVIDER.PHP di sebuah daftar() metode.
Untuk membuat contoh ini sangat jelas, mari kita tambahkan pernyataan jika logika bahwa jika kita memiliki lingkungan lokal, kita mengambil ReportService, jika tidak kita perlu Laporan Tahunan.
use App\Interfaces\ReportServiceInterface;
use App\Services\ReportService;
use App\Services\YearlyReportService;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
if (app()->environment('local')) {
$this->app->bind(ReportServiceInterface::class, function () {
return new ReportService();
});
} else {
$this->app->bind(ReportServiceInterface::class, function () {
return new YearlyReportService();
});
}
}
}
Lihat apa yang terjadi di sini?
Kami memilih layanan mana yang akan digunakan, tergantung di mana kami bekerja saat ini – di komputer lokal kami, atau di server langsung.
Kapan menggunakan ini?
Contoh di atas mungkin adalah penggunaan yang paling umum untuk injeksi ketergantungan dengan antarmuka – ketika Anda perlu menukar layanan Anda tergantung pada beberapa kondisi, dan Anda dapat dengan mudah melakukan ini di penyedia layanan.
Beberapa contoh lagi bisa saat Anda menukar penyedia email Anda atau penyedia pembayaran Anda. Tapi kemudian, tentu saja, penting (dan tidak mudah) untuk memastikan bahwa kedua layanan menerapkan antarmuka yang sama.
Artikel Loooong, kan? Ya, karena topik ini cukup rumit, dan saya ingin menjelaskannya dengan contoh kehidupan nyata, jadi Anda akan memahami tidak hanya bagaimana menggunakan injeksi dan layanan ketergantungan, tetapi juga mengapa menggunakannya dan kapan menggunakan setiap kasus.
Jika Anda memiliki pertanyaan atau komentar lagi, gunakan formulir di bawah ini!
News
Berita
News Flash
Blog
Technology
Sports
Sport
Football
Tips
Finance
Berita Terkini
Berita Terbaru
Berita Kekinian
News
Berita Terkini
Olahraga
Pasang Internet Myrepublic
Jasa Import China
Jasa Import Door to Door
Gaming center adalah sebuah tempat atau fasilitas yang menyediakan berbagai perangkat dan layanan untuk bermain video game, baik di PC, konsol, maupun mesin arcade. Gaming center ini bisa dikunjungi oleh siapa saja yang ingin bermain game secara individu atau bersama teman-teman. Beberapa gaming center juga sering digunakan sebagai lokasi turnamen game atau esports.
Comments are closed, but trackbacks and pingbacks are open.