Arayüz Bileşenleri

1.7k görüntülenme Markdown

Panelin kurulduğu dört yapı taşı. Eklediğiniz ekran, ürünle gelen ekranlar gibi görünür ve davranır.

Genel Bakış

Bileşen PHP'de kurulur ve şablonun içinde görünür: controller ne istediğini tarif eder, bileşen işaretlemeyi üretir. Sıralama, filtreleme, sayfalama ve sekme hafızası yeniden yazılmadan gelir.

Dördü de WISECP\Components altındadır ve new ile kurulur. Hepsi içeriğini konumsal argümanlarla değil bir seçenek dizisiyle alır.

Referans

Table

WISECP\Components\Table
public function __construct(string $name, array $options = []);   // $name = preset dosya adı

public function setColumns(array $columns): self;
public function setColumn(string $key, array $data): self;
public function deleteColumn(string $key): self;
public function setRows(array $rows): self;
public function setRowRender(callable $renderRow): self;
public function setFilters(array $filters): self;
public function setOptions(array $options): self;
public function getOptions(): array;

public function isRequestAjax(): bool;
public function ajaxControl(array $options = []): string;
public function allDataAjaxResponse(): string;
public function ajaxResponse(int $totalEntries = 0, int $totalSearchEntries = 0): string;

public function build(string $format = ''): string;        // '' = tüm tablo, 'justBody' = yalnız satırlar
public function buildList(string $format = ''): string;    // ızgara yerine kart satırları
public function container(string $content, array $attributes = []): string;
public function exportButton(array $options = []): string; // ['label', 'formats', 'class']

// Genel property'ler. İki model, bileşenin kendisinin çağırdığı closure'lardır.
public int $ajax_transition_limit = 500;
public mixed $totalModel;   // fn (string $search = '', array $filters = []): int
public mixed $dataModel;    // fn (string $search = '', string $order = '', string $direction = '', int $start = 0, int $end = -1): array

Kurucu seçenekleri, hepsi isteğe bağlı. Kurucu preset dosyasını kendisi include eder, controller başka hiçbir şeyi atamadan önce; bu yüzden preset seçenekleri getOptions() ile okur, satırları asla görmez.

preset Tablonun kendi adı yerine başka bir preset dosyası yükler; örn. ana listenin kolonlarını kullanan pano widget'ı için 'ticketList'.
lazy true ilk sorguyu sekme açılana kadar erteler. Detay sekmesi için değil; pahalı kaynaklar için (dosya sistemi taraması, uzak katalog).
perPage · perPageOptions · search · info · pagination Araç çubuğu anahtarları. false kontrolü kaldırır; [10, 25, 50, 100, -1] sayfa boyutlarını verir, -1 tümü demektir.
renderer 'list' müşteri panelinin kullandığı kart düzenine geçirir. Başka her değer ızgara verir.
export · exportPrivilege · exportName İndirme varsayılan açıktır. false kaldırır, bir yetki anahtarı daraltır, ad da dosya adı olur. Bunları controller'da verin: dışa aktarma isteği şablon çalışmadan sonlanır.
containerExtraAttributes Sarmalayıcıya yazılan attribute haritası; örn. filtreleri tarayıcı adresine yansıtmak için ['data-url-sync' => 'true'].

ajaxControl() kendi dizisini alır; isteği zaten yanıtladıysa boş olmayan, aksi hâlde boş bir dize döner. Çağıran taraf onu olduğu gibi döndürür.

baseLink Veri isteğinin kurulduğu adres. Alt sayfada bu, alt sayfanın tam adresi olmalıdır; controller kökü sayfa metoduna hiç ulaşmaz ve liste boş döner.
mode 'partial' (varsayılan) sunucuda sayfalar; 'allData' tüm kümeyi tek yanıtta verir.
ajaxExtraParams Her veri isteğinde taşınan ek sorgu değerleri; örn. ['type' => 'hosting'].
force Satır sayısı eşiğini ezer. Yalnız filtreler sorgunun kendisini şekillendiriyorsa meşrudur; gerekçesini yanına yazın.

setRowRender() geri çağrınızın aldığı ve geri verdiği satırın üç parçası vardır:

tek bir satırın şekli
$row = [
    // Kaydın modelden geldiği hali. Salt-okunur girdi.
    'model' => ['id' => 5, 'name' => 'example.com', 'status' => 'active'],

    // Kolon anahtarı başına bir giriş. 'value' hücre işaretlemesi, 'attributes' <td>'ye iner.
    // 'data-value' sıralamanın ve istemci tarafı filtrelemenin karşılaştırdığı HAM değerdir.
    'data' => [
        'id'     => ['value' => '<a href="...">#5</a>', 'attributes' => ['data-value' => 5]],
        'status' => ['value' => '<span class="badge">Aktif</span>', 'attributes' => ['data-value' => 'active']],
    ],

    // <tr> attribute'ları. Satır seviyesi filtre değerleri buradan okunur.
    'attributes' => ['class' => 'table-tr-bg-info', 'data-filter-status' => 'active'],
];

Tab ve Accordion

WISECP\Components\Tab · WISECP\Components\Accordion
// Tab. $type 'horizontal' ya da 'vertical'. add() İKİ argüman alır:
// panel anahtarı, sonra bir seçenek dizisi. Panel gövdesi $options['content']'tir.
public function __construct($name = '', $type = 'horizontal');
public function add($name, $options = []): self;
public function set($name, $options = []): self;                 // add() ile aynı
public function get($name = '');
public function remove($name = ''): self;
public function noUrl(bool $noUrl = true): self;
public function render(array $options = [], string $header = '', string $contents = ''): string;
public function header($options = []): string;
public function contents(array $options = []): string;

// Accordion. Aynı fikir, tipli, ve dikey/yatay seçimi yok.
public function __construct(string $name = '');
public function add(string $name, array $options = []): self;
public function set(string $name, array $options = []): self;
public function get(string $name = '');
public function remove(string $name): self;
public function noUrl(): self;
public function render(array $options = []): string;
content Panelin işaretlemesi. İki bileşenin de içeriği aldığı tek yer burasıdır; boş panel boş kalır, boş durumu kendiniz verirsiniz.
title Sekmenin ya da akordiyon başlığının etiketi. Yoksa anahtara düşer; çevrilmemiş bir panelin anahtarını göstermesinin sebebi budur.
icon İkon sınıfı, örn. 'bi bi-gear'. Yatay sekmede boşluk sınıfı iconClass'tan gelir ve varsayılanı 'me-2''dir.
badge · badgeClass Yalnız Tab: sekmenin içinde, etiketinden sonra görünen sayaç. Boş olmayan her değer görünür, '0' dahil.
subtitle · hideContentTitle Yalnız Tab, dikey düzen: rail'deki ikinci satır ve panelin tekrar ettiği başlığı bastıran anahtar.
show Yalnız Accordion: true bu bölümü açık başlatır. Bölümler ortak bir ebeveyni paylaşır, biri açılınca diğerleri kapanır.
headerTag · titleClass · buttonClass · bodyClass Yalnız Accordion: başlık elemanı (varsayılan 'h2') ve başlığın, tetikleyicinin (varsayılan 'bg-light', temizlemek için '') ve gövdenin sınıfları.

İkisi de açık paneli adreste, bileşenin kendi adı altında hatırlar: settings adlı bir sekme kümesi ?settings=general okur. Tek ekrandaki iki küme farklı ad ister.

WISECP\Components\Modal
// Her şey kurucuda verilir; setter'lar sonradan değiştirmek içindir
// ve void döndükleri için ZİNCİRLENMEZLER.
public function __construct(array $params);
public function setTitle(string $title): void;
public function setBody(string $body): void;
public function setFooter(string $footer): void;
public function setForm(?array $formAttributes): void;   // attribute haritası, sarmayı kaldırmak için null
public function setHeaderClasses(array $classes): void;
public function render(): string;
id DOM id'si ve tetikleyicinin işaret ettiği hedef. Varsayılanı 'SampleModal', yani id'siz iki pencere çakışır.
title · body · bodyClass · footer Başlık, içerik işaretlemesi, gövdeye ek sınıflar ve alt bölüm. Boş bir footer hiç oluşturulmaz.
form Başlığı, gövdeyi ve alt bölümü bir <form> içine saran attribute haritası: ['action' => $url, 'method' => 'POST']. Her çift attribute olarak yazılır, footer'daki gönder butonu pencereyi gönderir. Salt-okunur pencerede vermeyin.
headerClasses Yalnız tonu seçer: içinde danger geçen bir değer kırmızı başlık, başkası birincil başlık verir. Kabuk sabittir, renkli bir şerit boyayamaz.
modalDialogExtraClass · scrollable · centered 'modal-lg' gibi genişlik sınıfı ve ikisi de true varsayılanlı iki düzen anahtarı.
attributes Dış elemandaki varsayılanların üzerine birleştirilen ham attribute'lar. Perdeyi kilitlemenin desteklenen tek yolu budur.

Örnek

Bir liste üç dosya alır: controller veriyi bağlar, preset kolonları tanımlar ve her satırı modelden kurar, sayfa şablonu sonucu gösterir.

controller
$table = new \WISECP\Components\Table('widgetList', ['exportName' => 'widgets']);

// Operatörün seçtiği değerler. setFilters bunları veri isteğinde taşır;
// model ise yalnız bir isteği yanıtlarken alır.
$dynamic = [];
if ($status = Filter::init("REQUEST/filter/status", "route")) $dynamic['status'] = $status;

$table->setFilters($dynamic);
$filter = $table->isRequestAjax() ? $dynamic : [];

$table->totalModel = fn ($search = '', $filters = []) =>
    $this->model->list(true, array_merge($filter, $filters, ['word' => $search]));

$table->dataModel = fn ($search = '', $order = '', $direction = '', $start = 0, $end = -1) =>
    $this->model->list(false, array_merge($filter, ['word' => $search]), [$order => $direction], $start, $end);

// Boş olmayan dönüş, isteğin burada zaten yanıtlandığı anlamına gelir.
if ($response = $table->ajaxControl(['baseLink' => $links["controller"]])) return $response;

$this->addData('table', $table);
templates/admin/tables/widgetList.php
/** @var \WISECP\Components\Table $table */
if (!isset($table)) return;

$table->setColumns([
    'id'     => ['title' => 'ID', 'attributes' => ['class' => 'text-center'], 'sortable' => true],
    'name'   => ['title' => Language::gc("admin/widgets/th-name"), 'sortable' => true],
    'status' => ['title' => Language::gc("admin/widgets/th-status"), 'sortable' => "asc"],
    'email'  => ['title' => Language::gc("admin/widgets/th-email"), 'exportOnly' => true],
]);

$table->setRowRender(function ($row) {
    $id = (int) $row["model"]["id"];

    $row["data"]["id"]["value"]                     = '<a href="?id=' . $id . '">#' . $id . '</a>';
    $row["data"]["id"]["attributes"]["data-value"]  = $id;

    $row["data"]["name"]["value"] = htmlspecialchars($row["model"]["name"] ?? '');

    // Filtrenin karşılaştırdığı ham değerdir; hücre rozeti gösterir.
    $row["data"]["status"]["value"]                    = \WISECP\AdminComponents\Statuses::getInstance()->service($row["model"]["status"]);
    $row["data"]["status"]["attributes"]["data-value"] = $row["model"]["status"];

    // Ekranda çizilmez, indirmede vardır.
    $row["data"]["email"]["value"] = $row["model"]["email"] ?? '';

    $row["attributes"]["data-filter-status"] = $row["model"]["status"];

    return $row;
});
templates/admin/widgets/list.php
// Sayfa şablonu basmadan hiçbir şey görünmez. Preset zaten kurucunun içinde çalıştı,
// bu çağrı yalnız controller ile preset'in kurduğunu render eder.
if (isset($table)) {
    $table->setOptions(['containerExtraClass' => 'mt-3']);
    echo $table->build();
}

Bir sekme kümesi ve bir pencere, ikisi de seçenek dizisiyle beslenir:

koşullu panelli sekme kümesi ve gönderim yapan pencere
// footer.php $modals içinde ne varsa basar; şablon onu bir kez burada tanımlar
// ve sayfadaki her pencere üzerine ekler.
$modals = '';

$tab = new \WISECP\Components\Tab('widget-detail');

$tab->add('overview', [
    'title'   => Language::g('widgets-overview'),
    'icon'    => 'bi bi-grid-1x2',
    'content' => $overviewHtml,
]);

// Koşul BURADA, bir kez. Paneli okuyan biri sekmenin bir şey düştüğü için değil
// bu kural yüzünden görünmediğini böylece bilir.
if ((int) Config::get('options/reselling/status') === 1)
    $tab->add('reselling', [
        'title'   => Language::g('widgets-reselling'),
        'badge'   => $pendingCount,
        'content' => $resellingHtml,
    ]);

echo $tab->render();

$modal = new \WISECP\Components\Modal([
    'id'                    => 'widgetDeleteModal',
    'title'                 => Language::g('needs/delete'),
    'body'                  => '<p>' . Language::gc('admin/widgets/delete-confirm') . '</p>'
                             . '<input type="hidden" name="operation" value="delete_widget">',
    'footer'                => '<button type="submit" class="btn btn-danger">' . Language::g('needs/delete') . '</button>',
    'headerClasses'         => ['bg-danger'],
    'modalDialogExtraClass' => 'modal-lg',
    'form'                  => ['action' => $links["controller"], 'method' => 'POST'],
]);

$modals .= $modal->render();

Tuzaklar

Tab ve Accordion anahtar + seçenek dizisi alır, etiket + gövde değil

add('overview', 'Genel Bakış', $html) yazmak, seçenek dizisinin beklendiği yere bir dize ve var olmayan bir üçüncü argüman geçirir. Panel, başlığı olarak anahtarını gösterir ve hiç içerik taşımaz, hata da vermez. Gövde $options['content']'tir.

Pencerenin setter'ları hiçbir şey döndürmez, zincirlenemez

Her setter void tiplidir. Birini diğerine zincirlemek null üzerinde ölümcül bir çağrıdır. Her şeyi kurucu dizisinde verin; setter'lar zaten verdiğiniz bir değeri değiştirmek içindir.

Sayfalamanın nerede olacağına satır sayısı karar versin

Bileşen, toplam eşiği aştığı anda sunucu tarafı sayfalamaya kendisi geçer. Bu kararı çağrı yerinde zorlarsanız ya elli bin satır tek belgeye girer ya da yirmi satır için fazladan bir tur ödersiniz.

İç içe sekme kümesi adresin dışında kalmalı

Adrese yazan iki küme onun için çekişir, operatör geri döndüğünde yanlış çiftte açılır. İçteki küme noUrl() çağırır.

Faydalı oldu mu?

Geri bildiriminiz için teşekkürler!

Hâlâ Yardıma mı İhtiyacınız Var?

Yukarıda bulamadığınız her şey için destek ekibimiz her zaman yanınızda.