1. Magento PHP开发全指南从入门到精通作为一名在Magento开发领域深耕多年的技术专家我经常被问到如何系统性地掌握这个强大的电商平台开发。Magento作为全球最受欢迎的企业级电商解决方案之一其PHP开发体系既强大又复杂。本文将带你全面了解Magento PHP开发的核心要点。Magento开发不同于常规PHP项目它采用独特的模块化架构和MVC模式拥有自己的ORM系统和事件观察者机制。要成为合格的Magento开发者需要掌握以下几个关键领域1.1 Magento架构基础Magento采用模块化设计每个功能都以模块形式存在。典型的模块目录结构包含Block视图逻辑处理controllers控制器etc配置文件Helper辅助函数Model数据模型sql数据库脚本这种结构确保了代码的高度可维护性和扩展性。我建议新手开发者首先熟悉这种目录规范这是后续开发的基础。1.2 开发环境搭建工欲善其事必先利其器。Magento开发环境配置需要注意以下几点PHP版本Magento 2.x需要PHP 7.4数据库MySQL 5.7或MariaDB 10.2Web服务器Apache/Nginx开发工具推荐使用Docker容器化环境我个人的开发环境配置如下# Docker-compose示例配置 version: 3 services: web: image: php:7.4-apache ports: - 8080:80 volumes: - ./:/var/www/html links: - db db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: magento1.3 核心开发概念1.3.1 模块创建每个Magento扩展都以模块形式存在。创建模块需要以下步骤在app/code目录下创建模块目录结构创建etc/module.xml声明模块注册模块到Magento系统示例模块结构app/code/ Vendor/ Module/ Block/ Controller/ etc/ module.xml Model/ registration.php1.3.2 依赖注入Magento 2.x全面采用依赖注入(DI)设计模式。理解DI容器和对象管理器是关键// 通过构造函数注入依赖 public function __construct( \Magento\Catalog\Model\ProductFactory $productFactory ) { $this-productFactory $productFactory; }1.3.3 布局和模板系统Magento的视图层由布局XML和模板文件组成布局XML定义页面结构和块位置模板文件(.phtml)包含HTML和PHP混合代码示例布局文件page xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:noNamespaceSchemaLocationurn:magento:framework:View/Layout/etc/page_configuration.xsd body referenceContainer namecontent block classVendor\Module\Block\CustomBlock namecustom.block templateVendor_Module::custom.phtml/ /referenceContainer /body /page2. 数据库与模型开发2.1 数据模型创建Magento提供强大的ORM系统开发者可以通过模型与数据库交互// 创建模型 namespace Vendor\Module\Model; class CustomModel extends \Magento\Framework\Model\AbstractModel { protected function _construct() { $this-_init(Vendor\Module\Model\ResourceModel\CustomModel); } }对应的资源模型namespace Vendor\Module\Model\ResourceModel; class CustomModel extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb { protected function _construct() { $this-_init(vendor_module_table, entity_id); } }2.2 数据库安装脚本Magento使用安装脚本来管理数据库结构变更// InstallSchema.php namespace Vendor\Module\Setup; use Magento\Framework\Setup\InstallSchemaInterface; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\SchemaSetupInterface; class InstallSchema implements InstallSchemaInterface { public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) { $installer $setup; $installer-startSetup(); $table $installer-getConnection()-newTable( $installer-getTable(vendor_module_table) )-addColumn( entity_id, \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, [identity true, unsigned true, nullable false, primary true], Entity ID )-addColumn( name, \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 255, [nullable false], Name ); $installer-getConnection()-createTable($table); $installer-endSetup(); } }2.3 EAV模型对于需要灵活属性的实体Magento提供了EAV(Entity-Attribute-Value)模型// 创建EAV模型 namespace Vendor\Module\Model; class CustomEavModel extends \Magento\Framework\Model\AbstractModel { protected function _construct() { $this-_init(Vendor\Module\Model\ResourceModel\CustomEavModel); } }对应的资源模型需要继承Eav资源类namespace Vendor\Module\Model\ResourceModel; class CustomEavModel extends \Magento\Eav\Model\Entity\AbstractEntity { protected function _construct() { $this-setType(custom_eav_model); $this-setConnection(core_read, core_write); } }3. 前端开发实践3.1 控制器开发Magento控制器处理用户请求并返回响应namespace Vendor\Module\Controller\Index; class Index extends \Magento\Framework\App\Action\Action { protected $resultPageFactory; public function __construct( \Magento\Framework\App\Action\Context $context, \Magento\Framework\View\Result\PageFactory $resultPageFactory ) { $this-resultPageFactory $resultPageFactory; parent::__construct($context); } public function execute() { $resultPage $this-resultPageFactory-create(); $resultPage-getConfig()-getTitle()-set(__(Custom Page Title)); return $resultPage; } }3.2 块(Block)开发块是Magento中处理业务逻辑的组件namespace Vendor\Module\Block; class CustomBlock extends \Magento\Framework\View\Element\Template { protected $productFactory; public function __construct( \Magento\Framework\View\Element\Template\Context $context, \Magento\Catalog\Model\ProductFactory $productFactory, array $data [] ) { $this-productFactory $productFactory; parent::__construct($context, $data); } public function getProductCollection() { $collection $this-productFactory-create()-getCollection(); $collection-addAttributeToSelect(*) -setPageSize(5); return $collection; } }3.3 模板开发模板文件(.phtml)负责显示逻辑?php /** var \Vendor\Module\Block\CustomBlock $block */ $products $block-getProductCollection(); ? div classproduct-list ?php foreach ($products as $product): ? div classproduct-item h3? $block-escapeHtml($product-getName()) ?/h3 p? $block-escapeHtml($product-getSku()) ?/p /div ?php endforeach; ? /div4. 后端开发与管理界面4.1 管理网格(Grid)开发Magento后台网格用于展示数据列表namespace Vendor\Module\Block\Adminhtml\Custom\Grid; class Grid extends \Magento\Backend\Block\Widget\Grid\Extended { protected $collectionFactory; public function __construct( \Magento\Backend\Block\Template\Context $context, \Magento\Backend\Helper\Data $backendHelper, \Vendor\Module\Model\ResourceModel\CustomModel\CollectionFactory $collectionFactory, array $data [] ) { $this-collectionFactory $collectionFactory; parent::__construct($context, $backendHelper, $data); } protected function _prepareCollection() { $collection $this-collectionFactory-create(); $this-setCollection($collection); return parent::_prepareCollection(); } protected function _prepareColumns() { $this-addColumn(entity_id, [ header __(ID), index entity_id, ]); $this-addColumn(name, [ header __(Name), index name, ]); return parent::_prepareColumns(); } }4.2 表单开发管理后台表单用于数据编辑namespace Vendor\Module\Block\Adminhtml\Custom\Edit; class Form extends \Magento\Backend\Block\Widget\Form\Generic { protected function _prepareForm() { $form $this-_formFactory-create([ data [ id edit_form, action $this-getData(action), method post ] ]); $fieldset $form-addFieldset(base_fieldset, [ legend __(General Information) ]); $fieldset-addField(name, text, [ name name, label __(Name), title __(Name), required true ]); $form-setUseContainer(true); $this-setForm($form); return parent::_prepareForm(); } }4.3 控制器开发后台控制器处理管理界面请求namespace Vendor\Module\Controller\Adminhtml\Custom; class Save extends \Magento\Backend\App\Action { protected $customModelFactory; public function __construct( \Magento\Backend\App\Action\Context $context, \Vendor\Module\Model\CustomModelFactory $customModelFactory ) { $this-customModelFactory $customModelFactory; parent::__construct($context); } public function execute() { $data $this-getRequest()-getPostValue(); $id $this-getRequest()-getParam(entity_id); try { $model $this-customModelFactory-create(); if ($id) { $model-load($id); } $model-setData($data); $model-save(); $this-messageManager-addSuccess(__(Record has been saved.)); } catch (\Exception $e) { $this-messageManager-addError($e-getMessage()); } return $this-_redirect(*/*/); } }5. 高级开发技巧5.1 插件(Plugin)开发插件用于修改现有类的方法行为namespace Vendor\Module\Plugin; class ProductPlugin { public function afterGetName(\Magento\Catalog\Model\Product $product, $result) { return $result . (Modified); } }对应的di.xml配置config xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:noNamespaceSchemaLocationurn:magento:framework:ObjectManager/etc/config.xsd type nameMagento\Catalog\Model\Product plugin namevendor_module_product_plugin typeVendor\Module\Plugin\ProductPlugin / /type /config5.2 事件观察者Magento的事件系统允许模块间松耦合通信namespace Vendor\Module\Observer; class CustomObserver implements \Magento\Framework\Event\ObserverInterface { public function execute(\Magento\Framework\Event\Observer $observer) { $product $observer-getEvent()-getProduct(); // 自定义逻辑 } }对应的事件配置config xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:noNamespaceSchemaLocationurn:magento:framework:Event/etc/events.xsd event namecatalog_product_save_after observer namevendor_module_custom_observer instanceVendor\Module\Observer\CustomObserver / /event /config5.3 命令行工具创建自定义命令行工具namespace Vendor\Module\Console\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class CustomCommand extends Command { protected function configure() { $this-setName(vendor:module:custom) -setDescription(Custom command description); parent::configure(); } protected function execute(InputInterface $input, OutputInterface $output) { $output-writeln(Executing custom command); // 自定义逻辑 } }6. 性能优化与调试6.1 缓存优化Magento的缓存系统对性能至关重要// 清除特定缓存类型 $cacheType block_html; $cacheTypeList $this-cacheTypeList; $cacheTypeList-cleanType($cacheType); // 刷新缓存标签 $cacheFrontendPool $this-cacheFrontendPool; $cacheFrontend $cacheFrontendPool-get(\Magento\Framework\App\Cache\Type\Block::TYPE_IDENTIFIER); $cacheFrontend-clean(\Zend_Cache::CLEANING_MODE_MATCHING_TAG, [cache_tag]);6.2 数据库查询优化优化数据库查询是提升性能的关键// 使用索引提示 $collection $this-productCollectionFactory-create(); $collection-getSelect()-join( [stock $collection-getTable(cataloginventory_stock_item)], e.entity_id stock.product_id, [qty] )-where(stock.qty ?, 0) -useStraightJoin(); // 使用EXPLAIN分析查询 $connection $collection-getConnection(); $query $collection-getSelect()-__toString(); $explain $connection-query(EXPLAIN . $query)-fetchAll();6.3 调试技巧有效的调试方法// 日志记录 $this-_logger-info(Debug message, [context $data]); // 开发者模式工具 \Magento\Framework\App\ObjectManager::getInstance() -get(\Magento\Framework\App\State::class) -getMode(); // XDebug配置 // php.ini配置示例 [xdebug] zend_extensionxdebug.so xdebug.remote_enable1 xdebug.remote_hostlocalhost xdebug.remote_port9000 xdebug.idekeyPHPSTORM7. 安全最佳实践7.1 输入验证与过滤// 使用Magento的escape方法 $escapedValue $this-escapeHtml($userInput); // 使用验证器 $validator new \Zend_Validate_EmailAddress(); if (!$validator-isValid($email)) { throw new \Magento\Framework\Exception\LocalizedException(__(Invalid email address)); } // 使用过滤器 $filter new \Zend_Filter_StripTags(); $cleanInput $filter-filter($userInput);7.2 CSRF防护Magento内置CSRF防护机制// 表单中添加CSRF令牌 $formKey $this-formKey-getFormKey(); input nameform_key typehidden value? $formKey ? // 控制器中验证 if (!$this-getRequest()-isPost() || !$this-_validateFormKey()) { $this-_redirect(*/*/); return; }7.3 文件上传安全// 安全的文件上传处理 $uploader $this-_fileUploaderFactory-create([fileId file]); $uploader-setAllowedExtensions([jpg, jpeg, png]); $uploader-setAllowRenameFiles(true); $uploader-setFilesDispersion(true); $uploader-setAllowCreateFolders(true); $path $this-_filesystem-getDirectoryRead(DirectoryList::MEDIA)-getAbsolutePath(custom/); $result $uploader-save($path);8. 部署与维护8.1 部署流程# 生产环境部署命令 php bin/magento deploy:mode:set production php bin/magento setup:upgrade php bin/magento setup:di:compile php bin/magento setup:static-content:deploy -f php bin/magento cache:flush8.2 模块打包# 创建模块包 mkdir -p package/app/code/Vendor/Module cp -R app/code/Vendor/Module/* package/app/code/Vendor/Module/ cd package zip -r Vendor_Module.zip .8.3 升级策略// UpgradeSchema.php示例 namespace Vendor\Module\Setup; use Magento\Framework\Setup\UpgradeSchemaInterface; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\SchemaSetupInterface; class UpgradeSchema implements UpgradeSchemaInterface { public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context) { $setup-startSetup(); if (version_compare($context-getVersion(), 1.0.1, )) { // 1.0.1版本升级逻辑 } $setup-endSetup(); } }9. 实战案例分析9.1 自定义产品类型开发// 产品类型类 namespace Vendor\Module\Model\Product\Type; class CustomType extends \Magento\Catalog\Model\Product\Type\AbstractType { const TYPE_CODE custom_type; public function deleteTypeSpecificData(\Magento\Catalog\Model\Product $product) { // 自定义删除逻辑 } }9.2 支付网关集成// 支付方法模型 namespace Vendor\Module\Model\Payment; class CustomMethod extends \Magento\Payment\Model\Method\AbstractMethod { const CODE vendor_module_custom; protected $_code self::CODE; protected $_isOffline true; public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount) { // 授权逻辑 } }9.3 多店铺配置// 获取当前店铺信息 $storeManager \Magento\Framework\App\ObjectManager::getInstance() -get(\Magento\Store\Model\StoreManagerInterface::class); $currentStore $storeManager-getStore(); $websiteId $currentStore-getWebsiteId(); $storeId $currentStore-getId();10. 常见问题解决10.1 安装问题排查# 检查系统要求 php -r print_r(get_loaded_extensions()); php -r echo ini_get(memory_limit).PHP_EOL; # 解决权限问题 find var generated vendor pub/static pub/media app/etc -type f -exec chmod gw {} find var generated vendor pub/static pub/media app/etc -type d -exec chmod gws {} chown -R :www-data .10.2 性能问题分析# 使用Blackfire分析 blackfire run php bin/magento catalog:product:index # 使用New Relic监控 // 在app/etc/env.php中添加配置 system [ default [ newrelicreporting [ general [ enable 1, app_name Magento 2 Store ] ] ] ]10.3 扩展冲突解决// 使用偏好(preference)解决冲突 config xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:noNamespaceSchemaLocationurn:magento:framework:ObjectManager/etc/config.xsd preference forMagento\Catalog\Model\Product typeVendor\Module\Model\CustomProduct / /config11. 测试与质量保证11.1 单元测试namespace Vendor\Module\Test\Unit\Model; class CustomModelTest extends \PHPUnit\Framework\TestCase { protected $objectManager; protected $customModel; protected function setUp(): void { $this-objectManager new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this-customModel $this-objectManager-getObject(\Vendor\Module\Model\CustomModel::class); } public function testGetName() { $this-customModel-setName(Test); $this-assertEquals(Test, $this-customModel-getName()); } }11.2 集成测试namespace Vendor\Module\Test\Integration\Model; class CustomModelTest extends \Magento\TestFramework\TestCase\AbstractController { public function testSave() { $model \Magento\TestFramework\Helper\Bootstrap::getObjectManager() -create(\Vendor\Module\Model\CustomModel::class); $model-setName(Test); $model-save(); $this-assertNotEmpty($model-getId()); } }11.3 功能测试namespace Vendor\Module\Test\Functional; class FrontendTest extends \Magento\TestFramework\TestCase\AbstractController { public function testIndexAction() { $this-dispatch(module/index/index); $this-assertStringContainsString(Expected Content, $this-getResponse()-getBody()); } }12. 持续集成与部署12.1 CI/CD配置# .gitlab-ci.yml示例 stages: - test - deploy phpunit: stage: test script: - php bin/magento setup:upgrade - vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist deploy_production: stage: deploy script: - rsync -avz --delete ./ userproduction:/var/www/html/ only: - master12.2 自动化测试# 运行静态代码分析 php vendor/bin/phpcs --standardMagento2 app/code/Vendor/Module # 运行测试套件 php bin/magento dev:tests:run unit integration functional12.3 监控与告警// 自定义健康检查 namespace Vendor\Module\Controller\Health; class Check extends \Magento\Framework\App\Action\Action { public function execute() { $response [ status OK, timestamp time(), checks [ database $this-checkDatabase(), cache $this-checkCache() ] ]; return $this-getResponse()-representJson(json_encode($response)); } protected function checkDatabase() { try { $connection $this-_resource-getConnection(); $connection-query(SELECT 1); return true; } catch (\Exception $e) { return false; } } }13. 社区资源与进阶学习13.1 官方资源Magento官方文档Magento MarketplaceMagento GitHub13.2 社区论坛Magento Stack ExchangeMagento Forumsr/Magento on Reddit13.3 推荐书籍Magento 2 Development Quick Start Guide by Branko AjzeleMagento 2 Module Development by Bastian IkeMastering Magento 2 by Bret Williams14. 未来发展趋势14.1 PWA与Headless架构// React组件与Magento GraphQL交互示例 import React from react; import { useQuery } from apollo/client; import { gql } from apollo/client; const GET_PRODUCTS gql query { products(search: Yoga) { items { name sku price_range { minimum_price { regular_price { value currency } } } } } } ; function ProductList() { const { loading, error, data } useQuery(GET_PRODUCTS); if (loading) return pLoading.../p; if (error) return pError :(/p; return data.products.items.map(({ name, sku, price_range }) ( div key{sku} h3{name}/h3 p{price_range.minimum_price.regular_price.value}/p /div )); }14.2 微服务架构# docker-compose.yml微服务示例 version: 3 services: magento: image: magento/magento-cloud-docker-php:7.4-fpm depends_on: - mysql - redis - elasticsearch - rabbitmq environment: - DB_HOSTmysql - REDIS_HOSTredis - ELASTICSEARCH_HOSTelasticsearch - RABBITMQ_HOSTrabbitmq14.3 AI与个性化// 个性化产品推荐示例 namespace Vendor\Module\Model; class ProductRecommender { protected $customerSession; protected $productCollectionFactory; public function __construct( \Magento\Customer\Model\Session $customerSession, \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory ) { $this-customerSession $customerSession; $this-productCollectionFactory $productCollectionFactory; } public function getRecommendedProducts() { $customerId $this-customerSession-getCustomerId(); $collection $this-productCollectionFactory-create(); // 基于AI模型的推荐逻辑 $collection-addAttributeToFilter(entity_id, [in $this-getAiRecommendations($customerId)]); return $collection; } }15. 职业发展与认证15.1 Magento认证路径Magento Certified Associate DeveloperMagento Certified Professional DeveloperMagento Certified Professional Front End DeveloperMagento Certified Solution Specialist15.2 技能矩阵技能等级PHPMySQLJavaScriptMagento核心初级熟悉语法基础查询jQuery基础模块结构中级OOP精通优化查询RequireJS插件开发高级设计模式分库分表React/Vue核心修改15.3 薪资参考根据2023年数据初级开发者: $60,000-$80,000中级开发者: $80,000-$120,000高级开发者: $120,000-$160,000架构师: $160,00016. 项目实战礼品登记系统16.1 需求分析允许客户创建礼品登记添加产品到登记分享登记链接查看登记状态16.2 数据库设计CREATE TABLE mdg_giftregistry_entity ( entity_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, customer_id INT UNSIGNED NOT NULL, event_name VARCHAR(255) NOT NULL, event_date DATE NOT NULL, event_location VARCHAR(255) NOT NULL, FOREIGN KEY (customer_id) REFERENCES customer_entity(entity_id) ); CREATE TABLE mdg_giftregistry_item ( item_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, registry_id INT UNSIGNED NOT NULL, product_id INT UNSIGNED NOT NULL, qty DECIMAL(12,4) NOT NULL, FOREIGN KEY (registry_id) REFERENCES mdg_giftregistry_entity(entity_id), FOREIGN KEY (product_id) REFERENCES catalog_product_entity(entity_id) );16.3 核心代码实现// 登记模型 namespace Mdg\Giftregistry\Model; class Entity extends \Magento\Framework\Model\AbstractModel { protected function _construct() { $this-_init(Mdg\Giftregistry\Model\ResourceModel\Entity); } public function addProduct($productId, $qty 1) { $item $this-itemFactory-create(); $item-setRegistryId($this-getId()) -setProductId($productId) -setQty($qty); $item-save(); return $this; } }17. 性能调优实战17.1 前端优化!-- 合并压缩静态资源 -- config xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:noNamespaceSchemaLocationurn:magento:framework:View/etc/config.xsd css minify1/minify merge1/merge /css js minify1/minify merge1/merge /js /config17.2 后端优化// 使用缓存提升性能 namespace Vendor\Module\Model; class DataProvider { protected $cache; public function __construct( \Magento\Framework\App\CacheInterface $cache ) { $this-cache $cache; } public function getExpensiveData() { $cacheKey expensive_data_cache; $data $this-cache-load($cacheKey); if (!$data) { $data $this-calculateExpensiveData(); $this-cache-save(json_encode($data), $cacheKey, [], 3600); } else { $data json_decode($data, true); } return $data; } }17.3 数据库优化-- 添加索引提升查询性能 ALTER TABLE mdg_giftregistry_entity ADD INDEX IDX_CUSTOMER_ID (customer_id); ALTER TABLE mdg_giftregistry_item ADD INDEX IDX_REGISTRY_ID (registry_id); ALTER TABLE mdg_giftregistry_item ADD INDEX IDX_PRODUCT_ID (product_id); -- 使用覆盖索引 EXPLAIN SELECT entity_id FROM mdg_giftregistry_entity WHERE customer_id 123;18. 多语言与国际化18.1 翻译文件!-- i18n/en_US.csv -- Create Gift Registry,Create Wishlist Event Name,Occasion Name Event Date,Occasion Date !-- i18n/zh_CN.csv -- Create Gift Registry,创建礼品登记 Event Name,活动名称 Event Date,活动日期18.2 区域设置// 获取当前区域设置 $locale $this-_localeResolver-getLocale(); $currencyCode $this-_storeManager-getStore()-getCurrentCurrencyCode(); // 格式化日期 $formattedDate $this-_localeDate-formatDateTime( new \DateTime(), \IntlDateFormatter::MEDIUM, \IntlDateFormatter::NONE );18.3 货币处理// 货币格式化 $priceHelper $this-_objectManager-get(\Magento\Framework\Pricing\Helper\Data::class); $formattedPrice $priceHelper-currency(99.99, true, false); // 多货币转换 $baseCurrency $this-_storeManager-getStore()-getBaseCurrency(); $currentCurrency $this-_storeManager-getStore()-getCurrentCurrency(); $convertedPrice $baseCurrency-convert(100, $currentCurrency);19. API开发与集成19.1 REST API开发namespace Vendor\Module\Api; interface CustomRepositoryInterface { /** * param int $id * return \Vendor\Module\Api\Data\CustomInterface * throws \Magento\Framework\Exception\NoSuchEntityException */ public function getById($id); /** * param \Vendor\Module\Api\Data\CustomInterface $custom * return \Vendor\Module\Api\Data\CustomInterface */ public function save(\Vendor\Module\Api\Data\CustomInterface $custom); } // webapi.xml配置 routes xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:noNamespaceSchemaLocationurn:magento:module:Magento_Webapi:etc/webapi.xsd route url/V1/custom/:id methodGET service classVendor\Module\Api\CustomRepositoryInterface methodgetById/ resources resource refanonymous/ /resources /route /routes19.2 GraphQL开发# schema.graphqls type Query { customProducts(search: String): [ProductInterface] resolver(class: Vendor\\Module\\Model\\Resolver\\Products) } # 解析器实现 namespace Vendor\Module\Model\Resolver; class Products implements \