Tambahkan pohon Kategori di ekstensi khusus


Jawaban:


27

Persiapkan diri Anda, ini akan lama. Ini dia.
Anda membutuhkan file-file berikut:

app/code/local/[Namespace]/[Module]/Block/Adminhtml/[Entity]/Edit/Tab/Categories.php - tab yang akan menyajikan kategori.

<?php
class [Namespace]_[Module]_Block_Adminhtml_[Entity]_Edit_Tab_Categories
    extends Mage_Adminhtml_Block_Catalog_Category_Tree {
    protected $_categoryIds = null;
    protected $_selectedNodes = null;
    public function __construct() {
        parent::__construct();
        $this->setTemplate('[namespace]_module/[entity]/edit/tab/categories.phtml');
        $this->_withProductCount = false;
    }
    public function get[Entity](){
        return Mage::registry('current_[entity]'); //use other registration key if you have one
    }

    public function getCategoryIds(){
        if (is_null($this->_categoryIds)){
            $categories = $this->get[Entity]()->getSelectedCategories();
                $ids = array();
                foreach ($categories as $category){
                    $ids[] = $category->getId();
                }
                $this->_categoryIds = $ids;
        }
        return $this->_categoryIds;
    }
    public function getIdsString(){
        return implode(',', $this->getCategoryIds());
    }
    public function getRootNode(){
        $root = $this->getRoot();
        if ($root && in_array($root->getId(), $this->getCategoryIds())) {
            $root->setChecked(true);
        }
        return $root;
    }

    public function getRoot($parentNodeCategory = null, $recursionLevel = 3){
        if (!is_null($parentNodeCategory) && $parentNodeCategory->getId()) {
            return $this->getNode($parentNodeCategory, $recursionLevel);
        }
        $root = Mage::registry('category_root');
        if (is_null($root)) {
            $rootId = Mage_Catalog_Model_Category::TREE_ROOT_ID;
            $ids = $this->getSelectedCategoryPathIds($rootId);
            $tree = Mage::getResourceSingleton('catalog/category_tree')
                ->loadByIds($ids, false, false);
            if ($this->getCategory()) {
                $tree->loadEnsuredNodes($this->getCategory(), $tree->getNodeById($rootId));
            }
            $tree->addCollectionData($this->getCategoryCollection());
            $root = $tree->getNodeById($rootId);
            Mage::register('category_root', $root);
        }
        return $root;
    }
    protected function _getNodeJson($node, $level = 1){
        $item = parent::_getNodeJson($node, $level);
        if ($this->_isParentSelectedCategory($node)) {
            $item['expanded'] = true;
        }
        if (in_array($node->getId(), $this->getCategoryIds())) {
            $item['checked'] = true;
        }
        return $item;
    }
    protected function _isParentSelectedCategory($node){
        $result = false;
        // Contains string with all category IDs of children (not exactly direct) of the node
        $allChildren = $node->getAllChildren();
        if ($allChildren) {
            $selectedCategoryIds = $this->getCategoryIds();
            $allChildrenArr = explode(',', $allChildren);
            for ($i = 0, $cnt = count($selectedCategoryIds); $i < $cnt; $i++) {
                $isSelf = $node->getId() == $selectedCategoryIds[$i];
                if (!$isSelf && in_array($selectedCategoryIds[$i], $allChildrenArr)) {
                    $result = true;
                    break;
                }
            }
        }
        return $result;
    }
    protected function _getSelectedNodes(){
        if ($this->_selectedNodes === null) {
            $this->_selectedNodes = array();
            $root = $this->getRoot();
            foreach ($this->getCategoryIds() as $categoryId) {
                if ($root) {
                    $this->_selectedNodes[] = $root->getTree()->getNodeById($categoryId);
                }
            }
        }
        return $this->_selectedNodes;
    }

    public function getCategoryChildrenJson($categoryId){
        $category = Mage::getModel('catalog/category')->load($categoryId);
        $node = $this->getRoot($category, 1)->getTree()->getNodeById($categoryId);
        if (!$node || !$node->hasChildren()) {
            return '[]';
        }
        $children = array();
        foreach ($node->getChildren() as $child) {
            $children[] = $this->_getNodeJson($child);
        }
        return Mage::helper('core')->jsonEncode($children);
    }
    public function getLoadTreeUrl($expanded = null){
        return $this->getUrl('*/*/categoriesJson', array('_current' => true));
    }
    public function getSelectedCategoryPathIds($rootId = false){
        $ids = array();
        $categoryIds = $this->getCategoryIds();
        if (empty($categoryIds)) {
            return array();
        }
        $collection = Mage::getResourceModel('catalog/category_collection');
        if ($rootId) {
            $collection->addFieldToFilter('parent_id', $rootId);
        }
        else {
            $collection->addFieldToFilter('entity_id', array('in'=>$categoryIds));
        }

        foreach ($collection as $item) {
            if ($rootId && !in_array($rootId, $item->getPathIds())) {
                continue;
            }
            foreach ($item->getPathIds() as $id) {
                if (!in_array($id, $ids)) {
                    $ids[] = $id;
                }
            }
        }
        return $ids;
    }
}

app/design/adminhtml/default/default/[namespace]_[module]/[entity]/tab/edit/categories.phtml - templat yang diperlukan untuk membuat kategori

<div class="entry-edit">
    <div class="entry-edit-head">
        <h4 class="icon-head head-edit-form fieldset-legend">
            <?php echo Mage::helper('[module]')->__('Categories') ?>
        </h4>
    </div>
    <fieldset id="grop_fields">
        <input type="hidden" name="category_ids" id="[entity]_categories" value="<?php echo $this->getIdsString() ?>">
        <div id="[entity]-categories" class="tree"></div>
    </fieldset>
</div>
<?php if($this->getRootNode() && $this->getRootNode()->hasChildren()): ?>
<script type="text/javascript">
    Ext.EventManager.onDocumentReady(function() {
        var categoryLoader = new Ext.tree.TreeLoader({
           dataUrl: '<?php echo $this->getLoadTreeUrl()?>'
        });
        categoryLoader.createNode = function(config) {
            config.uiProvider = Ext.tree.CheckboxNodeUI;
            var node;
            if (config.children && !config.children.length) {
                delete(config.children);
                node = new Ext.tree.AsyncTreeNode(config);
            }
            else {
                node = new Ext.tree.TreeNode(config);
            }
            return node;
        };
        categoryLoader.on("beforeload", function(treeLoader, node) {
            treeLoader.baseParams.category = node.attributes.id;
        });

        categoryLoader.on("load", function(treeLoader, node, config) {
            varienWindowOnload();
        });
        var tree = new Ext.tree.TreePanel('[entity]-categories', {
            animate:true,
            loader: categoryLoader,
            enableDD:false,
            containerScroll: true,
            rootUIProvider: Ext.tree.CheckboxNodeUI,
            selModel: new Ext.tree.CheckNodeMultiSelectionModel(),
            rootVisible: '<?php echo $this->getRootNode()->getIsVisible() ?>'
        });
        tree.on('check', function(node) {
            if(node.attributes.checked) {
                categoryAdd(node.id);
            } else {
                categoryRemove(node.id);
            }
            varienElementMethods.setHasChanges(node.getUI().checkbox);
        }, tree);
        var root = new Ext.tree.TreeNode({
            text: '<?php echo $this->jsQuoteEscape($this->getRootNode()->getName()) ?>',
            draggable:false,
            checked:'<?php echo $this->getRootNode()->getChecked() ?>',
            id:'<?php echo $this->getRootNode()->getId() ?>',
            disabled: <?php echo ($this->getRootNode()->getDisabled() ? 'true' : 'false') ?>,
            uiProvider: Ext.tree.CheckboxNodeUI
        });
        tree.setRootNode(root);
        bildCategoryTree(root, <?php echo $this->getTreeJson() ?>);
        tree.addListener('click', categoryClick.createDelegate(this));
        tree.render();
        root.expand();
    });
    function bildCategoryTree(parent, config){
        if (!config) {
            return null;
        }
        if (parent && config && config.length){
            for (var i = 0; i < config.length; i++){
                config[i].uiProvider = Ext.tree.CheckboxNodeUI;
                var node;
                var _node = Object.clone(config[i]);
                if (_node.children && !_node.children.length) {
                    delete(_node.children);
                    node = new Ext.tree.AsyncTreeNode(_node);

                }
                else {
                    node = new Ext.tree.TreeNode(config[i]);
                }
                parent.appendChild(node);
                node.loader = node.getOwnerTree().loader;
                if(config[i].children){
                    bildCategoryTree(node, config[i].children);
                }
            }
        }
    }
    function categoryClick(node, e){
        if (node.disabled) {
            return;
        }
        node.getUI().check(!node.getUI().checked());
        varienElementMethods.setHasChanges(Event.element(e), e);
    };
    function categoryAdd(id) {
        var ids = $('[entity]_categories').value.split(',');
        ids.push(id);
        $('[entity]_categories').value = ids.join(',');
    }
    function categoryRemove(id) {
        var ids = $('[entity]_categories').value.split(',');
        while (-1 != ids.indexOf(id)) {
            ids.splice(ids.indexOf(id), 1);
        }
        $('[entity]_categories').value = ids.join(',');
    }
</script>
<?php endif; ?>

Di file formulir di mana Anda menambahkan tab entitas kustom Anda, tambahkan ini juga:

    $this->addTab('categories', array(
        'label' => Mage::helper('[module]')->__('Associated categories'),
        'url'   => $this->getUrl('*/*/categories', array('_current' => true)),
        'class'    => 'ajax'
    ));

Di pengontrol admin entitas kustom Anda, 2 tindakan ini yang akan menangani permintaan untuk kategori:

public function categoriesAction(){
    $this->_init[Entity]();
    $this->loadLayout();
    $this->renderLayout();
}
public function categoriesJsonAction(){
    $this->_init[Entity]();
    $this->getResponse()->setBody(
        $this->getLayout()->createBlock('[module]/adminhtml_[entity]_edit_tab_categories')
            ->getCategoryChildrenJson($this->getRequest()->getParam('category'))
    );
}

dan pastikan bahwa pada kontroler yang sama metode ini ada:

protected function _init[Entity](){
    $[entity]Id  = (int) $this->getRequest()->getParam('id');
    $[enity]    = Mage::getModel('[module]/[entity]');

    if ($[entity]Id) {
        $[entity]->load($[entity]Id);
    }
    Mage::register('current_[entity]', $[entity]);
    return $[entity];
}

Di file tata letak admin modul Anda tambahkan pegangan ini untuk tindakan kategori:

<adminhtml_[module]_[entity]_categories>
    <block type="core/text_list" name="root" output="toHtml">
        <block type="[module]/adminhtml_[entity]_edit_tab_categories" name="[entity].edit.tab.categories"/>
    </block>
</adminhtml_[module]_[entity]_categories>

Sekarang mari kita lanjutkan ke penyimpanan data Anda.
Untuk ini, Anda akan memerlukan yang berikut ini di salah satu skrip instal / peningkatan modul Anda. Ini akan membuat tabel di mana nilai tertaut akan disimpan

$table = $this->getConnection()
    ->newTable($this->getTable('[module]/[entity]_category'))
    ->addColumn('rel_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
        'unsigned'  => true,
        'identity'  => true,
        'nullable'  => false,
        'primary'   => true,
        ), 'Relation ID')
    ->addColumn('[entity]_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
        'unsigned'  => true,
        'nullable'  => false,
        'default'   => '0',
    ), '[Entity] ID')
    ->addColumn('category_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
        'unsigned'  => true,
        'nullable'  => false,
        'default'   => '0',
    ), 'Category ID')
    ->addColumn('position', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
        'nullable'  => false,
        'default'   => '0',
    ), 'Position')
    ->addIndex($this->getIdxName('[module]/[entity]_category', array('category_id')), array('category_id'))
    ->addForeignKey($this->getFkName('[module]/[entity]_category', '[entity]_id', '[module]/[entity]', 'entity_id'), '[entity]_id', $this->getTable('[module]/[entity]'), 'entity_id', Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE)
    ->addForeignKey($this->getFkName('[module]/[entity]_category', 'category_id', 'catalog/category', 'entity_id'),    'category_id', $this->getTable('catalog/category'), 'entity_id', Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE)
    ->addIndex(
    $this->getIdxName(
        '[module]/[entity]_category',
        array('[entity]_id', 'category_id'),
        Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE
    ),
    array('[entity]_id', 'category_id'),
    array('type' => Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE))
    ->setComment('[Entity] to Category Linkage Table');
$this->getConnection()->createTable($table);

Nyatakan meja Anda. Tambahkan ini di config.xmldalam <[module]_resource><entities>tag

<[entity]_category>
    <table>[module]_[entity]_category</table>
</[entity]_category>

Anda memerlukan model untuk menautkan ke kategori:
app/code/local/[Namespace]/[Module]/Model/[Entity]/Category.php

<?php

class [Namespace]_[Module]_Model_[Entity]_Category
    extends Mage_Core_Model_Abstract {
    protected function _construct(){
        $this->_init('[module]/[entity]_category');
    }
    public function save[Entity]Relation($[entity]){
        $data = $[entity]->getCategoriesData();
        if (!is_null($data)) {
            $this->_getResource()->save[Entity]Relation($[entity], $data);
        }
        return $this;
    }
    public function getCategoryCollection($[entity]){
        $collection = Mage::getResourceModel('[module]/[entity]_category_collection')
            ->add[Entity]Filter($[entity]);
        return $collection;
    }
}

dan model sumber daya app/code/local/[Namespace]/[Module]/Model/Resource/[Entity]/Category.php:

<?php

class [Namespace]_[Module]_Model_Resource_[Entity]_Category
    extends Mage_Core_Model_Resource_Db_Abstract {

    protected function  _construct(){
        $this->_init('[module]/[entity]_category', 'rel_id');
    }
    public function save[Entity]Relation($[entity], $data){
        if (!is_array($data)) {
            $data = array();
        }
        $deleteCondition = $this->_getWriteAdapter()->quoteInto('[entity]_id=?', $[entity]->getId());
        $this->_getWriteAdapter()->delete($this->getMainTable(), $deleteCondition);

        foreach ($data as $categoryId) {
            if (!empty($categoryId)){
                $this->_getWriteAdapter()->insert($this->getMainTable(), array(
                    '[entity]_id'      => $[entity]->getId(),
                    'category_id'     => $categoryId,
                    'position'      => 1
                ));
            }
        }
        return $this;
    }
}

dan model sumber daya koleksi: app/code/local/[Namespace]/[Module]/Model/Resource/[Entity]/Category/Collection.php

<?php
class [Namespace]_[Module]_Model_Resource_[Entity]_Category_Collection
    extends Mage_Catalog_Model_Resource_Category_Collection{
    protected $_joinedFields = false;
    public function joinFields(){
        if (!$this->_joinedFields){
            $this->getSelect()->join(
                array('related' => $this->getTable('[module]/[entity]_category')),
                'related.category_id = main_table.entity_id',
                array('position')
            );
            $this->_joinedFields = true;
        }
        return $this;
    }
    public function add[Entity]Filter($[entity]){
        if ($[entity] instanceof [Namespace]_[Module]_Model_[Entity]){
            $[entity] = $[entity]->getId();
        }
        if (!$this->_joinedFields){
            $this->joinFields();
        }
        $this->getSelect()->where('related.[entity]_id = ?', $[entity]);
        return $this;
    }
}

Sekarang di saveAction controller admin Anda, tambahkan ini tepat sebelum memanggil $[entity]->save()

$categories = $this->getRequest()->getPost('category_ids', -1);
if ($categories != -1) {
    $categories = explode(',', $categories);
    $categories = array_unique($categories);
    $[entity]->setCategoriesData($categories);
}

Dalam model entitas Anda, tambahkan ini di bagian atas kelas Anda: protected $_categoryInstance = null;dan metode ini di mana saja:

protected function _afterSave() {
    $this->getCategoryInstance()->save[Entity]Relation($this);
    return parent::_afterSave();
}
public function getCategoryInstance(){
    if (!$this->_categoryInstance) {
        $this->_categoryInstance = Mage::getSingleton('[module]/[entity]_category');
    }
    return $this->_categoryInstance;
}
public function getSelectedCategories(){
    if (!$this->hasSelectedCategories()) {
        $categories = array();
        foreach ($this->getSelectedCategoriesCollection() as $category) {
            $categories[] = $category;
        }
        $this->setSelectedCategories($categories);
    }
    return $this->getData('selected_categories');
}
public function getSelectedCategoriesCollection(){
    $collection = $this->getCategoryInstance()->getCategoryCollection($this);
    return $collection;
}

Itu saja. Saya harap saya tidak melewatkan apa pun. Kode mungkin memerlukan beberapa perubahan karena saya tidak tahu bagaimana tepatnya modul Anda dibangun, tetapi ide-ide utama ada di sana. Dengan beberapa debug, Anda harus membuatnya berfungsi.


Catatan: Kode di atas dibuat menggunakan Ultimate Module Creator v1.9 .


Pos luar biasa! Anda perlu sedikit keterampilan untuk menindaklanjuti, tetapi jika Anda mencari jawaban semacam ini, Anda harus sudah cukup. Ada kesalahan ketik di suatu tempat (maaf saya tidak ingat persis di mana) fungsi disebut ... categoTy ... bukan categoRy. terima kasih Marius
Giuseppe

Mengapa Anda tidak menggunakan api pohon kategori Magento untuk mendapatkan data dalam modul Anda dan meneruskannya dalam tampilan. Anda dapat memainkannya dengan sangat mudah.
Sourabh Modi

@SourabhModi. Saya telah menciptakan kembali koneksi kategori dengan cara yang sama yang digunakan untuk mengaitkan kategori ke suatu produk dalam formulir tambah / edit produk. Saya berpikir untuk tetap konsisten.
Marius

Saya hanya menyimpan data saya di bidang model yang disebut category_ids.
Giuseppe

1
@Marius saya mengerti maksud Anda, tetapi masalahnya adalah, jika Anda memanggil API Magento, kode dari sisi Anda akan sangat kurang dan secara internal Magento melakukan hal yang sama ketika api dipanggil seperti yang telah mereka lakukan untuk mengaitkan kategori pada formulir tambah / sunting produk . Jadi tidak ada gunanya menulis ulang kode ini lagi pada Anda sendiri karena Anda dapat menggunakan fungsi yang sama dengan memanggil fungsi (panggilan API adalah panggilan fungsi) yang secara internal menggunakan fungsi yang diperlukan sama seperti pada formulir tambah / sunting produk.
Sourabh Modi

2

Setidaknya untuk Magento 1.9 Anda harus yakin bahwa extJs dimuat.
Gunakan salah satu metode berikut untuk mengaktifkan penggunaan extJS di backend:

  1. Di controller Anda gunakan ini:

    $this->getLayout()->getBlock('head')->setCanLoadExtJs(true);
  2. Di layout Anda xml gunakan ini:

    <reference name="head">
        <action method="setCanLoadExtJs">
            <value>1</value>
        </action>
    </reference>
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.