0

Magento 2.2, developing a custom theme whose parent is Magento/blank.

I intend to create a module which generates a random discount weekly.

Firstly, I must retrieve a random product from a particular sub-category. This data will be utilised on the backend. I must then store its information for a week.

For now, though, I'm only looking for a way to create a model from the information.

There are various answers for Magento 1.x, utilising the rand() function, but I haven't discovered any clear description for Magento 2.

Here is the class, based on Thiago's answer:

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Magento\Framework\Console\Cli;

class CreateDiscount extends Command{

    protected $_productCollectionFactory;
    protected $_categoryFactory;

    public function __construct(
        \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
        \Magento\Catalog\Model\CategoryFactory $categoryFactory,
        \Magento\Framework\View\Element\Template\Context $context
    ) {
        $this->_categoryFactory = $categoryFactory;
        $this->_productCollectionFactory = $productCollectionFactory;
        parent::__construct($context);
    }

    /**
     * @var $categoryId
     */
    public function getRandomCategoryId() {
        $categoryId = rand(2, 4);
        settype($categoryId, "string");
        return $categoryId;
    }

    /**
     * @param int $categoryId
     */
    public function getRandomProduct($categoryId)
    {
        $products = $this->productRepository->getList($this->getProductSearchCriteria($categoryId));
        $randomId = array_rand($products->getItems(), 1);
        $productItems = $products->getItems();
        return $productItems[$randomId];
    }

    /**
     * @param $categoryId
     * @return \Magento\Framework\Api\SearchCriteria
     */
    private function getProductSearchCriteria($categoryId)
    {
        $searchCriteria = $this->searchCriteriaBuilder
            ->addFilter('category_id', $categoryId)
            ->create();
        return $searchCriteria;
    }

    public function randomProduct()
    {
        // Find a random product
        $product = $this->getRandomProduct($this->getRandomCategoryId());
        $sku = $product->getSku();
    }
}

2 Answers 2

4

The best approach (Good practice) is using Interfaces

/**
 * @param int $categoryId
 */
public function getRandomProduct(categoryId)
{
    $products = $this->productRepository->getList($this->getProductSearchCriteria($categoryId));
    $randomId = array_rand($products->getItems(), 1);
    $productItems = $products->getItems();
    return $productItems[$randomId];

}

/**
 * @param $categoryId
 * @return \Magento\Framework\Api\SearchCriteria
 */
private function getProductSearchCriteria($categoryId)
{
    $searchCriteria = $this->searchCriteriaBuilder
        ->addFilter('category_id', $categoryId)
        ->create();
    return $searchCriteria;
}

You should avoid using CollectionFactories and use the respective RepositoryInterface

For now, there is no way to sort items randonly check at Magento\Framework\Api\SortOrder

5
  • Thanks Thiago. I have attempted to implement your solution in my existing code, but my host's backend is down at the moment for some reason, so I can't test on my site. I've included your version, up to the point where I create the discount code. Could you let me know if I've understood properly please? Thanks!
    – Muckee
    Commented Feb 11, 2018 at 16:47
  • 2
    Seems to be fine. One thing is: you should never use $model->save(), $model->delete and so on. All those actions must be used through the properly interface. Take a look into Service Contracts Commented Feb 11, 2018 at 16:58
  • Thanks. Well I'll give you the green tick as you've answered my question, but now I'm even more confused. I've now included the entire class file in my question. I can see in the folder vendor/magento/module-sales-rule/Api/Data that there are various interfaces with all the commands I need, so I can guess that I'd essentially need to replace the statements which use rulefactory with ones using the functions from the interfaces, but I don't understand how to actually define and the rule that would utilise those functions, or how they would interact.
    – Muckee
    Commented Feb 12, 2018 at 11:55
  • I've removed all the unnecessary code from my question for clarity and added a new question. Do you think you'd be able to help? Thanks
    – Muckee
    Commented Feb 12, 2018 at 13:49
  • I will take a look. Commented Feb 12, 2018 at 14:10
2
protected $_productCollectionFactory;
protected $_categoryFactory;

public function __construct(
    \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
    \Magento\Catalog\Model\CategoryFactory $categoryFactory,
    \Magento\Framework\View\Element\Template\Context $context,
) {
    $this->_categoryFactory = $categoryFactory;
    $this->_productCollectionFactory = $productCollectionFactory;
    parent::__construct($context);
}

public function getProductCollection()
{
    $categoryId = 'yourcategoryid';
    $category = $this->_categoryFactory->create()->load($categoryId);
    $collection = $this->_productCollectionFactory->create();
    $collection->addAttributeToSelect('*');
    $collection->addCategoryFilter($category); // for your sub category
    $collection->addAttributeToFilter('visibility', \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH);
    $collection->addAttributeToFilter('status',\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED);
    $collection->getSelect()->orderRand(); // for random collection
    return $collection;
}

Hope this will help you to get random products from Sub category.

2
  • Just been doing a bit more reading. Here is another similar question: magento.stackexchange.com/questions/91997/… and, in the comments underneath the answer provided by Arvind07, people are saying that \Magento\Catalog\Model\ProductRepository should be used instead of productCollectionFactory. Can you clarify where this is relevant, or why it does not apply to this answer please? Thanks.
    – Muckee
    Commented Feb 8, 2018 at 10:04
  • 1
    @JoshuaFlood is a good practice use interfaces. Check my answer below Commented Feb 11, 2018 at 16:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.