Frage

Let's say I want to load a order item in a controller. I can use:

$order = $this->_objectManager->create('Magento\Sales\Model\Order\item')->load($id);

I see this happening in a lot of free and commercial modules. Even do everywhere on the forums they say Object manager is discouraged. Should I still use a service contract, even do the code is much more complex?

<?php namespace Xxx\xxx\Helper;

class GetOrderItemById
{
  private $orderRepository;
  private $searchCriteriaBuilder;

  public function __construct(
    \Magento\Framework\App\Helper\Context $context,
    \Magento\Sales\Model\Order\ItemRepository $orderRepository,
    \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
  ){
    $this->orderRepository = $orderRepository;
    $this->searchCriteriaBuilder = $searchCriteriaBuilder;
  }

  function getOrderItem($id)
  {
    $searchCriteria = $this->searchCriteriaBuilder
      ->addFilter('id', $id, 'eq')->create();
    $orderItem = $this->orderRepository->getList($searchCriteria)->getItems();
  }
}

EDIT: I have edited my controller class:

<?php namespace Xxx\Xxx\Controller\Adminhtml\Save;

use Magento\Framework\Controller\ResultFactory;

class Index extends \Magento\Backend\App\Action
{
    private $orderRepository;
    private $searchCriteriaBuilder;

    public function __construct(
      \Magento\Sales\Model\Order\ItemRepository $orderRepository,
      \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
    ){
      $this->orderRepository = $orderRepository;
      $this->searchCriteriaBuilder = $searchCriteriaBuilder;
    }

    public function execute()
    {
      $post = $this->getRequest()->getPostValue();
      if (isset($post)) {

        $searchCriteria = $this->searchCriteriaBuilder
          ->addFilter('quote_item_id', $post['quote_item_id'], 'eq')->create();
        $orderItem = $this->orderRepository->getList($searchCriteria)->getItems();

        foreach ($orderItem as $item) {
          $return['item_id'] = ($item->getParentItemId() != NULL ? $item->getParentItemId() : $item->getId());
          $return['order_id'] = $item->getOrderId();
          var_dump($return);
        }
    }
}

It returns:

2018/08/05 19:03:39 [error] 19724#19724: *775254 FastCGI sent in stderr: "PHP message: PHP Fatal error:  Uncaught TypeError: Argument 1 passed to Qxs\SerialCode\Controller\Adminhtml\Save\Index::__construct() must be an instance of Magento\Sales\Model\Order\ItemRepository, instance of Magento\Backend\App\Action\Context given, called in /data/web/magento2_staging/generated/code/Qxs/SerialCode/Controller/Adminhtml/Save/Index/Interceptor.php on line 14 and defined in /data/web/magento2_staging/app/code/Qxs/SerialCode/Controller/Adminhtml/Save/Index.php:10
War es hilfreich?

Lösung

Your class should look a little more like this, assuming that the $id variable represents an order item ID:

namespace Xxx\xxx\Helper;

class GetOrderItemById
{
    /**
     * @var \Magento\Sales\Api\OrderItemRepositoryInterface
     */
    private $orderItemRepository;

    /**
     * GetOrderItemById constructor.
     *
     * @param \Magento\Sales\Api\OrderItemRepositoryInterface $orderItemRepository
     */
    public function __construct(
        \Magento\Sales\Api\OrderItemRepositoryInterface $orderItemRepository
    ){
        $this->orderItemRepository   = $orderItemRepository;
    }

    /**
     * @param int $id
     *
     * @return \Magento\Sales\Api\Data\OrderItemInterface
     */
    public function getOrderItem($id)
    {
        return $this->orderItemRepository->get($id);
    }
}

You should be passing the OrderItemRepositoryInterface into your constructor instead of a reference to the concrete class.

You are correct that the usage of the object manager is discouraged. I still have not found a single instance where it's necessary to use it. Additionally, the ->load() method is deprecated. In order to guarantee that your code will continue to work, it is best to use methods declared in the interfaces.

Also, your Context constructor argument is never used and I also don't see that you extend any class so it is likely to be unnecessary.

Additionally, you should declare proper visibility on functions within your class.


In response to your updated question, what happened is that you updated the controller but the auto-generated class that lives in generated/code wasn't updated. Simply delete the generated/code directory and that issue should go away.

A few things about your constructor.

  • You should not pass in the concrete class \Magento\Sales\Model\Order\ItemRepository. Instead, you should replace that with \Magento\Sales\Api\OrderItemRepositoryInterface. You will still get the same class. By type-hinting the interface instead of the class name, you will receive the highest priority version of the interface, just in case it ever gets changed by you or some third party module.
  • $orderRepository would be more appropriately named $orderItemRepository because that is in fact what you are invoking. The class your are injecting into your constructor is not an order repository.

In your execute function:

  • You never check to see if array key quote_item_id exists in $post and you never check to see if post is actually an array. Both can throw a fatal error. It would be more efficient and safer to do it the way I recommend in the code posted below.
  • Each order item is an instance of \Magento\Sales\Api\Data\OrderItemInterface. You should use only methods that exist on the interface to guarantee that your code won't break. I am referring more specifically to $item->getId(). That method does not exist in the interface. Instead, use $item->getItemId()

You can copy and paste this example and it should work perfectly as-is. Just be sure to delete the generated/code directory.

    <?php

    namespace Xxx\Xxx\Controller\Adminhtml\Save;

    use Magento\Sales\Api\Data\OrderItemInterface;
    use Magento\Sales\Api\OrderItemRepositoryInterface;
    use Magento\Framework\Api\SearchCriteriaBuilder;
    use Magento\Backend\App\Action\Context;

    class Index extends \Magento\Backend\App\Action
    {
        /**
         * @var OrderItemRepositoryInterface
         */
        private $orderItemRepository;

        /**
         * @var SearchCriteriaBuilder
         */
        private $searchCriteriaBuilder;

        /**
         * Index constructor.
         *
         * @param OrderItemRepositoryInterface $orderItemRepository
         * @param SearchCriteriaBuilder        $searchCriteriaBuilder
         * @param Context               $context
         */
        public function __construct(
            OrderItemRepositoryInterface $orderItemRepository,
            SearchCriteriaBuilder $searchCriteriaBuilder,
            Context $context
        ) {
            parent::__construct($context);

            $this->orderItemRepository   = $orderItemRepository;
            $this->searchCriteriaBuilder = $searchCriteriaBuilder;
        }

        public function execute()
        {
            $itemId = $this->getRequest()->getPostValue(
                OrderItemInterface::QUOTE_ITEM_ID
            );

            if ($itemId) {
                $searchCriteria = $this->searchCriteriaBuilder
                    ->addFilter(OrderItemInterface::QUOTE_ITEM_ID, $itemId, 'eq');
                $orderItem      = $this->orderItemRepository->getList(
                    $searchCriteria->create()
                )->getItems();

                /** @var OrderItemInterface $item */
                foreach ($orderItem as $item) {
                    $return['item_id']  = ($item->getParentItemId() != null ? $item->getParentItemId() : $item->getItemId());
                    $return['order_id'] = $item->getOrderId();
                    var_dump($return);
                }
            }
        }
    }

On another note, a helpful note that you'll thank me for ages, I see you are using var_dump. Your life will be not only easier, but you'll more quickly understand the Magento architecture if you start using xDebug instead. I have create a 7-part YouTube tutorial series on how to install and use it. xDebug + PhpStorm

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit magento.stackexchange
scroll top