在上一篇文章中,我們熟悉了Joomla智能搜索組件的功能,討論了使用CRON進行定時索引的參數(shù)和配置。讓我們開始為我們自己的插件創(chuàng)建代碼。
資源清單
在開始技術部分之前,我將提到一些直接涉及主題的文章。以及一般涵蓋 Joomla 4 / Joomla 5 現(xiàn)代架構的插件的創(chuàng)建和/或更新的文章。接下來,我將假設讀者已經(jīng)閱讀了它們并且通常了解如何制作工作插件對于 Joomla:
- 創(chuàng)建智能搜索插件 - Joomla 官方文檔。適用于 Joomla 3,但大部分規(guī)定仍然適用于 Joomla 4 / Joomla 5
- 開發(fā)智能搜索插件 2012 年 Joomla 社區(qū)雜志的文章。
- Nicholas Dionysopoulos 所著的《Joomla Extensions Development》一書涵蓋了 Joomla 的開發(fā)! Joomla 版本 4 和 5 下的擴展。
- 新文檔門戶 manual.joomla.org 上的數(shù)據(jù)庫部分 - 適用于 Joomla 4 和 Joomla 5。 ## 技術部分。 Joomla 5智能搜索插件的開發(fā) 智能搜索組件與數(shù)據(jù)提供程序插件一起使用,其主要任務保持不變 - 選擇數(shù)據(jù)并將其提供給組件進行索引。但隨著時間的推移,重新索引任務也落入了插件的職責范圍。在本文中,我們假設我們從管理面板手動運行內容索引。 CLI 的工作在視覺上有所不同,但其本質保持不變。
對于有經(jīng)驗的開發(fā)人員,我會說搜索插件擴展了 JoomlaComponentFinderAdministratorIndexerAdapter 類,該類文件位于 administrator/components/com_finder/src/Indexer/Adapter.php。好吧,然后他們會自己解決這個問題。此外,作為示例,您可以在 plugins/finder 文件夾中研究 Joomla 核心智能搜索插件 - 用于文章、類別、聯(lián)系人、標簽等。我為 JoomShopping(Joomla 電子商務組件)和 SW JProjects(您自己的帶有更新服務器的 Joomla 擴展目錄組件)組件開發(fā)了一個智能搜索插件,因此類名稱和一些細微差別將與它們相關聯(lián)。我將使用 JoomShopping 的示例來展示其中的大部分內容。多語言問題的解決方案基于 SW JProjects 的示例。
智能搜索插件的文件結構
Joomshopping 智能搜索插件的文件結構與典型的沒有什么不同:
Joomla 5 智能搜索插件文件結構
文件服務/provider.php
文件provider.php允許您在Joomla DI容器中注冊插件,并允許您使用MVCFactory從外部訪問插件方法。
<?php /** * @package Joomla.Plugin * @subpackage Finder.Wtjoomshoppingfinder * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ \defined('_JEXEC') or die; use Joomla\CMS\Extension\PluginInterface; use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\Database\DatabaseInterface; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; use Joomla\Event\DispatcherInterface; use Joomla\Plugin\Finder\Wtjoomshoppingfinder\Extension\Wtjoomshoppingfinder; return new class () implements ServiceProviderInterface { /** * Registers the service provider with a DI container. * * @param Container $container The DI container. * * @return void * * @since 4.3.0 */ public function register(Container $container) { $container->set( PluginInterface::class, function (Container $container) { $plugin = new Wtjoomshoppingfinder( $container->get(DispatcherInterface::class), (array) PluginHelper::getPlugin('finder', 'wtjoomshoppingfinder') ); $plugin->setApplication(Factory::getApplication()); // Our plugin uses DatabaseTrait, so the setDatabase() method appeared // If it is not present, then we use only setApplication(). $plugin->setDatabase($container->get(DatabaseInterface::class)); return $plugin; } ); } };
插件類文件
這是包含插件主要工作代碼的文件。它應該位于 src/Extension 文件夾中。就我而言,插件類 JoomlaPluginFinderWtjoomshoppingfinderExtensionWtjoomshoppingfinder 位于文件 plugins/finder/wtjoomshoppingfinder/src/Extension/Wtjoomshoppingfinder.php 中。該插件的命名空間是 JoomlaPluginFinderWtjoomshoppingfinderExtension。
操作需要最少的類屬性和方法集(它們可以被訪問,包括由父 Adapter 類訪問)。
類的最低要求屬性
- $extension - 是組件的名稱,它定義內容的類型。例如,com_content。就我而言,這是 com_jshopping。
- $context - 是插件的唯一標識符,它設置索引的上下文,在該上下文中將訪問插件。事實上,這是插件類(元素)的名稱。在我們的例子中,Wtjoomshoppingfinder。
-
$layout - 是搜索結果元素的輸出布局的名稱。顯示搜索結果時使用此布局。例如,如果$layout參數(shù)設置為article,那么當您需要顯示該類型的搜索結果時,默認視圖模式將搜索名為default_article.php的布局文件。如果找不到這樣的文件,則將使用名為 default_result.php 的布局文件。 HTML 布局的輸出布局位于 components/com_finder/tmpl/search 中。但是,我們應該將布局作為覆蓋放置在 html 模板文件夾中 - templates/YOUR_TEMPLATE/html/com_finder/search。在我的例子中,我將布局命名為產(chǎn)品,文件名為 default_product.php。
- $table - 是我們正在訪問以獲取數(shù)據(jù)的數(shù)據(jù)庫中的表的名稱,例如#__content。就我而言,包含 JoomShopping 產(chǎn)品的主表稱為 #__jshopping_products。
- $state_field - 是數(shù)據(jù)庫表中負責索引元素是否發(fā)布的字段名稱。默認情況下,該字段稱為狀態(tài)。然而,在 JoomShopping 的情況下,該字段稱為product_publish。
<?php /** * @package Joomla.Plugin * @subpackage Finder.Wtjoomshoppingfinder * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ \defined('_JEXEC') or die; use Joomla\CMS\Extension\PluginInterface; use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\Database\DatabaseInterface; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; use Joomla\Event\DispatcherInterface; use Joomla\Plugin\Finder\Wtjoomshoppingfinder\Extension\Wtjoomshoppingfinder; return new class () implements ServiceProviderInterface { /** * Registers the service provider with a DI container. * * @param Container $container The DI container. * * @return void * * @since 4.3.0 */ public function register(Container $container) { $container->set( PluginInterface::class, function (Container $container) { $plugin = new Wtjoomshoppingfinder( $container->get(DispatcherInterface::class), (array) PluginHelper::getPlugin('finder', 'wtjoomshoppingfinder') ); $plugin->setApplication(Factory::getApplication()); // Our plugin uses DatabaseTrait, so the setDatabase() method appeared // If it is not present, then we use only setApplication(). $plugin->setDatabase($container->get(DatabaseInterface::class)); return $plugin; } ); } };
類中最少需要的方法
- setup() :bool - 是一種用于預配置插件、連接庫等的方法。該方法在重新索引期間(reindex() 方法)在 onBeforeIndex 事件上調用。該方法必須返回true,否則索引將被中斷。
- index() : void - 是開始索引本身的方法。它從原始 SQL 查詢數(shù)據(jù)中收集所需結構的對象,然后將其傳遞給 JoomlaComponentFinderAdministratorIndexerIndexer 類進行索引。該方法針對每個索引元素運行。方法參數(shù)是 $item - 數(shù)據(jù)庫查詢的結果,在 JoomlaComponentFinderAdministratorIndexerResult 類中格式化。
- getListQuery() :JoomlaDatabaseDatabaseQuery - 是一種獲取索引項列表的方法......
…這里我們開始深入研究細節(jié),因為 getListQuery() 方法并不是真正強制性的,盡管文檔和大多數(shù)文章都討論了它。
任何關于“復雜方案”主題的圖片都可以在這里。
深入了解細節(jié)。索引元素的數(shù)據(jù)結構。
令人驚訝的是,有時一些信息或想法在我們注意到并意識到之前就已經(jīng)在我們身邊轉了一圈了!很多東西,在我們眼前一年多了,還沒有達到認知,需要經(jīng)過多年的體驗,我們的注意力才集中到它們上。
關于 Joomla,由于某種原因,它的組件并沒有立即呈現(xiàn)出 Joomla 的某種通用架構特征(盡管這是一個明顯的事實)。包括數(shù)據(jù)庫表結構層面。讓我們看一下 Joomla 內容表的一些字段。我會保留的是,具體的列名對我們來說并不是那么重要(你可以隨時查詢 SELECT name AS title),一個索引元素的數(shù)據(jù)結構是多少:
- id - 自動增量
- asset_id - #__assets 表中條目的 ID,其中存儲了網(wǎng)站每個元素的組和用戶的訪問權限:文章、產(chǎn)品、菜單、模塊、插件和其他所有內容。 Joomla 使用訪問控制列表 (ACL) 模式。
- title - 元素標題
- 語言 - 元素語言
- introtext - 介紹性文本或元素的簡短可見描述
- fulltext - 項目的全文、產(chǎn)品的完整描述等
- state - 負責發(fā)布狀態(tài)的邏輯標志:項目是否已發(fā)布。
- catid - 項目類別的 ID。 Joomla 不像其他 CMS 那樣只有“站點頁面”。有些內容實體(文章、聯(lián)系人、產(chǎn)品等)必須屬于某些類別。
- 創(chuàng)建 - 項目的創(chuàng)建日期。
- access - 訪問權限組id(未授權站點用戶(訪客)、全部、注冊等)
- metakey - 元素的元關鍵字。是的,自 2009 年以來,Google 就不再使用它們。但在 Joomla 中,它們歷史上仍然存在,因為該字段用于相似文章模塊中,以使用指定關鍵字搜索實際相似的文章。
- metadesc - 元素元描述
- publish_up 和publish_down - 元素開始發(fā)布和取消發(fā)布的日期。這更多的是一種選擇,但在許多組件中都可以找到它。
如果我們比較表#__content(Joomla文章)、#__contact_details(聯(lián)系人組件)、#__tags(Joomla標簽)、#__categories(Joomla類別組件),那么我們會發(fā)現(xiàn)幾乎所有列出的數(shù)據(jù)類型無處不在。
如果創(chuàng)建智能搜索插件的組件遵循“Joomla方式”并繼承其架構,那么您可以在插件類中使用最少的方法。如果開發(fā)人員決定不尋找簡單的方法而走自己的路,那么您將不得不走困難的路,重新定義 Adapter 類的幾乎所有方法。
getListQuery() 方法
此方法在 3 種情況下被調用:
- Adapter類的getContentCount()方法是獲取索引項的數(shù)量(總共有多少篇文章,總共有多少個產(chǎn)品等)。
Joomla 智能搜索索引過程 您可以在調試模式下看到索引項的數(shù)量。
- Adapter 類的 getItem($id) 方法是通過 id 獲取特定索引元素。 getItem() 方法又在重新索引期間在 reindex($id) 方法中調用。
- Adapter 類的 getItems($offset, $limit, $query = null) 方法是獲取索引元素列表的方法。偏移量和限制是根據(jù)組件設置設置的 - “捆綁”中應包含多少個索引元素。
Joomla 5 智能搜索設置索引器批量大小
讓我們看一下 Joomla 核心插件的實現(xiàn)示例:
<?php /** * @package Joomla.Plugin * @subpackage Finder.Wtjoomshoppingfinder * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ \defined('_JEXEC') or die; use Joomla\CMS\Extension\PluginInterface; use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\Database\DatabaseInterface; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; use Joomla\Event\DispatcherInterface; use Joomla\Plugin\Finder\Wtjoomshoppingfinder\Extension\Wtjoomshoppingfinder; return new class () implements ServiceProviderInterface { /** * Registers the service provider with a DI container. * * @param Container $container The DI container. * * @return void * * @since 4.3.0 */ public function register(Container $container) { $container->set( PluginInterface::class, function (Container $container) { $plugin = new Wtjoomshoppingfinder( $container->get(DispatcherInterface::class), (array) PluginHelper::getPlugin('finder', 'wtjoomshoppingfinder') ); $plugin->setApplication(Factory::getApplication()); // Our plugin uses DatabaseTrait, so the setDatabase() method appeared // If it is not present, then we use only setApplication(). $plugin->setDatabase($container->get(DatabaseInterface::class)); return $plugin; } ); } };
getListQuery()方法返回一個DatabaseQuery對象,該對象是查詢構造函數(shù)的對象,其中已經(jīng)指定了表的名稱和選擇的字段。在調用它的方法中繼續(xù)使用它。
如果從 DatabaseQuery $query 對象中的 getContentCount() 調用 getListQuery(),則 select 的設置值將替換為 COUNT(*)。
如果從 getItem($id) 調用 getListQuery(),則條件 $query->where('a.id = ' . (int) $id) 并且僅選擇特定元素。在這里我們已經(jīng)看到父 Adapter 類在查詢中包含作為 a.* 的表名稱。這意味著我們還應該在 getListQuery() 方法的實現(xiàn)中使用這些前綴。
在從 getItems() 調用 getListQuery() 的情況下,$offset 和 $limit 將添加到我們構建的查詢中,以便在元素列表中移動以進行索引。
總結: getListQuery() - 必須包含三個不同 SQL 查詢的“工作片段”。 在這里實現(xiàn) Joomla 并沒有什么特別困難的。但是,如果有必要,您可以自己實現(xiàn) 3 個方法,而無需創(chuàng)建 getListQuery()。
非 Joomla 方式: 就 JoomShopping 而言,我發(fā)現(xiàn)一個產(chǎn)品可以有多個類別,并且歷史上該產(chǎn)品的類別 id (catid) 組件存儲在單獨的表中。同時,多年來一直無法指定產(chǎn)品的主要類別。收到產(chǎn)品類別后,查詢將發(fā)送到類別表,其中僅獲取第一個查詢結果,按默認類別 ID 排序 - 即升序。如果我們在編輯產(chǎn)品時更改類別,則主要產(chǎn)品類別是 ID 號較小的類別。產(chǎn)品的 URL 以此為基礎,產(chǎn)品可以從一個類別跳轉到另一個類別。
但是,大約 2 年前,這種 JoomShopping 行為已得到修復。由于該組件歷史悠久,受眾眾多,并且不能僅僅破壞向后兼容性,修復是可選的。必須在組件設置中啟用指定產(chǎn)品主類別的功能。然后 main_category_id 將被填充到帶有產(chǎn)品的表中。
但是這個功能默認是關閉的。而在智能搜索插件中,我們需要獲取JoomShopping組件的參數(shù),看看是否啟用了指定主商品類別的選項(并且它最近可能啟用,并且未指定某些產(chǎn)品的主類別 - 也是一個細微差別...)并生成 SQL 查詢以根據(jù)組件參數(shù)接收產(chǎn)品:或者是一個簡單的查詢,其中我們添加 main_category_id字段,或以舊的錯誤方式獲取類別 id 的 JOIN 請求。
在此請求中,多語言的細微差別立即凸顯出來。根據(jù) Joomla 方式,為網(wǎng)站的每種語言創(chuàng)建一個單獨的元素,并在它們之間建立關聯(lián)。因此,對于俄語 - 一篇文章。同一篇英文文章正在單獨創(chuàng)建。然后我們使用語言關聯(lián)將它們相互連接起來,當在 Joomla 前端切換語言時,我們將從一篇文章重定向到另一篇文章。
這不是 JoomShopping 中的做法:所有語言的數(shù)據(jù)都與產(chǎn)品存儲在同一個表中(好的)。添加其他語言的數(shù)據(jù)是通過添加帶有這些語言后綴的列來完成的(嗯...)。也就是說,我們的數(shù)據(jù)庫中不僅僅有標題或名稱字段。但還有 name_ru-RU、name_en-GB 等字段
Joomla JoomShopping 產(chǎn)品表結構片段
同時,我們需要設計一個通用的 SQL 查詢,以便可以從管理面板和 CLI 對其進行索引。同時,使用 CRON 啟動 CLI 時選擇索引語言也是一項任務。我承認,在撰寫本文時,我暫時推遲了對該問題的全面解決方案。使用我們自己的 getLangTag() 方法選擇語言,我們可以從 JoomShopping 參數(shù)中獲取主要語言,也可以使用網(wǎng)站的默認語言。也就是說,到目前為止,該解決方案僅適用于單語言網(wǎng)站。目前還無法進行不同語言的搜索。
但是,3個月后我解決了這個問題,但已經(jīng)在 SW JProjects 組件的智能搜索插件中了。我會進一步告訴你解決方案。
同時,讓我們看看JoomShopping發(fā)生了什么
<?php /** * @package Joomla.Plugin * @subpackage Finder.Wtjoomshoppingfinder * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ \defined('_JEXEC') or die; use Joomla\CMS\Extension\PluginInterface; use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\Database\DatabaseInterface; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; use Joomla\Event\DispatcherInterface; use Joomla\Plugin\Finder\Wtjoomshoppingfinder\Extension\Wtjoomshoppingfinder; return new class () implements ServiceProviderInterface { /** * Registers the service provider with a DI container. * * @param Container $container The DI container. * * @return void * * @since 4.3.0 */ public function register(Container $container) { $container->set( PluginInterface::class, function (Container $container) { $plugin = new Wtjoomshoppingfinder( $container->get(DispatcherInterface::class), (array) PluginHelper::getPlugin('finder', 'wtjoomshoppingfinder') ); $plugin->setApplication(Factory::getApplication()); // Our plugin uses DatabaseTrait, so the setDatabase() method appeared // If it is not present, then we use only setApplication(). $plugin->setDatabase($container->get(DatabaseInterface::class)); return $plugin; } ); } };
檢查點
我們創(chuàng)建了一種從 Joomla 查詢數(shù)據(jù)庫的方法,并了解了很多有關智能搜索插件如何工作的知識。
在下一篇文章中,我們將創(chuàng)建一個索引內容的方法并完成插件的創(chuàng)建。我們還將熟悉索引項如何存儲在數(shù)據(jù)庫中,并理解為什么這很重要,并通過多語言的非標準實現(xiàn)解決多語言組件的索引內容問題。
Joomla 社區(qū)資源
- https://joomla.org/
- Joomla 社區(qū)雜志中的這篇文章
- Mattermost 中的 Joomla 社區(qū)聊天(了解更多)
以上是Joomla 藝術中智能搜索的剖析 創(chuàng)建插件 I.的詳細內容。更多信息請關注PHP中文網(wǎng)其他相關文章!

熱AI工具

Undress AI Tool
免費脫衣服圖片

Undresser.AI Undress
人工智能驅動的應用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover
用于從照片中去除衣服的在線人工智能工具。

Clothoff.io
AI脫衣機

Video Face Swap
使用我們完全免費的人工智能換臉工具輕松在任何視頻中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的代碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
功能強大的PHP集成開發(fā)環(huán)境

Dreamweaver CS6
視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版
神級代碼編輯軟件(SublimeText3)

要合并兩個PHP數(shù)組并保留唯一值,有兩種主要方法。1.對于索引數(shù)組或僅需值去重的情況,使用array_merge和array_unique組合:先用array_merge($array1,$array2)合并數(shù)組,再用array_unique()去重,最終得到包含所有唯一值的新數(shù)組;2.對于關聯(lián)數(shù)組且希望保留第一個數(shù)組中的鍵值對時,使用 運算符:$result=$array1 $array2,這將確保第一個數(shù)組中的鍵不會被第二個數(shù)組覆蓋。這兩種方法分別適用于不同場景,根據(jù)是否需要保留鍵名或只關注

判斷密碼強度需結合正則與邏輯處理,基礎要求包括:1.長度不少于8位;2.至少含小寫字母、大寫字母、數(shù)字;3.可加入特殊字符限制;進階方面需避免連續(xù)重復字符及遞增/遞減序列,這需PHP函數(shù)檢測;同時應引入黑名單過濾常見弱密碼如password、123456;最終建議結合zxcvbn庫提升評估精度。

要安全處理PHP文件上傳需驗證來源與類型、控制文件名與路徑、設置服務器限制并二次處理媒體文件。1.驗證上傳來源通過token防止CSRF并通過finfo_file檢測真實MIME類型使用白名單控制;2.重命名文件為隨機字符串并根據(jù)檢測類型決定擴展名存儲至非Web目錄;3.PHP配置限制上傳大小及臨時目錄Nginx/Apache禁止訪問上傳目錄;4.GD庫重新保存圖片清除潛在惡意數(shù)據(jù)。

PHP變量作用域常見問題及解決方法包括:1.函數(shù)內部無法訪問全局變量,需使用global關鍵字或參數(shù)傳入;2.靜態(tài)變量用static聲明,只初始化一次并在多次調用間保持值;3.超全局變量如$_GET、$_POST可在任何作用域直接使用,但需注意安全過濾;4.匿名函數(shù)需通過use關鍵字引入父作用域變量,修改外部變量則需傳遞引用。掌握這些規(guī)則有助于避免錯誤并提升代碼穩(wěn)定性。

PHP注釋代碼常用方法有三種:1.單行注釋用//或#屏蔽一行代碼,推薦使用//;2.多行注釋用/.../包裹代碼塊,不可嵌套但可跨行;3.組合技巧注釋如用/if(){}/控制邏輯塊,或配合編輯器快捷鍵提升效率,使用時需注意閉合符號和避免嵌套。

寫好PHP注釋的關鍵在于明確目的與規(guī)范,注釋應解釋“為什么”而非“做了什么”,避免冗余或過于簡單。1.使用統(tǒng)一格式,如docblock(/*/)用于類、方法說明,提升可讀性與工具兼容性;2.強調邏輯背后的原因,如說明為何需手動輸出JS跳轉;3.在復雜代碼前添加總覽性說明,分步驟描述流程,幫助理解整體思路;4.合理使用TODO和FIXME標記待辦事項與問題,便于后續(xù)追蹤與協(xié)作。好的注釋能降低溝通成本,提升代碼維護效率。

AgeneratorinPHPisamemory-efficientwaytoiterateoverlargedatasetsbyyieldingvaluesoneatatimeinsteadofreturningthemallatonce.1.Generatorsusetheyieldkeywordtoproducevaluesondemand,reducingmemoryusage.2.Theyareusefulforhandlingbigloops,readinglargefiles,or

在PHP中創(chuàng)建數(shù)組的方法有兩種:使用array()函數(shù)或使用中括號[]。1.使用array()函數(shù)是傳統(tǒng)方式,兼容性好,定義索引數(shù)組如$fruits=array("apple","banana","orange"),關聯(lián)數(shù)組如$user=array("name"=>"John","age"=>25);2.使用[]是從PHP5.4開始支持的更簡潔的方式,如$color
