Kompatibilitas Versi
Plugin dapat mendeklarasikan versi framework yang didukung dan ditolak secara jelas ketika dipasang pada versi yang tidak kompatibel. Gunakan fitur ini ketika plugin didistribusikan sebagai package. Tanpa pemeriksaan ini, kegagalan yang muncul biasanya seperti Call to undefined method Panel::whatever() di tengah request — menyebut framework, bukan plugin yang meminta method tersebut.
Contoh minimal yang berfungsi
<?php
declare(strict_types=1);
namespace Acme\Reporting;
use PandaPanel\Core\Panel;
use PandaPanel\Plugins\Plugin;
use PandaPanel\Plugins\PluginMetadata;
final class ReportingPlugin extends Plugin
{
public function register(Panel $panel): void
{
$panel->resources([Resources\ReportResource::class]);
}
public function metadata(): PluginMetadata
{
return new PluginMetadata(
name: 'Acme Reporting',
package: 'acme/panda-reporting',
requiresPanel: '^1.2',
);
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Jika dipasang pada aplikasi dengan framework 1.0.3, Panel menolak dibangun:
The [Acme Reporting] plugin ([acme-reporting], registered on the [admin] panel)
requires panda-panel ^1.2, and 1.0.3 is installed. Upgrade the plugin, or pin
this framework to a version it supports.2
3
Di mana pemeriksaan dijalankan
Panel::plugins() memanggil PandaPanel\Plugins\PluginCompatibility::assert() untuk setiap plugin setelah duplicate-ID check dan sebelum register():
PluginCompatibility::assert($plugin, $this->getId());
$this->plugins[$id] = $plugin;
$plugin->register($this);2
3
4
5
Registration adalah momen paling awal ketika informasi kompatibilitas sudah diketahui sekaligus momen terakhir sebelum plugin mulai mengubah Panel. Karena pemeriksaan dilakukan di sini, plugin yang ditolak tidak meregistrasikan apa pun dan tidak meninggalkan Panel dalam kondisi setengah terkonfigurasi.
Exception yang digunakan adalah PandaPanel\Exceptions\PanelRegistrationException, turunan RuntimeException, dan bersifat fatal saat application boot. Ini disengaja: plugin yang tidak kompatibel adalah developer error, dan Panel yang hanya bekerja sebagian lebih berbahaya daripada Panel yang menolak dibangun.
PluginCompatibility::assert()
namespace PandaPanel\Plugins;
use PandaPanel\Contracts\PanelPlugin;
final class PluginCompatibility
{
/**
* @param string|null $installed the framework version to check against,
* defaulting to the one composer reports
*
* @throws \PandaPanel\Exceptions\PanelRegistrationException
*/
public static function assert(PanelPlugin $plugin, string $panelId, ?string $installed = null): void;
}2
3
4
5
6
7
8
9
10
11
12
13
14
| Parameter | Type | Default | Arti |
|---|---|---|---|
$plugin | PanelPlugin | wajib | Plugin yang dibaca untuk metadata()->requiresPanel, metadata()->name, dan id() |
$panelId | string | wajib | Dicantumkan di error message agar aplikasi multi-panel tahu plugin dipasang di mana |
$installed | ?string | null | Versi framework yang diperiksa. null berarti "tanya Composer" |
Urutan method secara lengkap:
- Baca
$plugin->metadata()->requiresPanel. Return jika nilainyanull. - Resolve
$installed, fallback ke Composer. Return jika hasilnyanull. - Jalankan
Semver::satisfies($installed, $constraint)dan return jika lolos. - Jika gagal, lempar exception yang menyebut nama plugin, ID, Panel, constraint, dan versi yang terpasang.
Test biasanya memanggil method secara langsung karena mengisi $installed adalah cara paling pasti menguji perbandingan pada checkout yang tidak memiliki versi package — lihat Testing Plugin:
use PandaPanel\Plugins\PluginCompatibility;
PluginCompatibility::assert($plugin, 'admin', '1.4.1');2
3
Menulis constraint
requiresPanel menggunakan constraint bergaya Composer dan dievaluasi oleh composer/semver melalui Semver::satisfies(). Apa pun yang diterima Composer di blok require juga berlaku di sini.
| Constraint | Dipenuhi oleh |
|---|---|
^1.2 | 1.2.0 hingga sebelum 2.0.0 |
~1.2.3 | 1.2.3 hingga sebelum 1.3.0 |
>=1.2 <2.0 | range yang sama dengan ^1.2, ditulis eksplisit |
1.4.* | semua patch pada 1.4 |
^1.2 || ^2.0 | salah satu major line, untuk plugin yang mendukung keduanya |
Deklarasikan constraint yang benar-benar dibutuhkan. ^1.2 karena plugin menggunakan method yang baru hadir pada 1.2 adalah fakta. Menyalin ^1.2 dari plugin lain hanyalah tebakan yang dapat menolak instalasi yang sebenarnya valid.
Tiga kondisi ketika pemeriksaan dilewati
Ketiganya berarti tidak ada pertanyaan versi yang dapat dijawab secara valid.
| Kondisi | Perilaku | Alasan |
|---|---|---|
Plugin tidak mendeklarasikan constraint (requiresPanel adalah null) | lolos | Sebagian besar plugin tidak membutuhkannya; plugin yang belum mendefinisikan compatibility tidak seharusnya dianggap sudah mendefinisikannya. |
| Framework tidak terpasang sebagai Composer package | lolos | Path repository, git checkout, atau test suite repository ini sendiri tidak memiliki version package yang dapat dibandingkan. |
Versi yang dilaporkan berupa branch alias (dev-main) atau placeholder Composer no-version-set | lolos | Constraint tidak dapat dinilai terhadap branch dan development checkout harus tetap dapat menguji ecosystem plugin. |
Konsekuensi praktisnya: plugin yang dikembangkan menggunakan local path repository tidak akan melihat constraint-nya ditegakkan. Mesin pertama yang benar-benar menegakkannya biasanya adalah instalasi tagged release dari Packagist. Karena itu test compatibility dengan mengisi $installed secara eksplisit, jangan hanya mengandalkan local run.
Cara versi framework ditemukan
private const PACKAGE = 'chocoalano/panel';
Composer\InstalledVersions::getPrettyVersion(self::PACKAGE);2
3
Konstanta tersebut harus sama persis dengan field name pada composer.json package framework. Jika nama tidak pernah dikenal oleh instalasi mana pun, lookup melempar exception yang kemudian dibaca sebagai "framework tidak dipasang sebagai package" dan menghasilkan null. Versi null membuat seluruh constraint requiresPanel dilewati secara diam-diam. Karena itu test suite package membandingkan konstanta tersebut terhadap composer.json, sehingga rename package tidak dapat tanpa sengaja mematikan compatibility check.
Jika Anda mengganti nama package pada fork, konstanta ini harus ikut diubah. Lihat Package Name Migration.
Error message
The [{name}] plugin ([{id}], registered on the [{panelId}] panel) requires
panda-panel {constraint}, and {installed} is installed. Upgrade the plugin, or
pin this framework to a version it supports.2
3
Lima fakta sengaja dicantumkan karena itulah informasi yang biasanya tidak tersedia dari stack trace: human-readable plugin name, ID yang dapat dicari di codebase, Panel tempat plugin dipasang, constraint yang diminta, dan versi yang benar-benar terpasang.
{name} berasal dari metadata()->name. Plugin yang tidak pernah mendeklarasikan metadata tetap dilaporkan menggunakan ID yang diubah menjadi title.
Hal yang tidak dilakukan pemeriksaan ini
Tidak menggantikan
requiremilik Composer. Package plugin tetap seharusnya mendeklarasikan"chocoalano/panel": "^1.2"dicomposer.json. Composer adalah lapisan pertama yang mencegah versi salah dipasang.requiresPaneladalah backstop untuk kondisi yang tidak dapat dilihat Composer: path repository,--ignore-platform-reqs, atau plugin yang ditempatkan langsung diapp/.Tidak memeriksa dependency antar-plugin. Plugin yang memerlukan plugin lain harus memeriksanya sendiri di
register():phppublic function register(Panel $panel): void { if (! $panel->hasPlugin('acme-billing')) { throw new RuntimeException('The reporting plugin requires the billing plugin.'); } }1
2
3
4
5
6Ini hanya bekerja jika billing ditulis lebih dulu di
plugins([...]), karenaregister()berjalan sesuai urutan array.Tidak memeriksa versi PHP, Laravel, atau Vue. Itu tanggung jawab Composer dan build system.
Tidak memeriksa frontend compatibility. Plugin dengan Vue component lama tetap dapat lolos version check tetapi gagal di browser. Lihat Upgrade Guide dan Published Asset Structure.
Catatan
- Check berjalan setiap application boot, termasuk pada console, karena
plugins()juga berjalan. Pekerjaannya hanya string comparison dan semver evaluation, tanpa filesystem atau network access. metadata()dipanggil olehassert()sebelumregister(). Metadata yang melakukan query akan menimbulkan masalah lifecycle yang sama sepertiregister()yang melakukan query.- Plugin dapat menaikkan constraint-nya pada versi baru tanpa mengganti ID. Aplikasi yang memakai
hasPlugin('acme-reporting')sedang menanyakan keberadaan plugin, bukan release tertentu.