
Menulis paket Anda untuk MODX tidak mudah bagi pemula, dan pengembang yang berpengalaman terkadang memiliki waktu yang menyenangkan. Tetapi pemula takut, dan yang berpengalaman mengerti :).
Posting ini berbicara tentang bagaimana Anda dapat menulis dan membangun paket komponen untuk MODX tanpa menginstal dan mengkonfigurasi MODX itu sendiri. Levelnya di atas rata-rata, jadi Anda mungkin harus memeras otak Anda dalam beberapa kasus, tetapi itu sepadan.
Saya meminta detail di bawah kucing.
Suatu ketika, ketika MODX Revolution baru saja muncul, itu dalam versi beta awal, para pengembang belum tahu bagaimana bekerja dengannya dan bagaimana menulis plugin untuk itu. Ya, kecuali tim yang meneliti CMS. Dan tim, saya harus mengatakan, sebagian berhasil dan menyediakan sistem dengan kemampuan untuk dengan mudah mengumpulkan paket yang kemudian dapat diinstal melalui repositori, yang tampaknya logis. Namun sejak itu, bertahun-tahun telah berlalu dan persyaratan untuk paket dan perakitannya telah sedikit berubah.
Copy-paste itu jahat, meski tidak selalu
Selama beberapa bulan terakhir, saya dihantui oleh pemikiran mengapa, untuk membangun paket untuk MODX, Anda harus menginstalnya, membuat database, membuat admin, dll. Begitu banyak aksi ekstra. Tidak, tidak ada yang salah dengan ini jika Anda mengaturnya sekali dan kemudian menggunakannya. Banyak yang melakukannya. Tetapi bagaimana ketika Anda ingin mempercayakan naskah kepada skrip, dan pergi dan minum kopi sendiri?
Kebetulan bahwa pencipta MODX digunakan untuk bekerja dengan MODX itu sendiri dan menambahkan kelas ke paket langsung ke kernel. Mereka juga menulis komponen pertama, skrip build pertama, yang kemudian digunakan sebagai contoh oleh pengembang lain yang hanya menyalin solusi, tidak selalu menggali esensi dari apa yang terjadi. Dan saya berhasil.
Tetapi tugasnya adalah untuk mengotomatiskan perakitan paket, lebih disukai di server, selalu dengan perangkat lunak minimum yang diperlukan, dengan sumber daya minimal dan karenanya dengan kecepatan yang lebih besar. Tugasnya sudah diatur dan setelah mempelajari sumbernya, Jason yang mengerem dalam obrolan menemukan solusinya.
Dan yang mana?
Hal pertama yang saya temukan adalah bahwa kode yang bertanggung jawab untuk membangun paket secara langsung terletak di pustaka xPDO, dan di MODX hanya ada kelas pembungkus yang menyediakan API yang lebih nyaman dan agak lebih mudah untuk dikerjakan, tetapi hanya jika MODX diinstal. Oleh karena itu, mungkin hanya xPDO yang dapat digunakan, tetapi dalam kode, konstruktor objek xPDO mengharuskan Anda menentukan data untuk koneksi database.
public function __construct( $dsn, $username = '', $password = '', $options = [], $driverOptions= null );
Setelah menginterogasi Jason, menjadi jelas bahwa meskipun parameter perlu diatur, koneksi fisik nyata ke database terjadi tepat pada saat diperlukan. Malas memuat semua kemuliaan. Masalah kedua telah diatasi.
Masalah ketiga adalah masalah menghubungkan xPDO ke proyek. Composer segera muncul di pikiran, tetapi versi 2.x yang dijalankan oleh MODX saat ini tidak mendukung Composer, dan cabang 3.x menggunakan ruang nama dan nama kelas ditulis berbeda dari 2.x, yang mengarah pada konflik dan kesalahan. Secara umum, tidak kompatibel. Kemudian saya harus menggunakan alat git dan menghubungkan xPDO sebagai submodule.
Cara menggunakan submodula
Pertama, baca dokumentasinya .
Kemudian, jika ini adalah proyek baru, Anda perlu menambahkan submodule:
$ git submodule add https://github.com/username/reponame
Perintah ini akan mengkloning dan menginstal submodule di proyek Anda. Maka Anda perlu menambahkan folder submodule ke repositori Anda dengan perintah git add. Itu tidak akan menambahkan seluruh folder dengan submodule, tetapi akan menambah hanya git tautan ke komit terakhir dari submodule.
Agar pengembang lain dapat mengkloning proyek dengan semua dependensi, Anda perlu membuat konfigurasi .gitmodules untuk submodula. Dalam proyek Slackify, seperti ini:
[submodule "_build/xpdo"] path = _build/xpdo url = https://github.com/modxcms/xpdo.git branch = 2.x
Setelah itu, saat kloning, cukup tentukan flag rekursif dan git akan mengunduh semua repositori dependen.
Akibatnya, kita memiliki xPDO, xPDO dapat digunakan tanpa terhubung ke database, jika tidak diperlukan, xPDO dapat dihubungkan ke kode komponen sebagai ketergantungan eksternal (git submodule). Sekarang implementasi skrip build.
Mari kita mengerti
Saya akan menjelaskan
skrip build dari add
Slackify -pada baru-baru ini diposting oleh saya. Komponen ini gratis dan tersedia untuk umum di GitHub, yang akan memfasilitasi belajar mandiri.
Hubungkan xPDO
Kami menghilangkan tugas konstanta dengan nama paket dan panggilan lain yang diperlukan dan menghubungkan xPDO.
require_once 'xpdo/xpdo/xpdo.class.php'; require_once 'xpdo/xpdo/transport/xpdotransport.class.php'; $xpdo = xPDO::getInstance('db', [ xPDO::OPT_CACHE_PATH => __DIR__ . '/../cache/', xPDO::OPT_HYDRATE_FIELDS => true, xPDO::OPT_HYDRATE_RELATED_OBJECTS => true, xPDO::OPT_HYDRATE_ADHOC_FIELDS => true, xPDO::OPT_CONNECTIONS => [ [ 'dsn' => 'mysql:host=localhost;dbname=xpdotest;charset=utf8', 'username' => 'test', 'password' => 'test', 'options' => [xPDO::OPT_CONN_MUTABLE => true], 'driverOptions' => [], ] ] ]);
Saya menambahkan submodule xPDO ke folder _build, yang kita perlukan hanya pada tahap pengembangan dan perakitan paket dan yang tidak akan masuk ke arsip utama komponen. Salinan kedua xPDO di situs dengan MODX langsung yang tidak kita butuhkan.
Dalam pengaturan koneksi xPDO, saya mengatur nama database di
dsn
, tetapi tidak memainkan peran apa pun. Adalah penting bahwa folder cache di dalam xPDO dapat ditulis. Itu saja, xPDO diinisialisasi.
Membuat hack yang rumit dengan kelas-kelas
Saat menggunakan MODX yang terinstal saat membuat paket, semuanya sederhana, kami mengambil dan membuat objek dari kelas yang kami butuhkan. MODX benar-benar menemukan kelas yang diperlukan, menemukan implementasi yang diperlukan untuk kelas ini (kelas dengan postfix _mysql), yang tergantung pada database dan kemudian membuat objek yang diinginkan (karena fitur ini, Anda mungkin mendapatkan kesalahan ketika membangun paket yang kelasnya * _mysql tidak ditemukan, ini tidak menakutkan). Namun, kami tidak memiliki basis atau implementasi. Kita perlu entah bagaimana mengganti kelas yang diinginkan, yang sedang kita lakukan.
class modNamespace extends xPDOObject {} class modSystemSetting extends xPDOObject {}
Kami membuat kelas dummy (rintisan), yang diperlukan untuk membuat objek yang diinginkan. Ini tidak harus dilakukan jika xPDO tidak secara khusus memeriksa kelas objek yang dimiliki. Tapi dia memeriksa.
Tetapi ada beberapa kasus khusus ketika Anda perlu melakukan sedikit lebih dari sekedar mendefinisikan kelas. Ini adalah kasus ketergantungan antar kelas. Misalnya, kita perlu menambahkan plugin ke kategori. Dalam kode, hanya
$category->addOne($plugin);
tetapi dalam kasus kami ini tidak akan berhasil.
Jika Anda pernah melihat
skema database MODX , Anda mungkin melihat elemen seperti agregat dan komposit. Itu ditulis tentang mereka dalam
dokumentasi , tetapi jika dengan cara yang sederhana, mereka menggambarkan hubungan antar kelas.
Dalam kasus kami, mungkin ada beberapa plugin dalam suatu kategori, di mana elemen agregat bertanggung jawab atas kelas
modCategory
. Oleh karena itu, karena kita memiliki kelas tanpa implementasi konkret, kita perlu menunjukkan koneksi ini dengan tangan. Lebih mudah untuk melakukan ini dengan
getFKDefinition
metode
getFKDefinition
:
class modCategory extends xPDOObject { public function getFKDefinition($alias) { $aggregates = [ 'Plugins' => [ 'class' => 'modPlugin', 'local' => 'id', 'foreign' => 'category', 'cardinality' => 'many', 'owner' => 'local', ] ]; return isset($aggregates[$alias]) ? $aggregates[$alias] : []; } }
Di komponen kami, hanya plugin yang digunakan, jadi kami menambahkan tautan hanya untuk mereka. Setelah itu, metode addMany dari kelas modCategory dapat dengan mudah menambahkan plugin yang diperlukan ke kategori, dan kemudian ke paket.
Buat paket
$package = new xPDOTransport($xpdo, $signature, $directory);
Seperti yang Anda lihat, semuanya sangat, sangat sederhana. Di sini kami perlu melewati parameter
$xpdo
, yang kami inisialisasi di awal. Jika tidak untuk saat ini, tidak akan ada masalah 2.
$signature
- nama paket, termasuk versi,
$directory
- tempat paket akan ditempatkan dengan hati-hati. Dari mana variabel-variabel ini berasal, lihat sendiri di sumbernya.
Buat namespace dan tambahkan ke paket
Kami membutuhkan namespace untuk mengikat lexicons dan pengaturan sistem untuk itu. Dalam kasus kami, hanya untuk ini, yang lain belum dipertimbangkan.
$namespace = new modNamespace($xpdo); $namespace->fromArray([ 'id' => PKG_NAME_LOWER, 'name' => PKG_NAME_LOWER, 'path' => '{core_path}components/' . PKG_NAME_LOWER . '/', ]); $package->put($namespace, [ xPDOTransport::UNIQUE_KEY => 'name', xPDOTransport::PRESERVE_KEYS => true, xPDOTransport::UPDATE_OBJECT => true, xPDOTransport::RESOLVE_FILES => true, xPDOTransport::RESOLVE_PHP => true, xPDOTransport::NATIVE_KEY => PKG_NAME_LOWER, 'namespace' => PKG_NAME_LOWER, 'package' => 'modx', 'resolve' => null, 'validate' => null ]);
Bagian pertama jelas bagi siapa saja yang pernah menulis kode untuk MODX. Yang kedua, dengan tambahan paket, sedikit lebih rumit. Metode
put
mengambil 2 parameter: objek itu sendiri dan berbagai parameter yang menggambarkan objek ini dan perilaku yang mungkin terjadi pada saat menginstal paket. Sebagai contoh,
xPDOTransport::UNIQUE_KEY => 'name'
berarti bahwa untuk namespace, bidang
name
dengan nama namespace itu sendiri sebagai suatu nilai akan digunakan sebagai kunci unik dalam database. Anda dapat membaca lebih lanjut tentang parameter
dalam dokumentasi xPDO , dan lebih baik dengan mempelajari kode sumber.
Dengan cara yang sama, Anda dapat menambahkan objek lain, seperti pengaturan sistem.
$package->put($setting, [ xPDOTransport::UNIQUE_KEY => 'key', xPDOTransport::PRESERVE_KEYS => true, xPDOTransport::UPDATE_OBJECT => true, 'class' => 'modSystemSetting', 'resolve' => null, 'validate' => null, 'package' => 'modx', ]);
Buat kategori
Dengan tambahan kategori, saya memiliki lelucon terbesar ketika saya menemukan jawabannya. Elemen-elemen yang dimasukkan ke dalam kategori dalam model xPDO harus keduanya termasuk dalam kategori ini, mis. bersarang di dalamnya, dan hanya kemudian kategori itu sendiri harus disarangkan dalam paket. Dan pada saat yang sama, Anda perlu memperhitungkan hubungan antar kelas, yang telah saya jelaskan di atas. Butuh waktu yang cukup lama untuk memahami, menyadari, dan menerapkannya dengan benar.
$package->put($category, [ xPDOTransport::UNIQUE_KEY => 'category', xPDOTransport::PRESERVE_KEYS => false, xPDOTransport::UPDATE_OBJECT => true, xPDOTransport::ABORT_INSTALL_ON_VEHICLE_FAIL => true, xPDOTransport::RELATED_OBJECTS => true, xPDOTransport::RELATED_OBJECT_ATTRIBUTES => [ 'Plugins' => [ xPDOTransport::UNIQUE_KEY => 'name', xPDOTransport::PRESERVE_KEYS => false, xPDOTransport::UPDATE_OBJECT => false, xPDOTransport::RELATED_OBJECTS => true ], 'PluginEvents' => [ xPDOTransport::UNIQUE_KEY => ['pluginid', 'event'], xPDOTransport::PRESERVE_KEYS => true, xPDOTransport::UPDATE_OBJECT => false, xPDOTransport::RELATED_OBJECTS => true ] ], xPDOTransport::NATIVE_KEY => true, 'package' => 'modx', 'validate' => $validators, 'resolve' => $resolvers ]);
Itu terlihat mengerikan, tetapi tidak begitu terlihat. Parameter penting adalah
xPDOTransport::RELATED_OBJECTS => true
, yang menunjukkan bahwa kategori tersebut memiliki elemen bersarang yang juga perlu dikemas dan kemudian diinstal.
Karena sebagian besar modul berisi berbagai elemen (bongkahan, cuplikan, plugins), kategori dengan elemen adalah bagian terpenting dari paket transportasi. Oleh karena itu, di sini validator dan resolver ditentukan, yang dilakukan selama instalasi paket.
Validator dilakukan sebelum instalasi, resolvers - after.
Saya hampir lupa, sebelum mengemas kategori, kita perlu menambahkan elemen kita ke dalamnya. Seperti ini:
$plugins = include $sources['data'] . 'transport.plugins.php'; if (is_array($plugins)) { $category->addMany($plugins, 'Plugins'); }
Tambahkan data lain ke paket.
Dalam paket Anda perlu menambahkan file lain dengan lisensi, file dengan log perubahan dan file dengan deskripsi komponen. Jika perlu, Anda dapat menambahkan skrip khusus lain melalui atribut
setup-options
, yang akan menampilkan jendela sebelum menginstal paket. Ini adalah saat alih-alih "Instal" tombol "Opsi Instalasi". Dan dari versi MODX 2.4 menjadi mungkin untuk menentukan dependensi antara paket menggunakan atribut yang
requires
, dan di dalamnya Anda juga dapat menentukan versi PHP dan MODX.
$package->setAttribute('changelog', file_get_contents($sources['docs'] . 'changelog.txt')); $package->setAttribute('license', file_get_contents($sources['docs'] . 'license.txt')); $package->setAttribute('readme', file_get_contents($sources['docs'] . 'readme.txt')); $package->setAttribute('requires', ['php' => '>=5.4']); $package->setAttribute('setup-options', ['source' => $sources['build'] . 'setup.options.php']);
Kami berkemas
if ($package->pack()) { $xpdo->log(xPDO::LOG_LEVEL_INFO, "Package built"); }
Itu saja, ambil paket yang sudah jadi di
_packages
, well, atau dari mana Anda mengkonfigurasi assembly.
Apa hasilnya?
Hasilnya melebihi harapan saya, karena pendekatan ini, meskipun memberlakukan beberapa batasan dan di beberapa tempat menambah beberapa ketidaknyamanan, tetapi menang dalam hal kemungkinan aplikasi.
Untuk membangun paket, cukup jalankan 2 perintah:
git clone --recursive git@github.com:Alroniks/modx-slackify.git cd modx-slackify/_build && php build.transport.php
Yang pertama adalah kloning dari repositori dan submodulanya. Parameter penting adalah
--recursive
, berkat itu git akan mengunduh dan menginstal, selain kode komponen itu sendiri, semua dependensi digambarkan sebagai submodul.
Yang kedua adalah membangun paket secara langsung. Setelah itu, Anda dapat mengambil
package-1.0.0-pl.transport.zip
yang sudah
_packages
folder
_packages
dan memuatnya, misalnya, ke dalam repositori.
Prospeknya luas. Misalnya, Anda dapat mengonfigurasi kail di GitHub, yang, setelah melakukan ke cabang, akan menjalankan skrip di server Anda yang akan mengumpulkan paket dan meletakkannya di semua situs yang Anda miliki. Atau unggah versi baru ke beberapa repositori, dan pada saat itu Anda akan membuat kopi untuk diri sendiri, seperti yang saya katakan di awal. Atau Anda dapat membuat dan menulis tes untuk modul dan menjalankan uji coba dan membangun melalui Jenkins atau Travis. Ya, banyak skenario yang bisa Anda buat. Dengan pendekatan ini, melakukan ini sekarang jauh lebih mudah.
Ajukan pertanyaan, coba jawab.
PS Jangan lewat,
letakkan bintang Slackify di GitHub .