Xóa chế độ xem cửa hàng theo chương trình trong tập lệnh nâng cấp


12

Tôi muốn xóa một cửa hàng theo chương trình . Nhìn vào Mage_Adminhtml_System_StoreController::deleteStorePostAction(), điều này khá dễ dàng (rút ngắn mã một chút):

$model = Mage::getModel('core/store')->load($id);

if ($model->getId() && $model->isCanDelete()) {
    $model->delete();
    Mage::dispatchEvent('store_delete', array('store' => $model));
}

Tôi muốn đặt mã này vào một kịch bản nâng cấp dữ liệu để việc xóa sẽ được thực hiện tự động.

Vấn đề là trong khi thực thi các tập lệnh nâng cấp trong data/Magento chỉ gọi các trình quan sát sự kiện được cấu hình trong globalkhu vực (xem Cập nhật cấu trúc Magento so với Cập nhật dữ liệu ). Một số nhà quan sát thích enterprise_cmsenterprise_searchcho sự kiện store_delete_afterđược xác định trong adminhtmlkhu vực để họ không bị xử tử. Việc xóa chế độ xem cửa hàng sẽ không được xử lý như việc xóa được thực hiện trong phần phụ trợ.

Làm thế nào để bạn xử lý các hoạt động như thế này? Tự tải các khu vực sự kiện bổ sung trong các kịch bản nâng cấp (tôi sợ điều đó)? Đừng sửa đổi dữ liệu như trong kịch bản nâng cấp mà hãy đặt các đoạn mã ma thuật của bạn vào một nơi ẩn thiêng và thực hiện thủ công?


1
Tại sao bạn cần xóa xem cửa hàng có vấn đề?
oleksii.svarychevskyi

Bởi vì chúng tôi có một số môi trường và nhanh hơn và đáng tin cậy hơn để thực hiện tất cả các thay đổi cấu hình theo chương trình.
Matthias Zeis

Bao giờ tìm thấy một giải pháp cho điều này? Làm thế nào thường xuyên bạn sẽ làm điều này? Cá nhân, tôi sẽ sử dụng tùy chọn thứ hai "Đừng sửa đổi dữ liệu như trong kịch bản nâng cấp mà đặt các đoạn mã ma thuật của bạn vào một nơi bí mật và thực hiện thủ công?"
ProxiBlue

Tôi hoãn vấn đề này vì có nhiều việc quan trọng hơn để làm. Chính @philwinkle của Magento SE đã trả lời trên Twitter: "Tôi thực hiện những điều này trong một hàng đợi hoặc lắng nghe và tổ chức một sự kiện điều phối adminhtml song song (còn gọi là giả mạo)" ( twitter.com/philwinkle/status/428183845985210369 ). Tôi tin rằng điều này quá rủi ro đối với tôi và mặc dù tôi không thích cách tiếp cận này nhưng tôi sẽ thực hiện bằng tay.
Matthias Zeis

@MatthiasZeis bạn có thể thêm câu đó làm câu trả lời và chấp nhận nó để giữ cho câu hỏi chưa được trả lời đếm ngược không?
Sander Mangel

Câu trả lời:


6

Vì vậy, ngay sau khi tôi tweet điều này với Matthias, tôi đã im lặng trên đài phát thanh. Tôi hy vọng bạn cảm thấy hồi hộp vì bạn đã chờ câu trả lời này trong vài tuần nay.

Ý tôi là "Tôi làm những việc này trong hàng đợi" là phản hồi trực tiếp với:

Một số nhà quan sát nhất định như Enterprise_cms và Enterprise_search cho sự kiện store_delete_after được xác định trong khu vực adminhtml để họ sẽ không bị xử tử. Việc xóa chế độ xem cửa hàng sẽ không được xử lý như việc xóa được thực hiện trong phần phụ trợ.

Phương thức xếp hàng:

Khi tôi biết rằng có một số sự kiện nhất định sẽ không kích hoạt trong bối cảnh chính xác (chủ yếu là cho EE, nhưng có thể áp dụng trong các bối cảnh khác), tôi thường chuyển việc xóa ra khỏi hàng đợi để nó sẽ chạy trong ngữ cảnh mà nó cần phải chạy .

Nói cách khác, tạo một bảng xếp hàng (hoặc hàng đợi / chủ đề trong RabbitMQ, v.v.) sẽ chứa các chi tiết của giao dịch và các móc nối sự kiện mà nó nên nghe. Điều này có thể thanh lịch hoặc đơn giản như bạn muốn nó được. Đây là một cơ bản

$queue = Mage::getModel('yourcompany/queue_job')
         ->setJobType('delete')
         ->setEntityType('core/store')
         ->setEntityId(12)
         ->setDispatchEvent('store_delete')
         ->setDispatchEventDataKey('store')
         ->save();

Và sau đó thực hiện hàng đợi sau trong CRON, nơi bạn có quyền kiểm soát cửa hàng nào đang "chạy" (hay bạn chỉ đang chạy nó như thể là quản trị viên, cửa hàng 0):

foreach(Mage::getModel('yourcompany/queue_job')->getCollection() as $job){
    if($job->getJobType()=='delete'){

        $model = Mage::getModel($this->getEntityType())->load($this->getEntityId());

        if ($model->getId() && $model->isCanDelete()) {
            $model->delete();
            Mage::dispatchEvent($job->getDispatchEvent(), array($job->setDispatchEventDataKey() => $model));
        }
    }
}

Rõ ràng nếu bạn đang trở nên ưa thích, bạn hãy thử / bắt và giao dịch. Tôi nghĩ rằng bạn có được ý chính.

Đây là cách khả thi duy nhất để kiểm soát bối cảnh mà sự kiện này nổ ra.

Phương pháp sự kiện Tandem:

Bạn có thể tự mình kích hoạt phương thức "adminhtml" - Alan đưa ra một lời giải thích khá chính xác về những gì bạn sẽ làm để ảnh hưởng đến điều đó , nhưng về cơ bản nó giống như thế này:

#File: app/code/core/Mage/Adminhtml/controllers/CustomerController.php
public function saveAction()
{
    //...
    $customer->save();
    //...
    Mage::dispatchEvent('adminhtml_customer_prepare_save', array(
        'customer'  => $customer,
        'request'   => $this->getRequest()
    ));        
    //..
}

Phiên bản quản trị của lưu khách hàng gọi mô hình lưu thông thường và gửi sự kiện adminhtml sau đó. Bạn có thể làm điều ngược lại với điều này trong một người quan sát nếu bạn muốn.


5

Khỉ thật, tôi yêu tôi một chút, nhưng tôi không đồng ý với sự phức tạp / giòn của việc vận chuyển các tham số nhiệm vụ khu vực ( adminhtml | crontab | frontend | global | install ) vào hàng đợi, đặc biệt nếu hàng đợi đó sẽ được thực thi một bối cảnh Magento. Nếu có các bối cảnh hỗn hợp cần xử lý thì giải pháp hàng đợi là sự thực hiện lại "vấn đề" hiện tại!

Tôi nghĩ rằng cách tiếp cận hàng đợi là dễ vỡ. Lập luận của tôi là việc tải các khu vực sự kiện sớm không thực sự là một vấn đề. Để giải thích điều này, hãy sao lưu và xem xét vấn đề:

Nguy hiểm của việc tải một khu vực sự kiện sớm trong một phạm vi thực thi là gì?

Để hiểu điều này, chúng ta phải kiểm tra các khu vực sự kiện trong bối cảnh thực hiện. Matthias, tôi tưởng tượng rằng bạn đã biết điều này, nhưng đối với sự chỉnh sửa của người khác:

Các tập lệnh thiết lập dữ liệu được thực thi Mage_Core_Model_App::run()trước khi gửi yêu cầu tới Bộ điều khiển phía trước:

public function run($params)
{
    $options = isset($params['options']) ? $params['options'] : array();
    $this->baseInit($options);
    Mage::register('application_params', $params);

    if ($this->_cache->processRequest()) {
        $this->getResponse()->sendResponse();
    } else {
        $this->_initModules();
//Global event area is loaded here
        $this->loadAreaPart(Mage_Core_Model_App_Area::AREA_GLOBAL, Mage_Core_Model_App_Area::PART_EVENTS);

        if ($this->_config->isLocalConfigLoaded()) {
            $scopeCode = isset($params['scope_code']) ? $params['scope_code'] : '';
            $scopeType = isset($params['scope_type']) ? $params['scope_type'] : 'store';
            $this->_initCurrentStore($scopeCode, $scopeType);
            $this->_initRequest();
//Data setup scripts are executed here: 
            Mage_Core_Model_Resource_Setup::applyAllDataUpdates();
        }

        $this->getFrontController()->dispatch();
    }
    return $this;
}

Vào thời điểm các tập lệnh thiết lập dữ liệu đang thực thi, khu vực sự kiện toàn cầu được tải. Các khu vực sự kiện định tuyến theo ngữ cảnh ( frontend hoặc adminhtml ) được tải sau này Mage_Core_Controller_Varien_Action::preDispatch()do bộ định tuyến khớp với hành động của bộ điều khiển ( areatên được đặt thông qua kế thừa):

public function preDispatch()
{
    //...
    Mage::app()->loadArea($this->getLayout()->getArea());
    //...
}

Vì vậy, thông thường trong quá trình khởi tạo ứng dụng, chỉ những người quan sát được cấu hình trong khu vực sự kiện toàn cầu sẽ được thực thi. Nếu tập lệnh thiết lập làm một cái gì đó như

$this->loadAreaPart(Mage_Core_Model_App_Area::AREA_ADMINHTML, Mage_Core_Model_App_Area::PART_EVENTS);

sau đó chỉ có hai nguy hiểm:

  1. Một người quan sát đã bị định cấu hình sai dưới adminhtml để quan sát một sự kiện không có ngữ cảnh như controller_front_init_beforehoặccontroller_front_init_routers
  2. Yêu cầu là một yêu cầu frontend .

# 1 nên dễ grep cho. # 2 là mối quan tâm thực sự và tôi nghĩ rằng Reflection có thể giải quyết vấn đề (lưu ý rằng tôi thiếu kinh nghiệm trong việc sử dụng sự phản chiếu):

<?php

//Start setup script as normal
$installer = $this;
$installer->startSetup()

//Load adminhtml event area
Mage::app()->loadAreaPart(
    Mage_Core_Model_App_Area::AREA_ADMINHTML,
    Mage_Core_Model_App_Area::PART_EVENTS
);

// your setup script logic here

//I hope this isn't a bad idea.
$reflectedApp = new ReflectionClass('Mage_Core_Model_App');
$_areas = $reflectedApp->getProperty('_areas');
$_areas->setAccessible(true);
$areas = $_areas->getValue(Mage::app());
unset($areas['adminhtml']);
$_areas->setValue(Mage::app(),$areas); //reset areas

//End setup script as normal
$installer->endSetup()

Tôi đã không kiểm tra điều này, nhưng nó loại bỏ chỉ số sự kiện adminhtml và Mage_Core_Model_App_Areađối tượng tương ứng .


1
Tôi không xứng đáng!! Tôi không xứng đáng!!!!
philwinkle
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.