Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding command to generate menu items from large category trees #13

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
243 changes: 243 additions & 0 deletions src/Console/Command/MenuGenerateCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
<?php
/**
* @category ScandiPWA
* @package ScandiPWA\MenuOrganizer
* @author Ivans Zuks <[email protected]>
* @copyright Copyright (c) 2019 Scandiweb, Ltd (http://scandiweb.com)
* Technodom_MenuOrganizer
*/
namespace ScandiPWA\MenuOrganizer\Console\Command;

use Exception;
use Magento\Catalog\Model\Category;
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory as CategoryCollectionFactory;
use Magento\Catalog\Model\ResourceModel\Category\Collection as CategoryCollection;
use Magento\Framework\DB\Adapter\AdapterInterface;
use ScandiPWA\MenuOrganizer\Model\ItemFactory;
use ScandiPWA\MenuOrganizer\Model\Menu;
use ScandiPWA\MenuOrganizer\Model\ResourceModel\Menu\CollectionFactory;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Class GenerateMenuCommand
*/
class MenuGenerateCommand extends Command
{
const COMMAND = 'scandipwa:menu:generate';
const COMMAND_DESCRIPTION = 'Generate menu items from categories';
const COMMAND_CUT_CATEGORIES = 'cut';
const COMMAND_MENU_NAME = 'name';
const COMMAND_MENU_ID = 'id';
const MAIN_TABLE = 'scandiweb_menumanager_item';

protected $menuConfig = [
'css_class' => 'Menu',
'is_active' => '1',
'store_id' => ['0']
];
protected $rootCategories = ['Root Catalog', 'Default Category'];
protected $ignoredCategories = [];
protected $ignoredCategoriesId = [];
protected $itemIds = [];

/**
* @var Menu
*/
protected $menu;

/**
* @var CollectionFactory
*/
protected $menuCollectionFactory;

/**
* @var CategoryCollectionFactory
*/
protected $categoryCollectionFactory;

/**
* @var ItemFactory
*/
protected $itemFactory;

/**
* @inheritDoc
*/
protected function configure()
{
$this->setName(self::COMMAND)
->setDescription(self::COMMAND_DESCRIPTION)
->addOption(
self::COMMAND_MENU_NAME,
null,
InputOption::VALUE_OPTIONAL,
__('Menu Name'),
'Main Menu'
)
->addOption(
self::COMMAND_MENU_ID,
null,
InputOption::VALUE_OPTIONAL,
__('Menu identifier'),
'main-menu'
)
->addOption(
self::COMMAND_CUT_CATEGORIES,
null,
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
__('Categories to not use in menu'),
[]
);
parent::configure();
}

/**
* MenuGenerateCommand constructor.
* @param CategoryCollectionFactory $categoryCollectionFactory
* @param Menu $menu
* @param ItemFactory $itemFactory
* @param CollectionFactory $menuCollectionFactory
* @param string|null $name
*/
public function __construct(
CategoryCollectionFactory $categoryCollectionFactory,
Menu $menu,
ItemFactory $itemFactory,
CollectionFactory $menuCollectionFactory,
string $name = null
) {
parent::__construct($name);
$this->menu = $menu;
$this->menuCollectionFactory = $menuCollectionFactory;
$this->categoryCollectionFactory = $categoryCollectionFactory;
$this->itemFactory = $itemFactory;
}

/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return void
* @throws Exception
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->ignoredCategories = $input->getOption(self::COMMAND_CUT_CATEGORIES);
$this->menuConfig['title'] = $input->getOption(self::COMMAND_MENU_NAME);
$this->menuConfig['identifier'] = $input->getOption(self::COMMAND_MENU_ID);
/** @var CategoryCollection $categoriesCollection */
$categoriesCollection = $this->categoryCollectionFactory->create();
$categoriesCollection->addAttributeToSelect('name');
$categoriesCollection->addAttributeToSelect('url_path');

$this->createMenu();
$this->removeAutogeneratedItems();

/** @var Category $category */
foreach ($categoriesCollection as $category) {
$this->createMenuItem($category);
}

$output->writeln('<info>Success</info>');
}

/**
* Create new Menu
*
* @throws Exception
*/
public function createMenu()
{
$id = $this->menuCollectionFactory->create()
->addFieldToFilter('identifier', $this->menuConfig['identifier'])
->getFirstItem()
->getId();
if ($id) {
$this->menu->load($id);
}
$this->menu->addData($this->menuConfig);
$this->menu->save();
}

/**
* Delete autogenerated menu items before creating new
*/
public function removeAutogeneratedItems()
{
$itemModel = $this->itemFactory->create();
$modelResource = $itemModel->getResource();

/** @var AdapterInterface $connection */
$connection = $modelResource->getConnection();
$connection->delete(
self::MAIN_TABLE,
['menu_id = ?' => $this->menu->getId()]
);
}

/**
* Get menu item parent category id
*
* @param $category
* @return mixed
*/
public function getParentId(Category $category)
{
if (!isset($this->itemIds[$category->getParentId()])) {
return '0';
}

return $this->itemIds[$category->getParentId()];
}

/**
* Create menu item
*
* @param $category
* @throws Exception
*/
public function createMenuItem($category)
{
if (!$this->isCategoryAvailable($category)) {
return;
}

$data = [
'menu_id' => $this->menu->getId(),
'title' => $category->getName(),
'url_type' => '0',
'url' => '/' . $category->getUrlPath(),
'category_id' => $category->getId(),
'parent_id' => $this->getParentId($category),
'is_active' => '1'
];
$item = $this->itemFactory->create();
$item->addData($data)->save();
$this->itemIds[$category->getId()] = $item->getId();
}

/**
* Check isn't category cut
*
* @param $category
* @return bool
*/
public function isCategoryAvailable($category)
{
if (in_array($category->getName(), $this->rootCategories) || $category->getLevel() > 4) {
return false;
}

if (in_array($category->getName(), $this->ignoredCategories)
|| in_array($category->getParentId(), $this->ignoredCategoriesId)
) {
$this->ignoredCategoriesId[] = $category->getId();
return false;
}

return true;
}
}
8 changes: 8 additions & 0 deletions src/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@
type="ScandiPWA\MenuOrganizer\Block\Renderer\Action"
/>

<type name="Magento\Framework\Console\CommandList">
<arguments>
<argument name="commands" xsi:type="array">
<item name="menu_generate" xsi:type="object">ScandiPWA\MenuOrganizer\Console\Command\MenuGenerateCommand</item>
</argument>
</arguments>
</type>

<virtualType name="MenuGridFilterPool" type="Magento\Framework\View\Element\UiComponent\DataProvider\FilterPool">
<arguments>
<argument name="appliers" xsi:type="array">
Expand Down