一键导入
joomla-conventions
Joomla 4/5 component development with MVC, services, plugins, and language handling
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Joomla 4/5 component development with MVC, services, plugins, and language handling
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
RESTful API design patterns, HTTP standards, versioning, error handling, and documentation
Joomla 3.x legacy patterns with JFactory, non-namespaced MVC, JDatabase, and plugin structure
Laravel best practices for Eloquent, controllers, validation, services, and testing
Performance optimization for PHP, JavaScript, databases, and caching strategies
PHP coding standards including strict typing, OOP patterns, error handling, and documentation
Deep dive into SOLID principles with PHP/TypeScript examples, refactoring patterns, and violation detection
| name | joomla-conventions |
| description | Joomla 4/5 component development with MVC, services, plugins, and language handling |
| license | MIT |
| compatibility | opencode |
| metadata | {"cms":"joomla","version":"4.0+"} |
com_example/
├── administrator/
│ ├── forms/
│ │ └── item.xml
│ ├── services/
│ │ └── provider.php
│ ├── src/
│ │ ├── Controller/
│ │ ├── Extension/
│ │ ├── Field/
│ │ ├── Helper/
│ │ ├── Model/
│ │ ├── Service/
│ │ ├── Table/
│ │ └── View/
│ └── tmpl/
│ └── items/
├── site/
│ ├── src/
│ └── tmpl/
├── media/
│ ├── css/
│ └── js/
└── language/
└── en-GB/
<?php
declare(strict_types=1);
namespace Joomla\Component\Example\Administrator\Extension;
use Joomla\CMS\Extension\ComponentInterface;
use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory;
use Joomla\CMS\Extension\Service\Provider\MVCFactory;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
return new class implements ServiceProviderInterface
{
public function register(Container $container): void
{
$container->registerServiceProvider(new MVCFactory('\\Joomla\\Component\\Example'));
$container->registerServiceProvider(new ComponentDispatcherFactory('\\Joomla\\Component\\Example'));
$container->set(
ComponentInterface::class,
function (Container $container) {
$component = new ExampleComponent($container->get(ComponentDispatcherFactoryInterface::class));
$component->setMVCFactory($container->get(MVCFactoryInterface::class));
return $component;
}
);
}
};
<?php
declare(strict_types=1);
namespace Joomla\Component\Example\Administrator\Model;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\Database\QueryInterface;
class ItemsModel extends ListModel
{
protected function getListQuery(): QueryInterface
{
$db = $this->getDatabase();
$query = $db->getQuery(true);
$query->select($db->quoteName(['a.id', 'a.title', 'a.state']))
->from($db->quoteName('#__example_items', 'a'));
// Filter by state
$state = $this->getState('filter.state');
if (is_numeric($state)) {
$query->where($db->quoteName('a.state') . ' = :state')
->bind(':state', $state, ParameterType::INTEGER);
}
return $query;
}
}
<?php
declare(strict_types=1);
namespace Joomla\Component\Example\Administrator\Table;
use Joomla\CMS\Table\Table;
use Joomla\Database\DatabaseDriver;
class ItemTable extends Table
{
public function __construct(DatabaseDriver $db)
{
parent::__construct('#__example_items', 'id', $db);
}
public function check(): bool
{
if (empty($this->title)) {
$this->setError(Text::_('COM_EXAMPLE_ERROR_TITLE_REQUIRED'));
return false;
}
return true;
}
}
// ALWAYS use parameter binding
$query->where($db->quoteName('id') . ' = :id')
->bind(':id', $id, ParameterType::INTEGER);
// For strings
$query->where($db->quoteName('alias') . ' = :alias')
->bind(':alias', $alias, ParameterType::STRING);
// NEVER do this:
// $query->where('id = ' . $id); // SQL INJECTION!
// In PHP
use Joomla\CMS\Language\Text;
echo Text::_('COM_EXAMPLE_TITLE');
echo Text::sprintf('COM_EXAMPLE_ITEMS_COUNT', $count);
echo Text::plural('COM_EXAMPLE_N_ITEMS_DELETED', $count);
// In templates
<?php echo Text::_('COM_EXAMPLE_SUBMIT'); ?>
Language file (language/en-GB/com_example.ini):
COM_EXAMPLE_TITLE="Example Component"
COM_EXAMPLE_ITEMS_COUNT="Found %d items"
COM_EXAMPLE_N_ITEMS_DELETED="1 item deleted"
COM_EXAMPLE_N_ITEMS_DELETED_1="1 item deleted"
COM_EXAMPLE_N_ITEMS_DELETED_MORE="%d items deleted"
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fieldset name="details">
<field
name="title"
type="text"
label="COM_EXAMPLE_FIELD_TITLE_LABEL"
required="true"
maxlength="255"
/>
<field
name="state"
type="list"
label="JSTATUS"
default="1"
>
<option value="1">JPUBLISHED</option>
<option value="0">JUNPUBLISHED</option>
</field>
</fieldset>
</form>
<?php
declare(strict_types=1);
namespace Joomla\Plugin\System\Example\Extension;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\SubscriberInterface;
final class Example extends CMSPlugin implements SubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
'onAfterInitialise' => 'onAfterInitialise',
];
}
public function onAfterInitialise(): void
{
// Plugin logic here
}
}
use Joomla\CMS\Factory;
$user = Factory::getApplication()->getIdentity();
if (!$user->authorise('core.edit', 'com_example')) {
throw new \Exception(Text::_('JERROR_ALERTNOAUTHOR'), 403);
}
// In form
<?php echo HTMLHelper::_('form.token'); ?>
// In controller
if (!Session::checkToken()) {
throw new \Exception(Text::_('JINVALID_TOKEN'), 403);
}