前の記事では、Joomla スマート検索コンポーネントの機能について説明し、CRON を使用したスケジュールされたインデックス作成のパラメーターと構成について説明しました。独自のプラグインのコードの作成を始めましょう。
技術的な部分を始める前に、主要なトピックに直接対処するいくつかの記事について言及します。 Joomla 4 / Joomla 5 の最新アーキテクチャ用のプラグインの作成および/または更新を一般的にカバーする記事と同様に、次に、読者がそれらを読んで、機能するプラグインを作成する方法について大体のアイデアを持っていると仮定します。 Joomla の場合:
経験豊富な開発者のために、検索プラグインは JoomlaComponentFinderAdministratorIndexerAdapter クラスを拡張するものであると説明します。クラス ファイルは administrator/components/com_finder/src/Indexer/Adapter.php にあります。そうすれば、彼らは自分でそれを理解するでしょう。また、サンプルとして、plugins/finder フォルダー内の記事、カテゴリ、連絡先、タグなどの Joomla コア スマート検索プラグインを調べることができます。私は JoomShopping (Joomla e-commerce コンポーネント) および SW JProjects (更新サーバーを備えた独自の Joomla 拡張機能ディレクトリ コンポーネント) コンポーネントのスマート検索プラグインに取り組んだため、クラス名といくつかのニュアンスはそれらに関連付けられています。 JoomShopping の例を使用してそのほとんどを説明します。多言語使用の問題の解決策は、SW JProjects の例に基づいています。
Joomshopping のスマート検索プラグインのファイル構造は、一般的なものと変わりません。
Joomla 5 スマート検索プラグインのファイル構造
ファイル 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.
です。操作に必要なクラス プロパティとメソッドの最小限のセットがあります (親のアダプター クラスを含めてアクセスされます)。
<?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() メソッドについて説明されているにもかかわらず、getListQuery() メソッドは実際には必須ではないためです。
「複雑なスキーム」に関するあらゆる写真をここに投稿できます。
私たちが気づく前に、情報やアイデアが何度もグルグルと私たちの前を通り過ぎてしまうのは驚くべきことです。多くの物事は、1 年以上私たちの目の前にあるにもかかわらず、まだ認識されておらず、私たちの注意がそれらに集中するのは、何年もの経験を経てからです。
Joomla に関連して、何らかの理由で、そのコンポーネントが Joomla に特徴的なある種の共通アーキテクチャを想定しているというビジョンがすぐには浮かびません (これは明白な事実ですが)。データベースのテーブル構造のレベルにも含まれます。 Joomla コンテンツ テーブルのいくつかのフィールドを見てみましょう。特定の列名は私たちにとってそれほど重要ではないことを留保します (いつでもタイトルとして SELECT 名をクエリできます)。1 つのインデックス付き要素のデータ構造はどれくらいですか:
テーブル #__content (Joomla 記事)、#__contact_details (連絡先コンポーネント)、#__tags (Joomla タグ)、#__categories (Joomla カテゴリ コンポーネント) を比較すると、リストされているほぼすべてのデータ型がどこでも見つかります。
スマート検索プラグインが作成されるコンポーネントが「Joomla 方式」に従っており、そのアーキテクチャを継承している場合は、プラグイン クラス内の最小限のメソッドで実行できます。開発者が簡単な方法を探さずに独自の道を進むことに決めた場合、Adapter クラスのほぼすべてのメソッドを再定義するという困難な方法を選択する必要があります。
このメソッドは 3 つの場合に呼び出されます:
Joomla コア プラグインの実装例を見てみましょう:
<?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 オブジェクトを返します。このオブジェクトには、テーブルの名前と選択対象のフィールドがすでに指定されています。これを呼び出すメソッドでの作業が続行されます。
DatabaseQuery $query オブジェクトの getContentCount() から getListQuery() が呼び出された場合、select の設定値は COUNT(*) に置き換えられます。
getItem($id) から getListQuery() が呼び出された場合、条件 $query->where('a.id = ' . (int) $id) および特定の要素のみが選択されます。そして、すでにここで、親のアダプター クラスにクエリ内のテーブル名が a.* として含まれていることがわかります。これは、getListQuery() メソッドの実装でもこれらのプレフィックスを使用する必要があることを意味します。
getItems() から getListQuery() を呼び出す場合、インデックス付けのための要素のリスト内を移動するために、作成したクエリに $offset と $limit が追加されます。
概要: getListQuery() - 3 つの異なる SQL クエリの「ワークピース」が含まれている必要があります。 そして、ここでの Joomla の実装に関して特に難しいことは何もありません。ただし、必要に応じて、getListQuery() を作成せずに 3 つのメソッドを自分で実装することもできます。
Joomla 以外の方法: JoomShopping の場合、製品には複数のカテゴリを含めることができ、歴史的に製品のカテゴリ ID (catid) コンポーネントは別のテーブルに保存されているという事実に遭遇しました。同時に、長年にわたり、製品の主要カテゴリを指定することはできませんでした。製品カテゴリを受信すると、カテゴリを含むテーブルにクエリが送信され、最初のクエリ結果だけが取得され、デフォルトのカテゴリ ID (つまり昇順) で並べ替えられました。製品の編集時にカテゴリを変更した場合、メインの製品カテゴリは ID 番号が小さいカテゴリになります。製品の URL はそれに基づいており、製品はあるカテゴリから別のカテゴリにジャンプできました。
しかし、ほぼ 2 年前、この JoomShopping の動作は修正されました。このコンポーネントには長い歴史があり、利用者が多く、下位互換性を単に破ることはできないため、修正はオプションになりました。製品のメイン カテゴリを指定する機能は、コンポーネント設定で有効にする必要があります。次に、main_category_id が製品とともにテーブルに入力されます。
ただし、この機能はデフォルトで無効になっています。 そして、スマート検索プラグインでは、JoomShopping コンポーネントのパラメータを取得する必要があります。メインの製品カテゴリを指定するオプションが有効になっているかどうかを確認します (そして、最近有効になっている可能性があり、一部の製品のメイン カテゴリが指定されていない - これもニュアンス...) を作成し、コンポーネント パラメータに基づいて製品を受け取るための SQL クエリを生成します。main_category_id フィールドを追加する単純なクエリのいずれかです。 、 または古い間違った方法でカテゴリ ID を取得するための JOIN リクエスト。
このリクエストではすぐに、多言語使用のニュアンスが前面に出てきます。 Joomla の方法によれば、サイトの言語ごとに個別の要素が作成され、それらの間に関連付けが設定されます。それで、ロシア語については、1つの記事です。同じ英語記事を別途作成中です。次に、言語の関連付けを使用してそれらを相互に接続し、Joomla フロントエンドで言語を切り替えると、ある記事から別の記事にリダイレクトされます。
これは JoomShopping では行われません。 すべての言語のデータは商品と同じテーブルに保存されます (OK)。他の言語のデータを追加するには、これらの言語の接尾辞 (うーん...) が付いている列を追加します。つまり、データベースにはタイトルや名前のフィールドだけが存在するわけではありません。ただし、name_ru-RU、name_en-GB などのフィールドがあります。
Joomla JoomShopping 製品テーブル構造フラグメント
同時に、管理パネルと CLI の両方からインデックスを作成できるように、ユニバーサル SQL クエリを設計する必要があります。同時に、CRON を使用して CLI を起動するときにインデックス言語を選択することも作業です。この記事を書いている時点では、当分の間、この問題の本格的な解決策を延期していたことを認めます。言語は独自の getLangTag() メソッドを使用して選択されます。このメソッドでは、JoomShopping パラメータからメイン言語を取得するか、サイトのデフォルト言語を取得します。つまり、これまでのところ、このソリューションは単一言語サイトのみを対象としています。別の言語での検索はまだ機能しません。
しかし、3 か月後、私はこの問題を解決しました。しかし、すでに SW JProjects コンポーネントのスマート検索プラグインに含まれていました。解決策についてはまた改めてお伝えします。
それまでの間、JoomShopping に何が起こったのか見てみましょう
<?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; } ); } };
私たちは Joomla からデータベースにクエリを実行するメソッドを作成し、スマート検索プラグインがどのように機能するかについて多くのことを学びました。
次の記事では、コンテンツのインデックスを作成するメソッドを作成し、プラグインの作成を完了します。また、インデックス付きアイテムがデータベースにどのように保存されるのかを知り、これが重要である理由を理解し、多言語の非標準実装による多言語コンポーネントのコンテンツのインデックス付けの問題を解決します。
以上がJoomla アートにおけるスマート検索の構造 プラグインの作成 I.の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。