بیان خلاصه ای از بحث توسط هوش مصنوعی:
در فصل های قبلی، ما یک افزونه عالی برای مدیریت پروژه ساده ایجاد کردیم. ما خیلی کار کردیم و یک کامپوننت، چند پلاگین، یک ماژول، برخی Override و حتی یک قالب چایلد توسعه دادیم. این کار زیادی است که باید برای خود نگه دارید، بنابراین احتمالاً می خواهید آن را در جهان منتشر کنید.
در این فصل، یاد خواهید گرفت که چگونه افزونه خود را آماده کنید تا بتوانید تمام مراحلی را که برای انتشار آن در جهان باید دنبال کنید و حتی نحوه دریافت پول برای آن را منتشر کنید.
در پایان این فصل، می دانید که چگونه با توسعه خود یک بسته قابل توزیع ایجاد کنید که بتوان آن را در سایت های زیادی که امکان دارد، نصب کرد. همچنین می دانید که چگونه تغییرات پایگاه داده را به طور خودکار مدیریت کنید و چگونه در هنگام نصب بسته های خود کارهای پیشرفته را انجام دهید. در نهایت، خواهید دید که چقدر آسان است که یک درگاه پرداخت به افزونه خود اضافه کنید و دانلود ها را به افراد بعد از پرداخت محدود کنید.
اینها موضوعاتی است که در این فصل به آنها خواهیم پرداخت:
- ایجاد یک بسته برای افزونه های شما
- نحوه مدیریت تغییرات پایگاه داده در افزونه های خود
- نحوه اجرای وظایف پیشرفته در نصب افزونه
- راه اندازی سرور بروز رسانی
- افزودن یک دیوار پرداخت به دانلود افزونه شما
الزامات فنی
در این فصل، ما فایل های بسته را برای توزیع افزونه های خود ایجاد می کنیم، بنابراین به موارد زیر نیاز خواهید داشت:
- Visual Studio Code یا یک ویرایشگر کد دلخواه شما
- فایل های کد این فصل را می توانید در GitHub در بیابید:
https://github.com/PacktPublishing/Developing-Extensions-for-Joomla-5/tree/chapter14
ایجاد یک بسته برای افزونه های شما
در جوملا، افزونه ها در قالب بسته بندی توزیع می شوند. این بسته ها شامل یک فایل فشرده (معمولا با فرمت zip) است که تمام فایل های افزونه را در خود جای می دهد و یک فایل مانیفست که حاوی دستورالعمل های جوملا در مورد نحوه قرار دادن فایل ها در جوملا است.
در فصل 2 ، ما اولین بسته را برای کامپوننت com_spm ایجاد کردیم. برای ایجاد این فایلzip ، ما فقط محتویات پوشه src/component را فشرده کردیم. این کار به این دلیل بود که ما فایل مانیفست ( src/component/spm.xml ) را در پوشه اصلی بسته ZIP قرار داده بودیم. بیایید به بخش های مختلف فایل مانیفست خود نگاه کنیم. فایل /src/component/spm.xml را باز کنید. خطوط زیر را در ابتدا و انتهای فایل مشاهده خواهید کرد:
<? xml version="1.0" encoding="utf-8" ?>
<extension type="component" method="upgrade">
...
</extension>
در این خطوط، استاندارد XML مورد استفاده و نوع افزونه ای که باید نصب کنیم را اعلام می کنیم. در فایل مانیفست ترتیب بخش ها مهم نیست. روش معمول این است که متادیتا را در ابتدای فایل قرار دهید:
<name>COM_SPM</name>
<author><![CDATA[Carlos Cámara]]></author>
<authorEmail>این آدرس ایمیل توسط spambots حفاظت می شود. برای دیدن شما نیاز به جاوا اسکریپت دارید </authorEmail>
<authorUrl>extensions.hepta.es</authorUrl>
<creationDate>2022-07-21</creationDate>
<copyright>(C) 2023 Piedpiper Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<version>0.1.0</version>
<description><![CDATA[COM_SPM_DESCRIPTION]]></description>
این ابرداده بر عملکرد افزونه ی شما تأثیر نمی گذارد، اما مهم است که به کاربر اجازه دهید، درباره افزونه، اطلاعات بیشتری کسب کند. اطلاعات نویسنده در فهرست مدیریت افزونه ها (Manage extensions) نمایش داده می شود و افزودن یک برچسب با اطلاعات مناسب به بسیاری از کاربران شما کمک می کند تا درباره افزونه شما اطلاعات بیشتری کسب کنند.
در زیر اطلاعات فراداده، می توانید تگ فضای نام را پیدا کنید که حاوی فضای نام افزونه ما است:
<namespace path="src">Piedpiper\Component\Spm</namespace>
این تگ به جوملا کمک می کند تا فضای نام خود را به نقشه کلاس های مورد استفاده در فریم ورک اضافه کنید. این نقشه در پوشه cache جوملا در پوشه اصلی نصب جوملای شما ایجاد شده است.
بعد از این تگ مهم، ما بخش administration را داریم:
<administration>
<files folder="admin">
<folder>forms</folder>
<folder>services</folder>
<folder>src</folder>
<folder>tmpl</folder>
<file>access.xml</file>
<file>config.xml</file>
</files>
<menu link="option=com_spm" img="class:default">COM_SPM_MENU_BACKEND</menu>
<submenu>
<menu link="option=com_spm&view=projects" img="default">COM_SPM_PROJECTS
</menu>
<menu link="option=com_categories& view=categories&extension=com_spm"
img="default">COM_SPM_PROJECT_CATEGORIES
</menu>
<menu link="option=com_spm&view=tasks" img="default">COM_SPM_TASKS
</menu>
<menu link="option=com_spm&view=invoices" img="default">COM_SPM_INVOICES
</menu>
</submenu>
</administration>
بخش administrationجوملا را از اقداماتی که باید انجام دهد برای قرار دادن افزونه ما را در backend سایت مطلع می کنیم. در این مورد، با اضافه کردن یک بخش فرعی (subsection) شروع می کنیم. در تگ بخشfiles ، ویژگی folder را اضافه می کنیم که حاوی نام پوشه ای است که در بسته شما حاوی فایل های Backend و پوشه های کامپوننت شما است. بخش فرعی به جوملا کمک می کند تا پوشه مدیر کامپوننت خود را ایجاد کند و این تگ ها را می پذیرد:
- folder با این تگ، نام پوشه ای را در بسته خود که قرار است در قسمت مدیریت کامپوننت شما کپی شود، مشخص می کنید.
- file این تگ نام فایلی را نشان می دهد که در قسمت مدیر کامپوننت شما کپی می شود.
مهم است که توجه داشته باشید که هنگام ایجاد بسته خود، باید آنچه را که پوشه مدیریت کامپوننت شما به نظر می رسد، تکرار کنید. در غیر این صورت، پیچیدگی غیر ضروری را به ساختار اضافه خواهید کرد.
پس از اعلان ساختار فایل ما، فایل مانیفست ما آیتم منو را برای کامپوننت ما در backend اعلام می کند. ما باید از تگmenu برای اعلام نقطه ورودی اصلی کامپوننت خود استفاده کنیم:
<menu link="option=com_spm" img="class:default">
COM_SPM_MENU_BACKEND
</menu>
در این تگ، ما دو ویژگی را می پذیریم:
- link این مسیر به کامپوننت ما در backend را به جوملا می گوید. ما هیچ SEF در backend نداریم، بنابراین باید مسیر URL کامل را به نمای پیش فرض کامپوننت خود نشان دهیم. معمولاً افزودن مقدارoption=com_COMPONENTNAME کافی است، اما می توانید متغیر view را به مسیر URL اضافه کنید.
- Img این پارامتر نام یک کلاس CSS را برای اضافه کردن یک آیکون به URL شما نشان می دهد.
بلافاصله پس از تگ menu ، بخشی را داریم که در آن می توانیم پیوندهای دیگری را به بخش های کامپوننت خود اضافه کنیم:
<submenu>
<menu link="option=com_spm&view=projects" img="default">
COM_SPM_PROJECTS
</menu>
<menu link="option=com_categories&view=categories&extension=com_spm" img="default">
COM_SPM_PROJECT_CATEGORIES
</menu>
<menu link="option=com_spm&view=tasks" img="default">
COM_SPM_TASKS
</menu>
<menu link="option=com_spm&view=invoices" img="default">
COM_SPM_INVOICES
</menu>
</submenu>
وقتی کامپوننت شما مناطق مختلفی دارد، می توانید این زیر منو را اضافه کنید. زمانی که کاربر روی لینک کامپوننت ما کلیک کند نشان داده خواهد شد. همچنین می توانیم از تگ menu برای افزودن لینک به منوی فرعی استفاده کنیم.
همانطور که ما در حال نوشتن پیوندها در یک فایل XML هستیم، باید به قرارداد نوشتن XML توجه کنیم و به آن احترام بگذاریم و از نهاد های HTML برای نوشتن کاراکترهای خاص مانند "&" استفاده کنیم.
پس از تعریف، می توانیم از قسمت فایل های سایت شروع کنیم. در این مورد، از تگ files برای اعلام ساختار فایل در قسمت frontend کامپوننت خود استفاده خواهیم کرد:
<files folder="site">
<folder>src</folder>
<folder>tmpl</folder>
</files>
این بخش دقیقاً مانند قسمتی که در بخش قبلی تعریف کردیم، کار می کند. در تگ folder ، نام پوشه را در بسته آرشیو خود، که شامل ساختار پوشه ما برای قسمت frontend کامپوننت است، اعلام می کنیم.
برای تگ media نیز، می توانیم از کد زیر استفاده کنیم:
<media folder="media" destination="com_spm">
<folder>css</folder>
<folder>js</folder>
<filename>joomla.asset.json</filename>
</media>
این تگ همانند تگ files عمل می کند، اما به جای انتقال فایل ها به قسمت frontend کامپوننت، آنها را به زیر پوشه ای در پوشه media منتقل می کند. این زیر پوشه در ویژگی مقصد (destination) تعریف شده است.
زمانی که جوملا، بسته را دریافت می کند، آن را در پوشه موقت جوملا (معمولاً در پوشه tmp داخل ریشه اصلی نصب جوملا) از حالت فشرده خارج می کند. سپس، فایل مانیفست را می خواند و دستورالعمل ها را برای قرار دادن بسته در سایت ما را دنبال می کند.
مدیریت نسخه ها در افزونه ی خود
در تمام فایل های مانیفست خود، نسخه افزونه را که نصب خواهیم کرد، تعریف کرده ایم. این مهم است زیرا جوملا، هنگام بررسی بروز رسانی، باید نسخه دقیق افزونه ی نصب شده را بداند.
روش رایج در جوملا، استفاده از نسخه سازی معنایی Semantic Versioning است که به اختصار SemVer گفته میشود. این روش افزودن نسخه به افزونه شما، اطلاعات بیشتری را در مورد آنچه در افزونه تغییر کرده است، به کاربر ارائه می دهد.
در نسخه سازی معنایی، نسخه های نرم افزار با استفاده از سه عدد ایجاد می شوند:
· Major: این عدد نشان دهنده تغییرات بزرگ در نرم افزار شما است، به این معنی که مشکلات و ناسازگاری ها در نرم افزار دیگری که از API افزونه شما استفاده می کند ظاهر می شود.
- Minor: این عدد نشان دهنده افزودن قابلیت یا ویژگی است که بر استفاده فعلی از افزونه API شما تأثیر نمی گذارد.
- Patch: این عدد نشان می دهد که شما در حال ارسال رفع اشکالی هستید که هیچ مشکلی در نرم افزار با استفاده از نسخه های پایین تر در همان شاخه ی کوچک، ایجاد نمی کند.
در افزونه SPM خود، ما با نسخه 1.0.0 شروع کردیم، بنابراین می توانیم با رعایت کاربردهای مختلف اعداد، به راحتی از نسخه سازی معنایی استفاده کنیم. برای مثال، می توانیم تعداد نسخه های فرعی را در هر فصل افزایش دهیم تا در نهایت به نسخه 1.14.0 برسیم.
در هر صورت، مهم است که شماره نسخه را به افزونه ی خود اضافه کنیم، به خصوص زمانی که آن را به صورت جهانی منتشر می کنیم.
بسته بندی تمام افزونه ها در یک فایل
در این کتاب ما چندین افزونه را برای ارائه ویژگی های بیشتر به SPM خود توسعه داده ایم و یاد گرفته ایم که چگونه برای هر افزونه بسته های جداگانه ایجاد کنیم. هنگامی که یک بسته را به کاربران خود تحویل می دهیم، می توانیم یک بسته را برای کامپوننت، بسته دیگر را برای ماژول و برخی از آنها را برای هر یک از پلاگین های پروژه خود ارسال کنیم. برخی از توسعه دهندگان این کار را انجام می دهند، اما برای کاربر خیلی راحت نیست.
در جوملا، ما نمی توانیم انواع مختلف افزونه ها را در یک مانیفست XML ترکیب کنیم، اما یک افزونه package داریم که می توانیم برای بسته بندی همه افزونه های خود در یک بسته استفاده کنیم و تنها آن بسته را در اختیار کاربر قرار دهیم.
افزونه بسته شامل یک فایل مانیفست XML و بسته های فایل تمام افزونه هایی است که می خواهیم در بسته خود قرار دهیم. بیایید با ایجاد فایل src/package/pkg_spm.xml با محتوای زیر، بسته را برای SPM خود ایجاد کنیم:
<?xml version="1.0" encoding="UTF-8" ?>
<extension type="package" method="upgrade">
<name>Simple Project Manager</name>
<packagename>spm</packagename>
<author>Carlos Camara</author>
<authorUrl>https://developingj5extensions.com/</authorUrl>
<creationDate>2023-11-01</creationDate>
<copyright>Copyright Piedpiper - 2022- 2023</copyright>
<license>GNU General Public License version 2; see LICENSE.md</license>
<version>1.0.0</version>
<packager>Carlos Camara</packager>
<packagerurl>https://developingj5extensions.com/ </packagerurl>
<description>Simple Project Manager package</description>
<scriptfile>pkg_script.php</scriptfile>
<blockChildUninstall>true</blockChildUninstall>
<files folder="packages">
<file type="component" id="com_spm">com_spm.zip</file>
<file type="plugin" id="spm" group="webservices">plg_webservices_spm.zip</file>
<file type="plugin" id="spm" group="content">plg_content_spm.zip</file>
</files>
<variant>full</variant>
</extension>
این فایل مانیفست بسیار شبیه به موارد قبلی است، اما برخی از برچسب ها و ویژگی های جدید وجود دارد که باید آنها را بررسی کنیم:
- packagename این تگ نام بسته را نشان می دهد. باید محتوای بسته را تعریف کند و باید همان نام فایل مانیفست بدون پیشوند pkg_ باشد. در مورد ما، spmکافی است.
- packager و packagerurlاین برچسب ها نویسنده بسته را تعریف می کنند. (ممکن است با توسعه دهنده افزونه های یکسان نباشد)
- scriptfile این کار به طور مشابه با افزونه های فردی کار می کند، اما باید با پیشوندpkg_ نامگذاری شود.
- blockChildUninstall نصب یک بسته در جوملا، فقط یک راه راحت برای نصب چندین افزونه است. تنظیم این پارامتر روی 1 باعث میشود که کاربران نتوانند افزونه های بسته را به صورت جداگانه حذف کنند.
- fileتگ فایل در مانیفست بسته، ویژگیtype را برای نشان دادن نوع بسته ای که ما نصب می کنیم و id را برای نشان دادن نام افزونه برای نصب می پذیرد.
هنگام اضافه کردن پلاگین به بسته، باید پلاگین گروه (group) را نیز قرار دهیم.
نکته مهم
لطفاً توجه داشته باشید که مشخصهid باید همان ورودی جدول #__extensions باشد که همان نامی است که در ویژگی افزونه قرار داده ایم.
هنگامی که مانیفست بسته را تعریف کردیم، می توانیم یک بسته ZIP حاوی آن و افزونه هایی که می خواهیم با آن نصب کنیم، ایجاد کنیم.
نحوه مدیریت تغییرات پایگاه داده در افزونه های خود
هنگام ایجاد کامپوننت اصلی خود، باید جداول پایگاه داده ایجاد می کردیم تا داده های خود را به صورت دستی در پایگاه داده ذخیره کنیم. این بهترین راه برای ارائه یک کامپوننت مناسب به دنیا نیست، به خصوص که جوملا به ما اجازه می دهد تا جداول پایگاه داده خود را به طور خودکار در هنگام نصب کامپوننت ایجاد کنیم.
برای اینکه جوملا، جداول ما را ایجاد کند، باید یک دستور SQL برای آن ارائه کنیم. بنابراین، بیایید فایل src/component/admin/sql/install/mysql/install.sql را اضافه کرده و محتوای فایل mock-data/src/database.sql را کپی کنیم:
CREATE TABLE IF NOT EXISTS '#__spm_projects' ( 'id' int(11) UNSIGNED NOT NULL AUTO_INCREMENT, 'name' VARCHAR(255) NOT NULL, 'alias' VARCHAR(255) NOT NULL, 'description' TEXT, 'deadline' DATETIME, 'category' INT(11), 'created' DATETIME DEFAULT NOW(), 'modified' DATETIME DEFAULT NOW(), 'created_by' INT(11) NOT NULL , 'modified_by' INT(11) NOT NULL , PRIMARY KEY ('id') ) ENGINE=InnoDB; CREATE TABLE IF NOT EXISTS '#__spm_tasks' ( 'id' int(11) UNSIGNED NOT NULL AUTO_INCREMENT, 'title' VARCHAR(255) NOT NULL, 'alias' VARCHAR(255) NOT NULL, 'description' TEXT, 'deadline' DATETIME, 'state' INT(3) NOT NULL, 'project' INT(11), 'created' DATETIME DEFAULT NOW(), 'modified' DATETIME DEFAULT NOW(), 'created_by' INT(11) NOT NULL , 'modified_by' INT(11) NOT NULL , PRIMARY KEY ('id') ) ENGINE=InnoDB; CREATE TABLE IF NOT EXISTS '#__spm_customers' ( 'id' int(11) UNSIGNED NOT NULL AUTO_INCREMENT, 'firstname' VARCHAR(255) NOT NULL, 'lastname' VARCHAR(255) NOT NULL, 'email' VARCHAR(255) NOT NULL, 'company_name' VARCHAR(255) NOT NULL, 'company_id' VARCHAR(255) NOT NULL, 'company_address' VARCHAR(255) NOT NULL, 'phone' VARCHAR(25) NOT NULL, 'user' INT(11), 'created' DATETIME DEFAULT NOW(), 'modified' DATETIME DEFAULT NOW(), 'created_by' INT(11) NOT NULL , 'modified_by' INT(11) NOT NULL , PRIMARY KEY ('id') ) ENGINE=InnoDB; CREATE TABLE IF NOT EXISTS '#__spm_invoices' ( 'id' int(11) UNSIGNED NOT NULL AUTO_INCREMENT, 'items' TEXT NOT NULL, 'number' VARCHAR(25) NOT NULL, 'amount' FLOAT DEFAULT 0.0, 'customer' INT(11), 'created' DATETIME DEFAULT NOW(), 'modified' DATETIME DEFAULT NOW(), 'created_by' INT(11) NOT NULL , 'modified_by' INT(11) NOT NULL , PRIMARY KEY ('id') ) ENGINE=InnoDB;
اینها دستورات SQL هستند که می توانیم از آنها برای ایجاد جداول خود در موتور پایگاه داده MySQL یا MariaDB استفاده کنیم، همانطور که در فصل 1 دیدیم. اکنون می توانیم بخش install را در فایل مانیفست خود در قسمت extension به صورت زیر وارد کنیم:
<extension> ... <install> <sql> <file driver="mysql" charset="utf8">sql/install/mysql/install.sql</file> </sql> </install> ... </extension>
این دستورالعمل به جوملا می گوید که از فایلinstall.sql که به تازگی در هنگام استفاده از درایور پایگاه دادهmysql تعریف کردیم، استفاده کند. از آنجایی که جوملا از MySQL و PostgreSQL پشتیبانی می کند، شما باید دستورالعمل های SQL را برای هر موتور پایگاه داده تعریف کنید. اگر فقط می خواهید یکی از موتور های پایگاه داده را در نظر بگیرید، فقط باید یکی از فایل ها را ارائه دهید. در جوملا، برای ارائه پشتیبانی بهتر از چند زبانه ها، به طور پیش فرض، از مجموعه حروف UTF-8 استفاده می کنیم، بنابراین ما برای روشن شدن این موضوع آن را در ویژگی charset قرار دهید.
این دستورالعمل ها فقط در روال نصب افزونه اجرا می شوند. هنگامی که می خواهید پس از بروز رسانی افزونه خود تغییراتی را به پایگاه داده اضافه کنید، باید مجموعه ی متفاوتی از دستورالعمل را تعریف کنید.
چگونه ساختار پایگاه داده خود را با بروز رسانی افزونه های خود تغییر دهید
بسیار متداول است که هنگام افزودن ویژگی های بیشتر به کامپوننت خود، تغییراتی را در ساختار پایگاه داده خود اضافه کنید. در این مواقع باید به جوملا اطلاع دهیم که چه تغییراتی را باید در پایگاه داده انجام دهد.
برای این کار می توانیم از تگ update در فایل مانیفست استفاده کنیم:
<extension> ... <update> <schemas> <schemapath type="mysql" charset="utf8">sql/updates/mysql</schemapath> </schemas> </update> ... </extension>
در این حالت از تگ های متفاوتی استفاده می کنیم اما معنی و دامنه یکسان است. به جای تگ file با ویژگی driver، از تگ schemapath با ویژگی type استفاده می کنیم که نشان دهنده نوع پایگاه داده مورد نظر ما است.
تگschemapath به یک فایل خاص اشاره نمی کند، بلکه به یک پوشه خاص در بسته افزونه ما اشاره می کند. برای گنجاندن دستورالعمل های بروزرسانی، باید یک فایل با دستورالعمل ها ایجاد کنید. اما قبل از پرداختن به آن، باید بدانید که نسخه های پایگاه داده در جوملا چگونه کار می کنند.
نسخه پایگاه داده به شماره نسخه افزونه مربوط نمی شود، بنابراین می توانید بدون توجه به شماره نسخه افزونه خود، با شماره نسخه مورد نظر خود، شروع کنید. اما هنگام اضافه کردن بروز رسانی MySQL، جوملا باید بداند که چه تغییراتی در هر بروز رسانی انجام می شود. احتمالاً بروزرسانی ها و تغییرات افزونه ی شما در پایگاه داده متوالی خواهد بود و نتیجه یک تغییر به ساختار پایگاه داده نسخه قبلی بستگی دارد. این بدان معناست که با هر نسخه، شما پایگاه داده را تغییر می دهید در حالی که فرض می کنید کاربر در آخرین نسخه افزونه است. چه اتفاقی می افتد وقتی کاربر چندین نسخه را که شامل تغییرات پایگاه داده در هر کدام می شود، نادیده بگیرد؟ در این صورت، جوملا باید قبل از اعمال آخرین تغییرات در پایگاه داده، تغییرات نادیده گرفته شده را انجام دهد.
جوملا! به محض اینکه فایلی را در پوشه تعریف شده در قسمت شناسایی کرد، شماره نسخه پایگاه داده را ذخیره می کند، بنابراین اگر فایل src/component/admin/sql/updates/mysql/1.0.0.sql را اضافه کنیم، جوملا این فایل را به عنوان نسخه اصلی پایگاه داده می شناسد و نسخه طرحواره (schema) پایگاه داده را به عنوان 1.0.0 ثبت می کند. در بروز رسانی کامپوننت بعدی شما، جوملا به پوشه نگاه می کند و هنگامی که فایل نسخه دیگری را پیدا کرد، فرض کنید 1.0.1، نسخه طرح کامپوننت را به 1.0.1 به روز می کند.
هنگامی که افزونه نصب شده یک فایل 2.0.0.sql ارائه می دهد ، جوملا تغییرات را از فایل های 1.0.2، 1.0.3، 1.1.0 و غیره به ترتیب اجرا می کند تا زمانی که به 2.0.0.sql برسد، که آخرین فایل اجرا شده، خواهد بود. به این ترتیب می توانید مطمئن باشید که بدون توجه به اینکه کاربر شما از کدام نسخه افزونه را به روز می کند، جوملا تمام تغییرات را به ترتیب درست، اعمال خواهد کرد.
برای افزونه SPM، فیلد وضعیت (status) برای پایگاه داده اضافه نکردیم. در برخی از کشورها، هنگامی که یک فاکتور ایجاد می کنید، نمی توانید آن را اصلاح کنید، یا ممکن است با دولت به مشکل بخورید. بیایید فیلد وضعیت را اضافه کنیم تا زمانی که فاکتور در حالت پیش نویس یا نهایی است، مشخص شود.
در افزونه ما، بیایید با کپی کردن فایل src/component/admin/mysql/install/mysql/install.sql در فایل src/component/admin/sql/updates/mysql/1.0.0.sql، بروزرسانی های MySQL را تعریف کنیم. به این ترتیب، ما تضمین می کنیم که اولین نسخه طرحواره ساختاری مشابه طرح پایگاه داده ای دارد که در هنگام نصب (install) استفاده می کنیم.
سپس، می توانیم تغییر خود را با ایجاد فایل src/component/admin/sql/updates/mysql/1.0.1.sql با محتوای زیر انجام دهیم:
ALTER TABLE '#__spm_invoices' ADD 'status' VARCHAR(5) NOT NULL DEFAULT 'draft' AFTER 'id';
این کد SQLیک ستون جدید به جدول فاکتورها (invoices) برای ذخیره مقادیر نهایی (final) یا پیش نویس (draft) را ذخیره کند که آخرین و مقادیر پیش فرض هستند.
اکنون، وقتی افزونه خود را در جوملا آپلود می کنیم، طرح پایگاه داده افزونه ی SPM به طور خودکار به نسخه 1.0.1 به روز می شود. اگر تغییرات پایگاه داده قابل اجرا نباشد، جوملا پس از نصب و هنگام دسترسی به System | Manage Database هشداری به کاربر در ناحیه مدیریت نشان می دهد، پایگاه داده ی کامپوننتی را که نیاز به آپدیت دارد، مشاهده می کنید.
پاک کردن پایگاه داده در حذف افزونه
در جوملا، هم همچنین می توانیم در برخی از دستورات SQL تعریف کنیم تا زمانی که کاربر، افزونه ی ما را حذف می کند، اجرا شوند. این تنظیمات برای حذف جداول پایگاه داده ای است که هنگام نصب کامپوننت خود ایجاد کردیم.
برای افزودن این دستورالعمل ها، باید بخش uninstall را در فایل مانیفست src/component/spm.xml با خطوط زیر اعلام کنیم:
<uninstall>
<sql>
<file driver="mysql" charset="utf8">sql/install/mysql/uninstall.sql</file>
</sql>
</uninstall>
همچنین باید کد زیر را به فایل src/component/admin/sql/install/mysql/uninstall.sql اضافه کنید:
DROP TABLE '#__spm_projects'; DROP TABLE '#__spm_tasks'; DROP TABLE '#__spm_customers'; DROP TABLE '#__spm_invoices';
اکنون، وقتی کامپوننت SPM را حذف می کنیم، این جداول از پایگاه داده ما حذف می شوند و تمام اطلاعات موجود در آنها از بین می رود. هنگام افزودن این ویژگی به کامپوننت خود، بهتر است قبل از انجام حذف به کاربران خود اطلاع دهید تا بتوانند از اطلاعات نسخه پشتیبان تهیه کنند.
ما اکنون می توانیم تغییرات زیادی در پایگاه داده را هنگام نصب، ارتقا یا حتی حذف افزونه خود انجام دهیم. حالا بیایید نحوه ایجاد تغییرات دیگر در هنگام مدیریت افزونه را یاد بگیریم.
نحوه اجرای وظایف پیشرفته در نصب افزونه
مدیریت بروز رسانی پایگاه داده جوملا، پیشرفته است، اما گاهی اوقات، برای نیازهای ما کافی نیست و باید هنگام نصب افزونه های خود، بررسی ها و وظایف سفارشی را انجام دهیم.
ما می توانیم یک اسکریپت PHP را برای انجام وظایف سفارشی هنگام نصب افزونه های خود تعیین کنیم. به عنوان یک مثال خوب، بیایید یک بررسی کننده ی PHP را به افزونه نصب خود، اضافه کنیم تا پلاگین ها به طور خودکار پس از نصب، فعال شوند.
برای انجام این کار، فایل مانیفست کامپوننت src/component/spm.xml را ویرایش کنید و تگscriptfile را به بخش زیر اضافه کنید:
<extension>
...
<scriptfile>script.php</scriptfile>
...
</extension>
با این کار، ما به جوملا دستور دادیم تا فایل script.php را در پوشه اصلی بسته ما جستجو کند و دستورالعمل هایی را که در آنجا پیدا می کند، اجرا کنیم.
سپس فایل src/component/script.php را با محتوای زیر ایجاد کنید:
<?php
defined('_JEXEC') or die;class Com_SpmInstallerScript
{
}
فایل script.php شامل یک کلاس PHP است که به هیچ کلاس دیگری گسترش نمی یابد یا از نظر فنی هیچ رابطی را پیاده سازی نمی کند.
جوملا اکنون به دنبال این فایل می گردد و در هنگام نصب افزونه به دنبال متد های خاصی در کلاس می گردد. این متد ها در مراحل مختلف فرآیند نصب، اجرا خواهند شد. متد ها اینها هستند:
- preflight ($type, $parent): این متد قبل از اجرای هرگونه تغییر در جوملا اجرا می شود. متغیر$type عملی را که ما انجام می دهیم را نشان می دهد: install ، update یا discover_install . متغیر $parent ، آبجکت نصب کننده است.
- install($parent): این متد زمانی اجرا می شود که فایل های افزونه بروزرسانی شده و ساختار پایگاه داده افزونه ارتقا یافته باشد. (به دنبال دستورالعمل های فایل بخش schemapath ) آبجکت نصب کننده را به عنوان پارامتر دریافت می کند.
- uninstall($type, $parent): این متد پس از حذف فایل های افزونه و پس از اجرای دستورالعمل های SQL ، اجرا می شود.
- update($parent): این متد آبجکت نصب کننده را به عنوان پارامتر دریافت می کند و فقط هنگام نصب بروز رسانی افزونه اجرا می شود.
- discover_install($parent): این متد شبیه به متد install است و تنها زمانی فعال می شود که از نصبDiscover در نصب کننده افزونه ی جوملا استفاده می کنید.
- postflight($type, $parent): وقتی به این متد رسیدیم، افزونه به طور کامل نصب شده است و جدول #__extensions جوملا با نسخه جدید به روز شده است. عمدتا برای نمایش پیام های سفارشی به کاربر استفاده می شود.
بیایید شروع به اضافه کردن یک بررسی کننده ی نسخه PHP در نصب افزونه کنیم. این یک متد مرسوم است زیرا افزونه های ما با در نظر گرفتن یک نسخه PHP توسعه یافته و آزمایش می شوند. بنابراین، برای اطمینان از اینکه کاربر از نسخه قدیمی PHP استفاده نمی کند که ممکن است مشکلاتی ایجاد کند، باید نسخه PHP مورد استفاده برای اجرای سایت را قبل از نصب افزونه بررسی کنیم.
این بررسی PHP باید قبل از نصب افزونه در جوملا انجام شود. در غیر این صورت، ما خطر تخریب سایت کاربر را داریم. بنابراین، باید متدpreflight را با محتوای زیر به کلاس اضافه کنیم:
public function preflight($type, $parent) { $minimumPhp = "8.1.0"; if (version_compare(\phpversion(), $minimumPhp, '>=')) { return true; } return false; }
در این کد، ما حداقل نسخه PHP مورد پشتیبانی خود را در افزونه خود تعریف میکنیم، و سپس از تابع PHP version_compare استفاده می کنیم تا بررسی کنیم که آیا نسخه فعلی PHP بزرگتر یا برابر با حداقل نسخه پشتیبانی شده ی ما است یا خیر.
وقتی نسخه با حداقل ما مطابقت داشت، مقدار true را بر می گردانیم و نصب ادامه می یابد. وقتی سایت حداقل شرایط را برآورده نمی کند، false را بر می گردانیم. با ظاهر شدن false در این متد، فرآیند نصب متوقف می شود.
بیایید فایل src/package/script.php را با محتوای زیر ایجاد کنیم:
<?php
\defined('_JEXEC') or die;
use Joomla\CMS\Factory;
class Pkg_SpmInstallerScript
{
public function preflight($type, $parent)
{
$minimumPhp = "8.1.0";
if (version_compare(\phpversion(), $minimumPhp,
'>=')) {
return true;
}
return false;
}
}
باز هم، این یک کلاس PHP ساده به نام Pkg_SpmInstallerScript است که از یک قرارداد نامگذاری پیروی می کند. ما از همان متدpreflight استفاده می کنیم که برای کامپوننت خود نوشتیم. این منطقی است، زمانی که ما به حداقل نسخه PHP برای کامپوننت نیاز داریم، باید آن را برای بسته نیز بخواهیم. در این اسکریپت به تعدادی از متد های جوملا نیاز داریم، بنابراین فضای های نام مورد نیاز را اضافه کرده ایم.
ما همچنین می خواهیم افزونه های وب سرویس و محتوای خود را در هنگام نصب فعال کنیم تا کاربر راحت تر از این کامپوننت استفاده کند. ما می توانیم یک اسکریپت نصب را به هر یک از افزونه ها اضافه کنیم تا آنها را از نصب بسته مستقل کنیم. اما زمانی که چندین پلاگین را همزمان نصب کرده باشید، این کار مفیدتر و قدرتمندتر است، بنابراین ما این اسکریپت را به بسته اضافه می کنیم.
حال باید متد postflight خود را با کد زیر اضافه کنیم:
public function postflight($type, $parent) { $onlyOnInstall = ['install', 'discover_install']; if (!in_array($type, $onlyOnInstall)) { return true; } $db = Factory::getContainer()->get('DatabaseDriver'); $query = $db->getQuery(true); $query->update($db->quoteName('#__extensions')); $query->set($db->quoteName('enabled') . ' = 1'); $query->where('( ' . ($db->quoteName('name') . ' = ' . $db->quote('plg_webservices_spm')) . ' OR ' . ($db->quoteName('name') . ' = ' . $db->quoqte('plg_content_spm')) . ' )'); $db->setQuery($query); $db->query(); }
در این متدpostflight ، ابتدا بررسی می کند که بسته خود را نصب کرده ایم. ما نمی خواهیم پیکربندی کاربر را به هم بریزیم و افزونه ای که غیرفعال شده است را فعال کنید. سپس، یک آبجکت پایگاه داده برای بروز رسانی جدول #__extensions دریافت می کنیم و با یک کوئری ساده، پلاگین های خود را فعال می کنیم.
ما اطلاعاتی در مورد وضعیت پلاگین ها در متد $parent نداریم، بنابراین باید رکورد مناسب را با استفاده از عبارت Where بدست آوریم.
فعال کردن پلاگین ها در نصب بسته برای کاربران ما بسیار راحت است و استفاده از اسکریپت نصب به ما کمک می کند تا بسیاری از وظایف را خودکار کنیم که زندگی آنها را آسان تر می کند. اما یکی از بهترین ویژگی هایی که می توانیم به افزونه های خود اضافه کنیم، فعال کردن بروزرسانی های زنده است که به آنها اجازه می دهد مستقیماً از backend خود به نسخه های جدید بروزرسانی شوند. در بخش بعدی، ما یاد خواهیم گرفت که چگونه این ویژگی را با استفاده از یک سرور بروز رسانی (update server)، فعال کنیم.
راه اندازی سرور بروز رسانی
وقتی برای جوملا، افزونه های تجاری یا سرگرمی توسعه می دهید، می خواهید مردم از آخرین نسخه افزونه شما استفاده کنند. بروز رسانی مداوم افزونه های شما تضمین می کند که بهترین تجربه را با آخرین پیشرفت ها و ویژگی ها به کاربران خود ارائه می دهید، و همچنین امنیت وب سایت های کاربران خود را تضمین می کند، زیرا احتمالاً با آخرین نسخه های PHP همگام خواهید بود و هر گونه آسیب پذیری شناخته شده در کد ما را برطرف می کند.
اما هر زمان که کد افزونه خود را به روز می کنید، باید کاربران خود را از نسخه جدید مطلع کنید و بسته دانلودی را ارائه دهید که می توانند در سایت خود نصب کنند. این برای شما بسیار ناخوشایند است، زیرا باید یک شبکه اطلاعاتی کامل راه اندازی کنید. با این حال، برای کاربران شما نیز ناخوشایند است زیرا آنها باید نسخه های جدید را برای بروز رسانی سایت خود آپلود کنند.
در جوملا، می توانیم با راه اندازی یک سرور بروزرسانی در وب سایت هایمان، اعلان های انتشار جدید را به راحتی به کاربران خود ارسال کنیم.
سرور بروز رسانی برای افزونه ی ما شامل یک فایل XML است که اطلاعات انتشار را برای افزونه ی ما اعلام می کند. این فایل باید عمومی و جوملا باید بتواند مستقیماً از یک URL به آن دسترسی داشته باشد. ما قصد داریم سرور آپدیت خود را در همان مخزن Git ایجاد کنیم، بنابراین فایل update_server/updates.xml را با محتوای زیر ایجاد می کنیم:
<?xml version="1.0" encoding="utf-8"?>
<updates>
<update>
<name>Simple Project Manager Package</name>
<description><![CDATA[A simple project manager extension]]></description>
<element>pkg_spm</element>
<type>package</type>
<version>1.0.0</version>
<maintainer>Carlos Camara</maintainer>
<maintainerurl>https://developingj5extensions.com</maintainerurl>
<client>administrator</client>
<infourl title="New release of SPM package">https://github.com/</infourl>
<downloads>
<downloadurl type="full" format="zip">https://github.com/</downloadurl>
</downloads>
<sha256></sha256>
<tags>
<tag>stable</tag>
</tags>
<targetplatform name="joomla" version="4\.[01234]|5\.0" />
<php_minimum>8.1.0</php_minimum>
<supported_databases mysql="5.7.0" mariadb="10.2" postgresql="9.2" />
</update>
</updates>
این فایل XMLاز همان قوانینی پیروی می کند که فایل های مانیفست ما در این کتاب به آنها نگاه کرده ایم. بخش اصلی شامل تمام بروز رسانی های ممکن برای افزونه ی ما است. هر بروز رسانی بین تگ update محصور شده است. باید تگ های زیر را تعریف کنیم:
- name نام افزونه برای بروز رسانی.
- description شرح کوتاهی از افزونه.
- element نام نصب شده افزونه. ما در حال ایجاد سرور بروز رسانی برای بسته هستیم، بنابراین از نام بسته استفاده می کنیم.
- type نوع افزونه را مشخص می کند. در اینجا، ما از package استفاده می کنیم.
- version شماره نسخه ی بسته ما.
- maintainer نام نویسنده بسته (اختیاری).
- maintainerurl نشانی اینترنتی نویسنده بسته (اختیاری).
- client این تگ، ناحیه مورد نظر جوملا را نشان می دهد. برای پکیج ها و کامپوننت ها، روی administrator تنظیم شده است. برای پلاگین ها باید آن را روی site قرار دهید و برای ماژول ها و قالب ها، باید مقدار مناسب (administrator) را برای ماژول ها و قالب های backend و در غیر این صورت site مشخص کنید. مقدار پیش فرض administrator است و عدم افزودن مقدار مناسب باعث نمایش بروزرسانی ها نمی شود.
- inforurl این تگ اختیاری است و به شما امکان می دهد یک URL با اطلاعات مربوط به بروز رسانی اضافه کنید.
- downloads این تگ قسمت دانلود ها را برای بروز رسانی تعریف می کند.
- downloadurl این تگ آدرس اینترنتی را که جوملا، بسته ی بروز رسانی را از آنجا دانلود میکند، مشخص می کند. ویژگیtype را می پذیرد و نشان می دهد که آیا بسته ارتقا یافته با حداقل تغییرات است یا یک بسته کامل با کامپوننت کامل. معمولاً روی full تنظیم می شود. همچنین ویژگیformat را با فرمت فایل برای بسته upgrade می پذیرد. برای حداکثر سازگاری، توصیه می کنم از پسوند zip استفاده کنید.
- sha256 این تگ اختیاری است و مقدار checksum [1]فایل بسته را نشان می دهد. این باعث افزایش امنیت دانلود می شود، زیرا جوملا فایل دانلود شده را قبل از ارتقا، بررسی می کند.
- tags این تگ اختیاری است و بخش جدیدی را تعریف می کند که در آن می توانید برچسب های مربوط به بروز رسانی را اضافه کنید. آنها عمدتاً برای تعیین پایداری بسته و استفاده از کلید واژه های dev , alpha , beta , rc وstable استفاده می شوند. اگر هیچ ثابتی تنظیم نشده است، جوملا به طور پیش فرض stable در نظر می گیرد.
- targetplatform با این تگ، پلتفرم و نسخه ای را که بروز رسانی برای آن توسعه داده شده است را تنظیم می کنید. برای ویژگیname ، فقط می توانید از جوملا استفاده کنید و برای ویژگی version، می توانید از یک نسخه یا یک عبارت معمولی برای تنظیم چندین نسخه استفاده کنید. در هر صورت، این فقط زمانی معتبر است که چندین نسخه جوملا را با همین فایل، هدف قرار دهید. اگر به بسته های بروز رسانی مختلف برای جوملاهای مختلف نیاز دارید، باید یک بخش کامل update را تعریف کنید که به فایل مناسب اشاره می کند.
- php_minimum حداقل نیاز PHP را برای کامپوننت تعیین می کند. وقتی جوملا، بروز رسانی های جدید را بررسی می کند، اگر نصب حداقل نیاز PHP را برآورده نکند، پیامی به کاربر نشان می دهد و اجازه بروز رسانی را نمی دهد.
- supported_databases این تگ حداقل مورد نیاز پایگاه داده را تعیین می کند. این سه ویژگی mysql ، mariadb و postgresql را می پذیرد که حداقل نسخه هر سرور پایگاه داده را نشان می دهد.
هنگامی که یک سرور آپدیت داریم، باید آن را به فایل مانیفست افزونه خود اضافه کنیم تا جوملا آن را به جدول سایت های بروز رسانی اضافه می کند و بروز رسانی بسته را بررسی می کند.
برای افزودن این سرور بروزرسانی به فایل مانیفست، باید فایل مانیفست src/package/pkg_spm.xml را ویرایش کرده و بخش زیر را اضافه کنیم:
<extension>
...
<updateservers>
<server type="extension" priority="2" name="Simple Project Manager Updates">https://raw.githubusercontent.com/PacktPublishing/Developing-Extensions-for-Joomla-5/chapter14/src/update_server/updates.xml
</server>
</updateservers>
</extension>
در تگ server ، ما از ویژگی type با مقدار افزونه استفاده می کنیم تا نشان دهیم که یک افزونه منحصر به فرد است (به یاد داشته باشید که یک پکیج افزونه، خود یک افزونه است). سپس، می توانیم یک ویژگی اولویت (priority) را تعریف کنیم. اگر چندین سرور بروز رسانی برای بسته وجود داشته باشد از این ویژگی استفاده می شود. یکی با اولویت کمتر برتری دارد. در نهایت، ویژگی نام افزونه را اضافه می کنیم. مقدار تگ آدرس فایل XML خواهد بود.
بعد از این تعاریفXML، زمانی که ما یک آپدیت جدید به سرور آپدیت خود اضافه می کنیم ، جوملا آن را بررسی کرده و کاربر را در مورد نسخه جدید مطلع می کند.
بعد از تنظیم سرور آپدیت و افزودن آن به فایل مانیفست پکیج، می توانیم بروزرسانی های منظم را به راحتی به کاربران خود ارائه دهیم و آماده ی انتشار افزونه ما باشید تا جهان از آن لذت ببرد.
افزودن یک درگاه پرداخت به دانلود افزونه شما
جوملا از توسعه دهندگان تجاری پشتیبانی می کند و برخی از ویژگی ها را فراهم می کند تا راه اندازی افزونه های توسعه کسب و کار برای جوملا را آسان تر کند. یکی از آخرین موارد اضافه شده به هسته، پشتیبانی از کلیدهای دانلود (download keys) هنگام درخواست بروز رسانی است.
کلیدهای دانلود معمولاً یک قالب رشته الفبایی هستند و به شما امکان می دهند بروز رسانی افزونه های خود را دانلود کنید. این برای کاربران بسیار راحت است زیرا می توانند از ویژگی بروز رسانی زنده برای افزونه ها استفاده کنند. در مورد توسعه دهندگان، آنها می توانند کنترل کنند که چه کسی می تواند افزونه های آنها را دانلود کند.
این کلیدهای دانلود باید به لینک دانلود بروز رسانی زنده افزونه اضافه شوند تا زمانی که کاربر درخواست دانلود می کند، در صورت معتبر بودن کلید دانلود فعال شود و در صورت رد شدن، آن را غیر فعال کند.
راه برای در نظر گرفتن کلیدهای دانلود در افزونه جوملا، افزودن یک بخش جدید به مانیفست XML شما است. بنابراین، اجازه دهید فایل src/package/pkg_spm.xml را ویرایش کرده و تگ زیر را اضافه کنیم:
<dlid prefix="spm_key=" suffix="&customer=1"/>
وقتی که جوملا این تگ را در نصب افزونه پیدا می کند، کاربران می توانند یک کلید دانلود را به منطقه Update sites افزونه نصب شده، اضافه کنند.
پس از تنظیم کلید دانلود، جوملا از ویژگی های پیشوند و افزونه به همراه کلید دانلود معرفی شده توسط کاربر برای تولید URL دانلود بسته به شکل زیر استفاده میکند:
https://developingj5extensions.com/package-download?spm_key=DOWNLOAD_KEY&customer=1
بنابراین، جوملا پیشوند+کلید دانلود+پسوند (prefix + download key + suffix) نشان داده شده را به URL دانلود را اضافه می کند و درخواست دانلود، دارای یک پارامتر کلیدی خواهد بود که می توانید از آن برای اجازه یا رد دانلود استفاده کنید.
در هر صورت، می توانید هر دو ویژگی پیشوند و پسوند (prefix + suffix) را خالی بگذارید و فقط پارامتر کلید دانلود اضافه خواهد شد.
به این ترتیب، راه اندازی یک درگاه پرداخت و ایجاد کلیدهای دانلود برای مشتریان خود تنها کاری است که باید انجام دهید تا یک درگاه پرداخت دانلود به افزونه خود اضافه کنید. بسته به رویکرد بازاریابی و مشارکتی که می خواهید، گزینه های مختلفی برای انجام آن وجود دارد.
منابع فصل
- مستندات جوملا در مورد فایل های مانیفست واقعاً توصیفی است:
https://docs.joomla.org/Manifest_files
- می توانید اطلاعات بیشتری در مورد نسخه سازی معنایی در سایت آن بخوانید:
- مستندات جوملا یک مقاله عالی ارائه می دهد که تمام جزئیات مربوط به فایل سرور بروز رسانی جوملا را مشخص می کند:
https://docs.joomla.org/Deploying_an_Update_Server#Supporting_Tools
[1] Checksum در اصل اثر انگشت فایل ها است. وقتی شما فایلی را از جایی دانلود می کنید ممکن است همان فایل واقعی نباشد و با یک فایل مخرب عوض شده باشد. يا اینکه فایل شما نصفه و نیمه دانلود شده باشد. وقتی اثر انگشت فایل شما را بدانید، می توانید قبل از اجرا آن را چک کنید تا مطمئن شوید، این همانی است که شما می خواستید.