Magento 2 REST API باستخدام وحدة بسيطة كمثال

أرحب بكم يا حبيبي الحب! نظرًا لأنني أقوم بالتطوير على منصة Magento للتجارة الإلكترونية منذ عام 2013 ، بعد أن جمعت شجاعتي واعتقدت أنه في هذا المجال يمكنني أن أسمي نفسي ، على الأقل ، مطورًا واثقًا ، قررت كتابة مقالتي الأولى على المحور حول هذا النظام. وسأبدأ بتنفيذ واجهة برمجة التطبيقات REST API في Magento 2. هنا ، من خارج الصندوق هناك وظائف لمعالجة الطلبات وسأحاول شرحها باستخدام مثال على وحدة بسيطة. هذه المقالة مخصصة أكثر لأولئك الذين عملوا بالفعل مع Magenta. وهكذا ، من المهتمين ، من فضلك ، تحت القط.

تعادل


مخيلتي سيئة للغاية ، لذلك توصلت إلى المثال التالي: تخيل أننا بحاجة إلى تنفيذ مدونة ، يمكن فقط للمستخدمين من لوحة المشرف كتابة المقالات. من وقت لآخر ، يدق علينا نوع من إدارة علاقات العملاء ويحمل هذه المقالات على نفسه (لماذا لا يكون واضحًا ، ولكن هذه هي الطريقة التي سنبرر بها استخدام REST API). لتبسيط الوحدة ، حذفت على وجه التحديد تنفيذ عرض المقالات على الواجهة الأمامية وفي لوحة المشرف (يمكنك تنفيذها بنفسك ، أوصي بمقالة جيدة عن الشبكات). سوف تتأثر فقط وظيفة معالجة الاستعلام هنا.

تطوير العمل


أولاً ، قم بإنشاء بنية الوحدة النمطية ، دعنا نسميها AlexPoletaev_Blog (لم يزول نقص الخيال). نضع الوحدة في دليل التطبيق / الرمز .

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 / مدونة / register.php
 <?php \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, 'AlexPoletaev_Blog', __DIR__ ); 


هذان الملفان هما الحد الأدنى المطلوب للوحدة النمطية.

إذا تم كل شيء في Feng Shui ، فنحن بحاجة إلى إنشاء عقود خدمة (ما هو داخل Magenta وكيف يعمل ، يمكنك القراءة هنا وهنا ) ، والذي سنفعله:

AlexPoletaev / المدونة / Api / Data / 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 جدولًا بمقالات من مدونتنا. قم بإنشاء جدول أدناه. يجب أن يكون لكل عمود من قاعدة البيانات مُحضر ومُحضر خاص به في هذه الواجهة ، وسنكتشف سبب أهمية ذلك لاحقًا. توفر واجهة PostRepositoryInterface مجموعة قياسية من الطرق للتفاعل مع قاعدة البيانات وتخزين الكيانات المحملة في ذاكرة التخزين المؤقت. يتم استخدام نفس الأساليب لواجهة برمجة التطبيقات. ملاحظة مهمة أخرى ، يلزم وجود 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 - معرف مستخدم المشرف (مفتاح خارجي في حقل user_id من جدول admin_user)
  • العنوان - العنوان
  • المحتوى - نص المقالة
  • create_at - تاريخ الانشاء
  • updated_at - تعديل التاريخ

تحتاج الآن إلى إنشاء مجموعة قياسية من فئات Magenta Model و ResourceModel و Collection . لماذا لن أرسم هذه الفئات ، هذا الموضوع واسع ويتجاوز نطاق هذه المقالة ، المهتمين ، يمكنه البحث عن Google بمفرده. باختصار ، هذه الفئات مطلوبة للتعامل مع الكيانات (المقالات) من قاعدة البيانات. أنصحك بالقراءة عن أنماط نموذج المستودع وأنماط طبقة الخدمة.

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); } } 


سيلاحظ القارئ اليقظ أن نموذجنا يطبق الواجهة التي تم إنشاؤها سابقًا وجميع المراسلات والمستوطنين.

في نفس الوقت ننفذ المستودع وطرقه:

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 / Data / 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 / Blog / Console / Command / 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 / Blog / Console / Command / 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 / Blog / 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 ، ويتم ذلك في ملف 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 ، مما يسمح لأي شخص بالطرق على واجهة برمجة التطبيقات الخاصة بنا ، وإلا فإنك تحتاج إلى تكوين حقوق الوصول (ACLs).

ذروة


تفترض جميع الخطوات الإضافية أنك مكّنت وضع المطور. هذا يتجنب التلاعبات غير الضرورية مع نشر إحصائيات المحتوى وتجميع DI.

سجل وحدتنا الجديدة ، قم بتشغيل الأمر: إعداد php bin/magento setup:upgrade .

تحقق من أنه تم إنشاء جدول alex_poletaev_blog_post جديد.

بعد ذلك ، قم بتحميل بيانات الاختبار باستخدام برنامجنا النصي المخصص:

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

معلمة المشرف في هذا البرنامج النصي هي اسم المستخدم من جدول admin_user (قد يختلف بالنسبة لك) ، في كلمة واحدة ، المستخدم من لوحة المشرف ، والتي ستتم كتابتها في عمود author_id.

الآن يمكنك البدء في الاختبار. للاختبارات ، استخدمت Magento 2.2.4 ، المجال http://m224ce.local/ .

تتمثل إحدى طرق اختبار REST API في فتح http://m224ce.local/swagger واستخدام وظيفة getList ، ولكن تذكر أن طريقة getList لا تعمل هناك بشكل صحيح. لقد اختبرت أيضًا جميع الطرق باستخدام حليقة ، أمثلة:

احصل على مقال بالمعرف = 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} 

حذف مقال بالمعرف = 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) للطريقة

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

الخاتمة


بالنسبة لأولئك المهتمين بما يحدث أثناء الطلب وكيف تعالجه Magenta ، سأقدم أدناه بعض الروابط إلى الأساليب مع تعليقاتي. إذا لم ينجح شيء ما ، فيجب خصم هذه الطرق أولاً.

المراقب المسؤول عن معالجة الطلب
\ Magento \ Webapi \ Controller \ Rest :: dispatch ()

دعا المقبل
\ Magento \ Webapi \ Controller \ Rest :: processApiRequest ()

تسمى العديد من الطرق الأخرى داخل processApiRequest ، ولكن الطريقة التالية هي الأهم
\ Magento \ Webapi \ Controller \ Rest \ InputParamsResolver :: Resolution ()

\ Magento \ Webapi \ Controller \ Rest \ Router :: match () - يتم تحديد مسار معين (من خلال طريقة \Magento\Webapi\Model\Rest\Config::getRestRoutes() ، يتم سحب جميع المسارات المناسبة من الطلب من الطلب). يحتوي كائن المسار على جميع البيانات اللازمة لمعالجة الطلب - الفئة ، الطريقة ، حقوق الوصول ، إلخ.

\ Magento \ Framework \ Webapi \ ServiceInputProcessor :: process ()
- يستخدم \Magento\Framework\Reflection\MethodsMap::getMethodParams() ، حيث يتم سحب معلمات الطريقة من خلال الانعكاس

\ Magento \ Framework \ Webapi \ ServiceInputProcessor :: convertValue () - العديد من الخيارات لتحويل صفيف إلى DataObject أو إلى صفيف من DataObject

\ Magento \ Framework \ Webapi \ ServiceInputProcessor :: _ createFromArray () - التحويل المباشر ، حيث يتم التحقق من وجود انعكاس وجود الرسائل والمستوطنين ( تذكر ، قلت أعلاه أننا سنعود إليهم؟) وأن لديهم نطاقًا عامًا. بعد ذلك ، يمتلئ الكائن بالبيانات من خلال المستوطنين.

في النهاية ، في الطريقة
\ Magento \ Webapi \ Controller \ Rest :: processApiRequest () ، من خلال call_user_func_array أسلوب كائن المستودع.

الخاتمة


مستودع وحدة جيثب

هناك طريقتان للتثبيت:

1) عبر الملحن. للقيام بذلك ، قم باضافة العنصر التالي الى مصفوفة repositories في ملف composer.json

 { "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/ar413463/


All Articles