Magento 2 REST API以一个简单的模块为例

亲爱的哈伯拉维兹,我欢迎您! 自从2013年以来我一直在Magento电子商务平台上进行开发以来,我积淀了勇气,并相信至少在这个领域我可以称自己为一个自信的开发人员,因此我决定在该中心上撰写有关该系统的第一篇文章。 我将从Magento 2中REST API的实现开始。这里,开箱即用的是用于处理请求的功能,我将尝试使用一个简单模块的示例进行演示。 本文更适合已与Magenta合作的人员。 因此,有兴趣的人请注意。

领带


我的想象力很差,所以我想出了以下示例:假设我们需要实现一个博客,只有管理面板中的用户才能编写文章。 有时,某些CRM会联系我们,并将这些文章上传到自己(为什么尚不清楚,但这就是我们使用REST API的理由)。 为了简化该模块,我特别省略了在前端和管理面板中显示文章的实现(您可以自己实现,我推荐一篇关于网格的好文章 )。 这里仅查询处理功能会受到影响。

行动发展


首先,创建模块的结构 ,我们将其称为AlexPoletaev_Blog (缺乏想象力并没有消失)。 我们将模块放在app / code目录中。

AlexPoletaev /博客/ etc / module.xml
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> <module name="AlexPoletaev_Blog" setup_version="1.0.0"/> </config> 


AlexPoletaev /博客/ registration.php
 <?php \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, 'AlexPoletaev_Blog', __DIR__ ); 


这两个文件是模块所需的最低要求。

如果一切在风水中完成,那么我们需要创建服务合同(洋红色中的内容以及它的工作方式,您可以在此处此处阅读),我们将这样做:

AlexPoletaev /博客/ Api /数据/ PostInterface.php
 <?php namespace AlexPoletaev\Blog\Api\Data; /** * Interface PostInterface * @package AlexPoletaev\Api\Data * @api */ interface PostInterface { /**#@+ * Constants * @var string */ const ID = 'id'; const AUTHOR_ID = 'author_id'; const TITLE = 'title'; const CONTENT = 'content'; const CREATED_AT = 'created_at'; const UPDATED_AT = 'updated_at'; /**#@-*/ /** * @return int */ public function getId(); /** * @param int $id * @return $this */ public function setId($id); /** * @return int */ public function getAuthorId(); /** * @param int $authorId * @return $this */ public function setAuthorId($authorId); /** * @return string */ public function getTitle(); /** * @param string $title * @return $this */ public function setTitle(string $title); /** * @return string */ public function getContent(); /** * @param string $content * @return $this */ public function setContent(string $content); /** * @return string */ public function getCreatedAt(); /** * @param string $createdAt * @return $this */ public function setCreatedAt(string $createdAt); /** * @return string */ public function getUpdatedAt(); /** * @param string $updatedAt * @return $this */ public function setUpdatedAt(string $updatedAt); } 


AlexPoletaev /博客/ Api / PostRepositoryInterface.php
 <?php namespace AlexPoletaev\Blog\Api; use AlexPoletaev\Blog\Api\Data\PostInterface; use Magento\Framework\Api\SearchCriteriaInterface; /** * Interface PostRepositoryInterface * @package AlexPoletaev\Api * @api */ interface PostRepositoryInterface { /** * @param int $id * @return \AlexPoletaev\Blog\Api\Data\PostInterface */ public function get(int $id); /** * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria * @return \AlexPoletaev\Blog\Api\Data\PostSearchResultInterface */ public function getList(SearchCriteriaInterface $searchCriteria); /** * @param \AlexPoletaev\Blog\Api\Data\PostInterface $post * @return \AlexPoletaev\Blog\Api\Data\PostInterface */ public function save(PostInterface $post); /** * @param \AlexPoletaev\Blog\Api\Data\PostInterface $post * @return bool */ public function delete(PostInterface $post); /** * @param int $id * @return bool */ public function deleteById(int $id); } 


让我们更详细地分析这两个接口。 PostInterface界面显示一个表格,其中包含来自我们博客的文章。 在下面创建一个表。 数据库中的每一列在此接口中都必须具有自己的getter和setter,我们稍后将找出为什么这很重要。 PostRepositoryInterface接口提供了一组标准方法,用于与数据库进行交互并将已加载的实体存储在缓存中。 API使用相同的方法。 另一个重要说明是,这些接口中必须存在正确的PHPDocs,因为Magenta在处理REST请求时会使用反射来确定方法中的输入参数和返回值。

使用安装脚本,创建一个表,该表将存储来自博客的帖子:

AlexPoletaev /博客/设置/ InstallSchema.php
 <?php namespace AlexPoletaev\Blog\Setup; use AlexPoletaev\Blog\Api\Data\PostInterface; use AlexPoletaev\Blog\Model\ResourceModel\Post as PostResource; use Magento\Framework\DB\Adapter\AdapterInterface; use Magento\Framework\DB\Ddl\Table; use Magento\Framework\Setup\InstallSchemaInterface; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\SchemaSetupInterface; use Magento\Security\Setup\InstallSchema as SecurityInstallSchema; /** * Class InstallSchema * @package AlexPoletaev\Blog\Setup */ class InstallSchema implements InstallSchemaInterface { /** * Installs DB schema for a module * * @param SchemaSetupInterface $setup * @param ModuleContextInterface $context * @return void */ public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) { $setup->startSetup(); $table = $setup->getConnection() ->newTable( $setup->getTable(PostResource::TABLE_NAME) ) ->addColumn( PostInterface::ID, Table::TYPE_INTEGER, null, ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], 'Post ID' ) ->addColumn( PostInterface::AUTHOR_ID, Table::TYPE_INTEGER, null, ['unsigned' => true, 'nullable' => true,], 'Author ID' ) ->addColumn( PostInterface::TITLE, Table::TYPE_TEXT, 255, [], 'Title' ) ->addColumn( PostInterface::CONTENT, Table::TYPE_TEXT, null, [], 'Content' ) ->addColumn( 'created_at', Table::TYPE_TIMESTAMP, null, ['nullable' => false, 'default' => Table::TIMESTAMP_INIT], 'Creation Time' ) ->addColumn( 'updated_at', Table::TYPE_TIMESTAMP, null, ['nullable' => false, 'default' => Table::TIMESTAMP_INIT_UPDATE], 'Update Time' ) ->addForeignKey( $setup->getFkName( PostResource::TABLE_NAME, PostInterface::AUTHOR_ID, SecurityInstallSchema::ADMIN_USER_DB_TABLE_NAME, 'user_id' ), PostInterface::AUTHOR_ID, $setup->getTable(SecurityInstallSchema::ADMIN_USER_DB_TABLE_NAME), 'user_id', Table::ACTION_SET_NULL ) ->addIndex( $setup->getIdxName( PostResource::TABLE_NAME, [PostInterface::AUTHOR_ID], AdapterInterface::INDEX_TYPE_INDEX ), [PostInterface::AUTHOR_ID], ['type' => AdapterInterface::INDEX_TYPE_INDEX] ) ->setComment('Posts') ; $setup->getConnection()->createTable($table); $setup->endSetup(); } } 


该表将包含以下几列(别忘了,我们将所有内容都尽可能简化):

  • id-自动递增
  • author_id-管理员用户标识(admin_user表中user_id字段上的外键)
  • 标题-标题
  • 内容-文章文字
  • created_at-创建日期
  • Updated_at-编辑日期

现在,您需要创建一组标准的洋红色模型ResourceModelCollection类。 为什么我不画这些类,所以这个主题很广泛,超出了本文的讨论范围,有兴趣的人可以自己搜索。 简而言之,需要这些类来操作数据库中的实体(文章)。 我建议您阅读有关域模型,存储库和服务层模式的信息。

AlexPoletaev /博客/模型/ Post.php
 <?php namespace AlexPoletaev\Blog\Model; use AlexPoletaev\Blog\Api\Data\PostInterface; use AlexPoletaev\Blog\Model\ResourceModel\Post as PostResource; use Magento\Framework\Model\AbstractModel; /** * Class Post * @package AlexPoletaev\Blog\Model */ class Post extends AbstractModel implements PostInterface { /** * @var string */ protected $_idFieldName = PostInterface::ID; //@codingStandardsIgnoreLine /** * @inheritdoc */ protected function _construct() //@codingStandardsIgnoreLine { $this->_init(PostResource::class); } /** * @return int */ public function getAuthorId() { return $this->getData(PostInterface::AUTHOR_ID); } /** * @param int $authorId * @return $this */ public function setAuthorId($authorId) { $this->setData(PostInterface::AUTHOR_ID, $authorId); return $this; } /** * @return string */ public function getTitle() { return $this->getData(PostInterface::TITLE); } /** * @param string $title * @return $this */ public function setTitle(string $title) { $this->setData(PostInterface::TITLE, $title); return $this; } /** * @return string */ public function getContent() { return $this->getData(PostInterface::CONTENT); } /** * @param string $content * @return $this */ public function setContent(string $content) { $this->setData(PostInterface::CONTENT, $content); return $this; } /** * @return string */ public function getCreatedAt() { return $this->getData(PostInterface::CREATED_AT); } /** * @param string $createdAt * @return $this */ public function setCreatedAt(string $createdAt) { $this->setData(PostInterface::CREATED_AT, $createdAt); return $this; } /** * @return string */ public function getUpdatedAt() { return $this->getData(PostInterface::UPDATED_AT); } /** * @param string $updatedAt * @return $this */ public function setUpdatedAt(string $updatedAt) { $this->setData(PostInterface::UPDATED_AT, $updatedAt); return $this; } } 


AlexPoletaev /博客/模型/ ResourceModel / Post.php
 <?php namespace AlexPoletaev\Blog\Model\ResourceModel; use AlexPoletaev\Blog\Api\Data\PostInterface; use Magento\Framework\Model\ResourceModel\Db\AbstractDb; /** * Class Post * @package AlexPoletaev\Blog\Model\ResourceModel */ class Post extends AbstractDb { /** * @var string */ const TABLE_NAME = 'alex_poletaev_blog_post'; /** * Resource initialization * * @return void */ protected function _construct() //@codingStandardsIgnoreLine { $this->_init(self::TABLE_NAME, PostInterface::ID); } } 


AlexPoletaev /博客/模型/ ResourceModel / Post / Collection.php
 <?php namespace AlexPoletaev\Blog\Model\ResourceModel\Post; use AlexPoletaev\Blog\Model\Post; use AlexPoletaev\Blog\Model\ResourceModel\Post as PostResource; use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; /** * Class Collection * @package AlexPoletaev\Blog\Model\ResourceModel\Post */ class Collection extends AbstractCollection { /** * @inheritdoc */ protected function _construct() //@codingStandardsIgnoreLine { $this->_init(Post::class, PostResource::class); } } 


细心的读者会注意到,我们的模型实现了先前创建的接口及其所有的getter和setter。

同时,我们实现存储库及其方法:

AlexPoletaev /博客/模型/ PostRepository.php
 <?php namespace AlexPoletaev\Blog\Model; use AlexPoletaev\Blog\Api\Data\PostInterface; use AlexPoletaev\Blog\Api\Data\PostSearchResultInterface; use AlexPoletaev\Blog\Api\Data\PostSearchResultInterfaceFactory; use AlexPoletaev\Blog\Api\PostRepositoryInterface; use AlexPoletaev\Blog\Model\ResourceModel\Post as PostResource; use AlexPoletaev\Blog\Model\ResourceModel\Post\Collection as PostCollection; use AlexPoletaev\Blog\Model\ResourceModel\Post\CollectionFactory as PostCollectionFactory; use AlexPoletaev\Blog\Model\PostFactory; use Magento\Framework\Api\SearchCriteriaInterface; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Exception\StateException; /** * Class PostRepository * @package AlexPoletaev\Blog\Model */ class PostRepository implements PostRepositoryInterface { /** * @var array */ private $registry = []; /** * @var PostResource */ private $postResource; /** * @var PostFactory */ private $postFactory; /** * @var PostCollectionFactory */ private $postCollectionFactory; /** * @var PostSearchResultInterfaceFactory */ private $postSearchResultFactory; /** * @param PostResource $postResource * @param PostFactory $postFactory * @param PostCollectionFactory $postCollectionFactory * @param PostSearchResultInterfaceFactory $postSearchResultFactory */ public function __construct( PostResource $postResource, PostFactory $postFactory, PostCollectionFactory $postCollectionFactory, PostSearchResultInterfaceFactory $postSearchResultFactory ) { $this->postResource = $postResource; $this->postFactory = $postFactory; $this->postCollectionFactory = $postCollectionFactory; $this->postSearchResultFactory = $postSearchResultFactory; } /** * @param int $id * @return PostInterface * @throws NoSuchEntityException */ public function get(int $id) { if (!array_key_exists($id, $this->registry)) { $post = $this->postFactory->create(); $this->postResource->load($post, $id); if (!$post->getId()) { throw new NoSuchEntityException(__('Requested post does not exist')); } $this->registry[$id] = $post; } return $this->registry[$id]; } /** * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria * @return \AlexPoletaev\Blog\Api\Data\PostSearchResultInterface */ public function getList(SearchCriteriaInterface $searchCriteria) { /** @var PostCollection $collection */ $collection = $this->postCollectionFactory->create(); foreach ($searchCriteria->getFilterGroups() as $filterGroup) { foreach ($filterGroup->getFilters() as $filter) { $condition = $filter->getConditionType() ? $filter->getConditionType() : 'eq'; $collection->addFieldToFilter($filter->getField(), [$condition => $filter->getValue()]); } } /** @var PostSearchResultInterface $searchResult */ $searchResult = $this->postSearchResultFactory->create(); $searchResult->setSearchCriteria($searchCriteria); $searchResult->setItems($collection->getItems()); $searchResult->setTotalCount($collection->getSize()); return $searchResult; } /** * @param \AlexPoletaev\Blog\Api\Data\PostInterface $post * @return PostInterface * @throws StateException */ public function save(PostInterface $post) { try { /** @var Post $post */ $this->postResource->save($post); $this->registry[$post->getId()] = $this->get($post->getId()); } catch (\Exception $exception) { throw new StateException(__('Unable to save post #%1', $post->getId())); } return $this->registry[$post->getId()]; } /** * @param \AlexPoletaev\Blog\Api\Data\PostInterface $post * @return bool * @throws StateException */ public function delete(PostInterface $post) { try { /** @var Post $post */ $this->postResource->delete($post); unset($this->registry[$post->getId()]); } catch (\Exception $e) { throw new StateException(__('Unable to remove post #%1', $post->getId())); } return true; } /** * @param int $id * @return bool */ public function deleteById(int $id) { return $this->delete($this->get($id)); } } 


方法\AlexPoletaev\Blog\Model\PostRepository::getList()应该返回某种格式的数据,因此我们还将需要此接口:

AlexPoletaev /博客/ Api /数据/ PostSearchResultInterface.php
 <?php namespace AlexPoletaev\Blog\Api\Data; use Magento\Framework\Api\SearchResultsInterface; /** * Interface PostSearchResultInterface * @package AlexPoletaev\Blog\Api\Data */ interface PostSearchResultInterface extends SearchResultsInterface { /** * @return \AlexPoletaev\Blog\Api\Data\PostInterface[] */ public function getItems(); /** * @param \AlexPoletaev\Blog\Api\Data\PostInterface[] $items * @return $this */ public function setItems(array $items); } 


为了使测试模块更容易,我们将创建两个控制台脚本,这些脚本可在表中添加和删除测试数据:

AlexPoletaev /博客/控制台/命令/ DeploySampleDataCommand.php
 <?php namespace AlexPoletaev\Blog\Console\Command; use AlexPoletaev\Blog\Api\PostRepositoryInterface; use AlexPoletaev\Blog\Model\Post; use AlexPoletaev\Blog\Model\PostFactory; use Magento\User\Api\Data\UserInterface; use Magento\User\Model\User; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * Class DeploySampleDataCommand * @package AlexPoletaev\Blog\Console\Command */ class DeploySampleDataCommand extends Command { /**#@+ * @var string */ const ARGUMENT_USERNAME = 'username'; const ARGUMENT_NUMBER_OF_RECORDS = 'number_of_records'; /**#@-*/ /** * @var PostFactory */ private $postFactory; /** * @var PostRepositoryInterface */ private $postRepository; /** * @var UserInterface */ private $user; /** * @param PostFactory $postFactory * @param PostRepositoryInterface $postRepository * @param UserInterface $user */ public function __construct( PostFactory $postFactory, PostRepositoryInterface $postRepository, UserInterface $user ) { parent::__construct(); $this->postFactory = $postFactory; $this->postRepository = $postRepository; $this->user = $user; } /** * @inheritdoc */ protected function configure() { $this->setName('alex_poletaev:blog:deploy_sample_data') ->setDescription('Blog: deploy sample data') ->setDefinition([ new InputArgument( self::ARGUMENT_USERNAME, InputArgument::REQUIRED, 'Username' ), new InputArgument( self::ARGUMENT_NUMBER_OF_RECORDS, InputArgument::OPTIONAL, 'Number of test records' ), ]) ; parent::configure(); } /** * @inheritdoc */ protected function execute(InputInterface $input, OutputInterface $output) { $username = $input->getArgument(self::ARGUMENT_USERNAME); /** @var User $user */ $user = $this->user->loadByUsername($username); if (!$user->getId() && $output->getVerbosity() > 1) { $output->writeln('<error>User is not found</error>'); return null; } $records = $input->getArgument(self::ARGUMENT_NUMBER_OF_RECORDS) ?: 3; for ($i = 1; $i <= (int)$records; $i++) { /** @var Post $post */ $post = $this->postFactory->create(); $post->setAuthorId($user->getId()); $post->setTitle('test title ' . $i); $post->setContent('test content ' . $i); $this->postRepository->save($post); if ($output->getVerbosity() > 1) { $output->writeln('<info>Post with the ID #' . $post->getId() . ' has been created.</info>'); } } } } 


AlexPoletaev /博客/控制台/命令/ RemoveSampleDataCommand.php
 <?php namespace AlexPoletaev\Blog\Console\Command; use AlexPoletaev\Blog\Model\ResourceModel\Post as PostResource; use Magento\Framework\App\ResourceConnection; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * Class RemoveSampleDataCommand * @package AlexPoletaev\Blog\Console\Command */ class RemoveSampleDataCommand extends Command { /** * @var ResourceConnection */ private $resourceConnection; /** * @param ResourceConnection $resourceConnection */ public function __construct( ResourceConnection $resourceConnection ) { parent::__construct(); $this->resourceConnection = $resourceConnection; } /** * @inheritdoc */ protected function configure() { $this->setName('alex_poletaev:blog:remove_sample_data') ->setDescription('Blog: remove sample data') ; parent::configure(); } /** * @inheritdoc */ protected function execute(InputInterface $input, OutputInterface $output) { $connection = $this->resourceConnection->getConnection(); $connection->truncateTable($connection->getTableName(PostResource::TABLE_NAME)); if ($output->getVerbosity() > 1) { $output->writeln('<info>Sample data has been successfully removed.</info>'); } } } 


Magento 2的主要特征是其依赖注入实现的广泛使用。 为了使Magenta知道实现对应的接口,我们需要在di.xml文件中指定这些依赖项。 同时,我们将在此文件中注册新创建的控制台脚本:

AlexPoletaev /博客/ etc / di.xml
 <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <preference for="AlexPoletaev\Blog\Api\Data\PostInterface" type="AlexPoletaev\Blog\Model\Post"/> <preference for="AlexPoletaev\Blog\Api\PostRepositoryInterface" type="AlexPoletaev\Blog\Model\PostRepository"/> <preference for="AlexPoletaev\Blog\Api\Data\PostSearchResultInterface" type="Magento\Framework\Api\SearchResults" /> <type name="Magento\Framework\Console\CommandList"> <arguments> <argument name="commands" xsi:type="array"> <item name="deploy_sample_data" xsi:type="object">AlexPoletaev\Blog\Console\Command\DeploySampleDataCommand</item> <item name="remove_sample_data" xsi:type="object">AlexPoletaev\Blog\Console\Command\RemoveSampleDataCommand</item> </argument> </arguments> </type> </config> 


现在注册REST API的路由,这在webapi.xml文件中完成:

AlexPoletaev /博客/ etc / webapi.xml
 <?xml version="1.0"?> <routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd"> <route url="/V1/blog/posts" method="POST"> <service class="AlexPoletaev\Blog\Api\PostRepositoryInterface" method="save"/> <resources> <resource ref="anonymous"/> </resources> </route> <route url="/V1/blog/posts/:id" method="DELETE"> <service class="AlexPoletaev\Blog\Api\PostRepositoryInterface" method="deleteById"/> <resources> <resource ref="anonymous"/> </resources> </route> <route url="/V1/blog/posts/:id" method="GET"> <service class="AlexPoletaev\Blog\Api\PostRepositoryInterface" method="get"/> <resources> <resource ref="anonymous"/> </resources> </route> <route url="/V1/blog/posts" method="GET"> <service class="AlexPoletaev\Blog\Api\PostRepositoryInterface" method="getList"/> <resources> <resource ref="anonymous"/> </resources> </route> </routes> 


在这里,我们告诉Magente在请求特定的URL和特定的http方法(POST,GET等)时使用哪个接口和该接口中的哪个方法。 另外,为简化起见,使用了anonymous资源,这绝对允许任何人敲我们的API,否则您需要配置访问权限(ACL)。

高潮


所有其他步骤均假定您启用了开发人员模式。 这样可以避免在部署内容静态和DI编译时进行不必要的操作。

注册我们的新模块,运行命令: php bin/magento setup:upgrade

检查是否已创建新的alex_poletaev_blog_post表。

接下来,使用我们的自定义脚本加载测试数据:

 php bin/magento -v alex_poletaev:blog:deploy_sample_data admin 

此脚本中的admin参数是admin_user表中的用户名 (可能与您不同),也就是ad​​min面板中的用户,该用户名将写在author_id列中。

现在您可以开始测试了。 为了进行测试,我使用了Magento 2.2.4,域为http://m224ce.local/

测试REST API的一种方法是打开http://m224ce.local/swagger并使用swagger功能,但请记住, getList方法无法在其中正常工作。 我还用curl测试了所有方法,例如:

获取ID = 2的文章

 curl -X GET -H "Accept: application/json" "http://m224ce.local/rest/all/V1/blog/posts/2" 

答案是:

 {"id":2,"author_id":1,"title":"test title 2","content":"test content 2","created_at":"2018-06-06 21:35:54","updated_at":"2018-06-06 21:35:54"} 

获取author_id = 2的文章列表

 curl -g -X GET -H "Accept: application/json" "http://m224ce.local/rest/all/V1/blog/posts?searchCriteria[filterGroups][0][filters][0][field]=author_id&searchCriteria[filterGroups][0][filters][0][value]=1&searchCriteria[filterGroups][0][filters][0][conditionType]=eq" 

答案是:

 {"items":[{"id":1,"author_id":1,"title":"test title 1","content":"test content 1","created_at":"2018-06-06 21:35:54","updated_at":"2018-06-06 21:35:54"},{"id":2,"author_id":1,"title":"test title 2","content":"test content 2","created_at":"2018-06-06 21:35:54","updated_at":"2018-06-06 21:35:54"},{"id":3,"author_id":1,"title":"test title 3","content":"test content 3","created_at":"2018-06-06 21:35:54","updated_at":"2018-06-06 21:35:54"}],"search_criteria":{"filter_groups":[{"filters":[{"field":"author_id","value":"1","condition_type":"eq"}]}]},"total_count":3} 

删除ID = 3的文章

 curl -X DELETE -H "Accept: application/json" "http://m224ce.local/rest/all/V1/blog/posts/3" 

答案是:

 true 

保存新文章

 curl -X POST -H "Content-Type: application/json" -H "Accept: application/json" -d '{"post": {"author_id": 1, "title": "test title 4", "content": "test content 4"}}' "http://m224ce.local/rest/all/V1/blog/posts" 

答案是:

 {"id":4,"author_id":1,"title":"test title 4","content":"test content 4","created_at":"2018-06-06 21:44:24","updated_at":"2018-06-06 21:44:24"} 

请注意,对于带有http POST方法的请求,必须传递post键,该键实际上对应于该方法的输入参数($ post)

 \AlexPoletaev\Blog\Api\PostRepositoryInterface::save() 

结局


对于那些对请求过程中发生的事情以及Magenta如何处理请求感兴趣的人,下面我将在注释中提供一些方法链接。 如果某些方法不起作用,则必须首先从这些方法中扣除。

负责处理请求的控制器
\ Magento \ Webapi \控制器\ Rest ::派遣()

下一个叫
\ Magento \ Webapi \ Controller \ Rest :: processApiRequest()

processApiRequest内部调用了许多其他方法,但第二个最重要的方法
\ Magento \ Webapi \控制器\休息\ InputParamsResolver :: resolve()

\ Magento \ Webapi \控制器\ Rest \路由器:: match() -确定特定的路由(在内部,通过\Magento\Webapi\Model\Rest\Config::getRestRoutes()方法,所有合适的路由均从请求中被拉出)。 路由对象包含处理请求的所有必要数据-类,方法,访问权限等。

\ Magento \ Framework \ Webapi \ ServiceInputProcessor ::进程()
-使用\Magento\Framework\Reflection\MethodsMap::getMethodParams() ,其中方法参数通过反射获取

\ Magento \ Framework \ Webapi \ ServiceInputProcessor :: convertValue() -用于将数组转换为DataObject或从DataObject转换为数组的几个选项

\ Magento \ Framework \ Webapi \ ServiceInputProcessor :: _ createFromArray() -直接转换,通过反射检查getter和setter的存在(记住,我在上面说过,我们将返回到它们吗?)并且它们具有公共作用域。 接下来,通过设置器将数据填充到对象中。

在方法的最后
\ Magento \ Webapi \ Controller \ Rest :: processApiRequest() ,通过call_user_func_array调用存储库对象call_user_func_array方法。

结语


Github模块存储库

有两种安装方法:

1)通过作曲家。 为此,请将以下对象添加到composer.json文件中的repositories数组中

 { "type": "git", "url": "https://github.com/alexpoletaev/magento2-blog-demo" } 

然后在终端中键入以下命令:

 composer require alexpoletaev/magento2-blog-demo:dev-master 

2)下载模块文件,然后手动将其复制到app/code/AlexPoletaev/Blog目录中

无论选择哪种方法,最后都需要运行升级:

 php bin/magento setup:upgrade 

我希望本文对某人有用。 如果您有任何意见,建议或问题,请发表评论。 谢谢您的关注。

Source: https://habr.com/ru/post/zh-CN413463/


All Articles