Reputation: 127
I'm editing a custom plugin in magento in which I need add a field to upload an image and save it's path in the database together with other data. The form works fine with the additional data, as well as the database recording. However, it seems that the $_FILES variable always return empty. What is more curious is that an file called "cache_2ca019d1e2db75b611e5f3aa5c932970" is always generated in the media directory every time I try to upload an image in my module.
I've found people with similar problems here, but none of the presented solutions worked for me. I'm lost =/
This is my Form file:
<?php
class SmashingMagazine_BrandDirectory_Block_Adminhtml_Brand_Edit_Form
extends Mage_Adminhtml_Block_Widget_Form
{
protected function _prepareForm()
{
// instantiate a new form to display our brand for editing
$form = new Varien_Data_Form(array(
'id' => 'edit_form',
'action' => $this->getUrl(
'smashingmagazine_branddirectory_admin/brand/edit',
array(
'_current' => true,
'continue' => 0,
)
),
'method' => 'post',
'enctype' => 'multipart/form-data'
));
$form->setUseContainer(true);
$this->setForm($form);
// define a new fieldset, we only need one for our simple entity
$fieldset = $form->addFieldset(
'general',
array(
'legend' => $this->__('Brand Details')
)
);
$brandSingleton = Mage::getSingleton(
'smashingmagazine_branddirectory/brand'
);
// add the fields we want to be editable
$this->_addFieldsToFieldset($fieldset, array(
'name' => array(
'label' => $this->__('Name'),
'input' => 'text',
'required' => true,
),
'url_key' => array(
'label' => $this->__('URL Key'),
'input' => 'text',
'required' => true,
),
'image' => array(
'label' => $this->__('Image'),
'input' => 'image',
'required' => true,
'disabled' => false,
'readonly' => true,
),
'visibility' => array(
'label' => $this->__('Visibility'),
'input' => 'select',
'required' => true,
'options' => $brandSingleton->getAvailableVisibilies(),
),
/**
* Note: we have not included created_at or updated_at,
* we will handle those fields ourself in the Model before save.
*/
));
return $this;
}
/**
* This method makes life a little easier for us by pre-populating
* fields with $_POST data where applicable and wraps our post data in
* 'brandData' so we can easily separate all relevant information in
* the controller. You can of course omit this method entirely and call
* the $fieldset->addField() method directly.
*/
protected function _addFieldsToFieldset(
Varien_Data_Form_Element_Fieldset $fieldset, $fields)
{
$requestData = new Varien_Object($this->getRequest()
->getPost('brandData'));
foreach ($fields as $name => $_data) {
if ($requestValue = $requestData->getData($name)) {
$_data['value'] = $requestValue;
}
// wrap all fields with brandData group
$_data['name'] = "brandData[$name]";
// generally label and title always the same
$_data['title'] = $_data['label'];
// if no new value exists, use existing brand data
if (!array_key_exists('value', $_data)) {
$_data['value'] = $this->_getBrand()->getData($name);
}
// finally call vanilla functionality to add field
$fieldset->addField($name, $_data['input'], $_data);
}
return $this;
}
/**
* Retrieve the existing brand for pre-populating the form fields.
* For a new brand entry this will return an empty Brand object.
*/
protected function _getBrand()
{
if (!$this->hasData('brand')) {
// this will have been set in the controller
$brand = Mage::registry('current_brand');
// just in case the controller does not register the brand
if (!$brand instanceof
SmashingMagazine_BrandDirectory_Model_Brand) {
$brand = Mage::getModel(
'smashingmagazine_branddirectory/brand'
);
}
$this->setData('brand', $brand);
}
return $this->getData('brand');
}
}
And this is my Controller File:
<?php
class SmashingMagazine_BrandDirectory_Adminhtml_BrandController
extends Mage_Adminhtml_Controller_Action
{
/**
* Instantiate our grid container block and add to the page content.
* When accessing this admin index page we will see a grid of all
* brands currently available in our Magento instance, along with
* a button to add a new one if we wish.
*/
public function indexAction()
{
// instantiate the grid container
$brandBlock = $this->getLayout()
->createBlock('smashingmagazine_branddirectory_adminhtml/brand');
// add the grid container as the only item on this page
$this->loadLayout()
->_addContent($brandBlock)
->renderLayout();
}
/**
* This action handles both viewing and editing of existing brands.
*/
public function editAction()
{
/**
* retrieving existing brand data if an ID was specified,
* if not we will have an empty Brand entity ready to be populated.
*/
$brand = Mage::getModel('smashingmagazine_branddirectory/brand');
if ($brandId = $this->getRequest()->getParam('id', false)) {
$brand->load($brandId);
if ($brand->getId() < 1) {
$this->_getSession()->addError(
$this->__('This brand no longer exists.')
);
return $this->_redirect(
'smashingmagazine_branddirectory_admin/brand/index'
);
}
}
// process $_POST data if the form was submitted
if ($postData = $this->getRequest()->getPost('brandData')) {
try {
// image upload
if(isset($_FILES['image']['name']) and (file_exists($_FILES['image']['tmp_name'])))
{
try
{
$path = Mage::getBaseDir('media') . DS . 'banner' . DS;
$uploader = new Varien_File_Uploader('image');
$uploader
->setAllowedExtensions(array('jpg','png','gif','jpeg'));
$uploader->setAllowRenameFiles(false);
$uploader->setFilesDispersion(false);
$destFile = $path.$_FILES[$image]['name'];
$filename = $uploader->getNewFileName($destFile);
$uploader->save($path, $filename);
$data['img'] = $_FILES['image']['name'];
}
catch(Exception $e)
{
}
}
else
{
if(isset($data['image']['delete']) && $postData['image']['delete'] == 1)
$data['image'] = '';
else
unset($data['image']);
}
// continue
$brand->addData($postData);
$brand->save();
$this->_getSession()->addSuccess(
$this->__($_FILES['image']['name'])
);
// redirect to remove $_POST data from the request
return $this->_redirect(
'smashingmagazine_branddirectory_admin/brand/edit',
array('id' => $brand->getId())
);
} catch (Exception $e) {
Mage::logException($e);
$this->_getSession()->addError($e->getMessage());
}
/**
* if we get to here then something went wrong. Continue to
* render the page as before, the difference being this time
* the submitted $_POST data is available.
*/
}
// make the current brand object available to blocks
Mage::register('current_brand', $brand);
// instantiate the form container
$brandEditBlock = $this->getLayout()->createBlock(
'smashingmagazine_branddirectory_adminhtml/brand_edit'
);
// add the form container as the only item on this page
$this->loadLayout()
->_addContent($brandEditBlock)
->renderLayout();
}
public function deleteAction()
{
$brand = Mage::getModel('smashingmagazine_branddirectory/brand');
if ($brandId = $this->getRequest()->getParam('id', false)) {
$brand->load($brandId);
}
if ($brand->getId() < 1) {
$this->_getSession()->addError(
$this->__('This brand no longer exists.')
);
return $this->_redirect(
'smashingmagazine_branddirectory_admin/brand/index'
);
}
try {
$brand->delete();
$this->_getSession()->addSuccess(
$this->__('The brand has been deleted.')
);
} catch (Exception $e) {
Mage::logException($e);
$this->_getSession()->addError($e->getMessage());
}
return $this->_redirect(
'smashingmagazine_branddirectory_admin/brand/index'
);
}
/**
* Thanks to Ben for pointing out this method was missing. Without
* this method the ACL rules configured in adminhtml.xml are ignored.
*/
protected function _isAllowed()
{
/**
* we include this switch to demonstrate that you can add action
* level restrictions in your ACL rules. The isAllowed() method will
* use the ACL rule we have configured in our adminhtml.xml file:
* - acl
* - - resources
* - - - admin
* - - - - children
* - - - - - smashingmagazine_branddirectory
* - - - - - - children
* - - - - - - - brand
*
* eg. you could add more rules inside brand for edit and delete.
*/
$actionName = $this->getRequest()->getActionName();
switch ($actionName) {
case 'index':
case 'edit':
case 'delete':
// intentionally no break
default:
$adminSession = Mage::getSingleton('admin/session');
$isAllowed = $adminSession
->isAllowed('smashingmagazine_branddirectory/brand');
break;
}
return $isAllowed;
}
}
Thanks in advance.
Upvotes: 1
Views: 1350
Reputation: 394
// add the fields we want to be editable
$this->_addFieldsToFieldset($fieldset, array(
'name' => array(
'label' => $this->__('Name'),
'input' => 'text',
'required' => true,
),
'url_key' => array(
'label' => $this->__('URL Key'),
'input' => 'text',
'required' => true,
),
'image' => array(
'label' => $this->__('Image'),
'input' => 'image',
'name' => 'image',
'required' => true,
'disabled' => false,
),
'visibility' => array(
'label' => $this->__('Visibility'),
'input' => 'select',
'required' => true,
'options' => $brandSingleton->getAvailableVisibilies(),
),
/**
* Note: we have not included created_at or updated_at,
* we will handle those fields ourself in the Model before save.
*/
));
Try this by adding name attribute on image.
Upvotes: 1