Magento – load custom review attribute

event-observermagento-1.9modelreview

I'm using magento 1.9.2.4 version.
I tried to add custom field(file) in product review page. I have added new attribute to review_detail table using

$installer->run("ALTER TABLE {$this->getTable('review_detail')} 
    ADD COLUMN(customfield' varchar(255) NULL);

Now added the field in review_detail table. Now i'm trying to add/save the data with customfield using my custom module review_save_before event by calling myFunction.
When printing the model, it does not added my custom field.

MyFunction code is here

public function myFunction(Varien_Event_Observer $observer)
{
    $object = $observer->getEvent()->getObject();
    $data = $object->getData();
    $review = Mage::getModel('review/review')->getCollection()->getData();
    echo "<pre>";
    print_r($data);
    exit;
}

How to assign and save data for my customfield using the model.

Updates:
Config.xml

<models>
    <customreview>
        <class>Mycompany_Customreview_Model</class>
        <resourceModel>customreview_mysql4</resourceModel>
    </customreview>
    <customreview_mysql4>
        <class>Mycompany_Customreview_Model_Mysql4</class>
        <entities>
            <customreview><table>review_detail</table></customreview>
        </entities>
        <rewrite>
            <review>Mycompany_Customreview_Model_Resource_Review</review>
        </rewrite>
    </customreview_mysql4>
</models>
<resources>
    <customreview_setup>
        <setup>
            <module>Mycompany_Customreview</module>
            <class>Mage_Eav_Model_Entity_Setup</class>
        </setup>
        <connection>
            <use>core_setup</use>
        </connection>
    </customreview_setup>
    <customreview_write>
        <connection>
            <use>core_write</use>
        </connection>
    </customreview_write>
    <customreview_read>
        <connection>
            <use>core_read</use>
        </connection>
    </customreview_read>
</resources>

<review_save_after>
    <observers>
        <add_custom_field_to_the_review>
            <type>singleton</type>
            <class>customreview/observer</class>
            <method>myFunction</method>
        </add_custom_field_to_the_review>
    </observers>
</review_save_after>

In installer script:

$installer->getConnection()
    ->addColumn($installer->getTable('review/review_detail'),'customfield', array(
        'type'      => Varien_Db_Ddl_Table::TYPE_TEXT,
        'nullable'  => false,
        'length'    => 255,
        'comment'   => 'Custom Field'
    ));

In my phtml file:

<li>
    <label for="customfield" class="required"><em>*</em><?php echo $this->__('Custom Field') ?></label>
    <div class="input-box">
        <textarea name="customfield" id="customfield" cols="5" rows="3" class="required-entry"><?php echo $this->escapeHtml($data->getCustomfield()) ?></textarea>
    </div>
</li>

My observer:

public function myFunction($observer)
{
    $object = $observer->getEvent()->getObject();
    if (!$object->getCustomfield()) {
        echo "nop";exit;
        return $this;
    }

    try {
        /** @var Varien_Db_Adapter_Interface $connection */
        $adapter = Mage::getSingleton('core/resource')->getConnection('core_write');
        $reviewDetailTable = $adapter->getTableName('review_detail');
        $select = $adapter->select()
            ->from($reviewDetailTable, 'detail_id')
            ->where('review_id = :review_id');
        $detailId = $adapter->fetchOne($select, array(':review_id' => $object->getId()));

        if ($detailId) {
            $detail = array(
                'customfield' => $object->getCustomfield()
            );
            $condition = array("detail_id = ?" => $detailId);
            $adapter->update($reviewDetailTable, $detail, $condition);
        }
    } catch (Exception $e) {
        Mage::logException($e);
    }

    return $this;
}

Best Answer

Data is saved to the table review/review_detail with different method. There are 3 fields in the resource model:

  1. title
  2. detail
  3. nickname

They are saved manually to this table. Other data is ignored whether it present in the review model or not. Here is a part of code responsible for that:

/**
 * Perform actions after object save
 *
 * @param Varien_Object $object
 * @return Mage_Review_Model_Resource_Review
 */
protected function _afterSave(Mage_Core_Model_Abstract $object)
{
    $adapter = $this->_getWriteAdapter();
    /**
     * save detail
     */
    $detail = array(
        'title' => $object->getTitle(),
        'detail' => $object->getDetail(),
        'nickname' => $object->getNickname(),
    );
    $select = $adapter->select()
        ->from($this->_reviewDetailTable, 'detail_id')
        ->where('review_id = :review_id');
    $detailId = $adapter->fetchOne($select, array(':review_id' => $object->getId()));

    if ($detailId) {
        $condition = array("detail_id = ?" => $detailId);
        $adapter->update($this->_reviewDetailTable, $detail, $condition);
    } else {
        $detail['store_id'] = $object->getStoreId();
        $detail['customer_id'] = $object->getCustomerId();
        $detail['review_id'] = $object->getId();
        $adapter->insert($this->_reviewDetailTable, $detail);
    }

You have several options:

  1. You can save your data in the table review/review and not in the table review/review_detail.
  2. You can write an observer to add necessary data after saving all the review objects (save_after) and save again.

I suppose, that the first option is better. All you need to realize it is to add your field to the table review/review. After that all data will be saved automatically without an observer.

If you choose the second option, you should rewrite your observer in the following way:

Use the event review_save_after in the config.xml file:

<events>
    <review_save_after>
        <observers>
            <add_custom_field_to_the_review>
                <type>singleton</type>
                <class>test/observer</class>
                <method>myFunction</method>
            </add_custom_field_to_the_review>
        </observers>
    </review_save_after>

Do the following changes in your method:

public function myFunction($observer)
{
    $object = $observer->getEvent()->getObject();
    if (!$object->getCustomfield()) {
        return $this;
    }

    try {
        /** @var Varien_Db_Adapter_Interface $connection */
        $adapter = Mage::getSingleton('core/resource')->getConnection('core_write');
        $reviewDetailTable = $adapter->getTableName('review_detail');
        $select = $adapter->select()
            ->from($reviewDetailTable, 'detail_id')
            ->where('review_id = :review_id');
        $detailId = $adapter->fetchOne($select, array(':review_id' => $object->getId()));

        if ($detailId) {
            $detail = array(
                'customfield' => $object->getCustomfield()
            );
            $condition = array("detail_id = ?" => $detailId);
            $adapter->update($reviewDetailTable, $detail, $condition);
        }
    } catch (Exception $e) {
        Mage::logException($e);
    }

    return $this;
}

This allows to successfully save data to the table review_details.

enter image description here

We checked this by adding the input form to the products review.

<li>
    <label for="customfield" class="required"><em>*</em><?php echo $this->__('Custom Field') ?></label>
    <div class="input-box">
        <textarea name="customfield" id="customfield" cols="5" rows="3" class="required-entry"><?php echo $this->escapeHtml($data->getCustomfield()) ?></textarea>
    </div>
</li>

enter image description here

Additionally, we recommend you to update your installation script:

<?php
/* @var $installer Mage_Core_Model_Resource_Setup */
$installer = $this;
$installer->startSetup();

$installer->getConnection()
    ->addColumn($installer->getTable('review/review_detail'),'customfield', array(
        'type'      => Varien_Db_Ddl_Table::TYPE_TEXT,
        'nullable'  => false,
        'length'    => 255,
        'comment'   => 'Custom Field'
    ));

$installer->endSetup();