Tag Archives: magento

Magento: Changing street line count of customer address programatically

Nowadays I’m facing interesting programming challenges. The last one was the changing of street line count of a customer address. As you may know, Magento doesn’t have a good documentation for similar situations. So here it is how I did it.

Create an upgrade script in your module. Inside you should have something like:

$installer = $this;
$installer->startSetup();
$db = $this->getConnection();
$path = "customer/address/street_lines";
$value = 3; // change this with your new street line value
// here you will read the config id of the street line
// if exists update it, else insert it, naturally you could have used a replace into syntax also
// this is just for simplicity. Be careful, this solution does not treat cases when
// you are using multiple stores with different settings
$sql = $db->prepare("
    SELECT config_id
    FROM core_config_data 
    WHERE 
        path = :path
    ");
$sql->execute(array(
    ":path" => $path
));
$result = $sql->fetch();
if (!empty($result))
{
    $sql = $db->prepare("
        UPDATE core_config_data
        SET
            value = :value
        WHERE
            config_id = :config_id
    ");
    $sql->execute(array(
        ":config_id" => $result['config_id'],
        ":value" => $value
    ));
}
else
{
    $sql = $db->prepare("
        INSERT INTO core_config_data (path, value)
        VALUES(:path, :value)
    ");
    $sql->execute(array(
        ":path" => $path,
        ":value" => $value
    ));
}
// next step is to read the attribute id of "street" from the eav_attribute table
$sql = $db->prepare("
    SELECT attribute_id
    FROM eav_attribute
    WHERE 
        entity_type_id = 2 AND
        attribute_code = 'street'
    ");
$sql->execute();
$result = $sql->fetch();
$streetAttributeId = $result['attribute_id'];
// update "multiline_count" column in "customer_eav_attribute" table
$sql = $db->prepare("
UPDATE customer_eav_attribute
SET multiline_count = :value
WHERE
attribute_id = :street_attribute_id
");
$sql->execute(array(
":value" => $value,
":street_attribute_id" => $streetAttributeId
));

$installer->endSetup();

Briefly: you have to save in core_config_data and also in customer_eav_attribute table your new street line value.

How to create a UNIQUE column in magento install script

You can add unique columns in your install script easier than you thought. After searching for a while in search engines without any results, the good old method helped: search in all files of magento… The good news is that you get the results of my searches right here:

<?php
$installer = $this;
$installer->startSetup();
$table = $installer->getConnection()
->newTable($installer->getTable(SOME_TABLE_NAME_DEFINITION))

->addColumn(“my_unique_column_name”,…)

->addIndex($installer->getIdxName(SOME_TABLE_NAME_DEFINITION, array(‘my_unique_column_name’), Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE), “my_unique_column_name”,array(“type” => Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE));
$installer->getConnection()->createTable($table);

$installer->endSetup();

Grid column types in Magento

I recently had to implement a new grid in Magento, and I wasn’t sure what should I write to the type parameter:

protected function _prepareColumns()
{
      $this->addColumn('some_column_id', array(
              'header' => Mage::helper('core')->__('Some column name'),
              'index' => 'some_column_index',
              'type' => '???',
      ));
...

So I made a little bit of research to find out all the types available. I don’t want to go in details, so here is the list:

  • action
  • checkbox
  • concat
  • country
  • currency
  • date
  • datetime
  • input
  • interface
  • ip
  • longtext
  • massaction
  • number
  • options
  • price
  • radio
  • select
  • store
  • text
  • theme
  • wrapline

You will find all these types in /app/code/core/Mage/Adminhtml/Block/Widget/Grid/Column/Renderer folder. You can also make your own grid types similarly.

Using Magento Flex uploader

A few days ago I tried to use Uploadify in Magento, but it failed because of jQuery noConflict, so I decided to try Magento’s default uploader, the Flex Uploader.

I couldn’t find a good documentation or tutorial about it, so I did a little research.

In the template you should put:

<?php $htmlId = "someHtmlId"; ?>
 <div id="<?php echo $htmlId ?>" class="uploader">
     <div class="buttons">
        <div id="<?php echo $htmlId ?>-install-flash" style="display:none">
            <?php echo Mage::helper('media')->__('This content requires last version of Adobe Flash Player. <a href="%s">Get Flash</a>', 'http://www.adobe.com/go/getflash/') ?>
        </div>
     </div>
     <div class="clear"></div>
     <div id="<?php echo $htmlId ?>-template" class="no-display">
         <div id="{{id}}" class="file-row">
             <span class="file-info">{{name}} ({{size}})</span>
             <span class="delete-button"><button id="{{id}}-delete" title="<?php echo $this->__("Delete")?>" type="button" class="scalable delete" onclick="uploader.removeFile('{{fileId}}')" style=""><span><span><span><?php echo $this->__("Delete") ?></span></span></span></button></span>
             <span class="progress-text"></span>
             <div class="clear"></div>
         </div>
     </div>
     <div id="<?php echo $htmlId ?>-template-progress" class="no-display">
         {{percent}}% {{uploaded}} / {{total}}
     </div>
 </div>

Practically this will be the place where the uploader will show you the progress of the upload. You will also need to place a javascript code which should look like:

    var uploader = new Flex.Uploader('<?php echo $htmlId ?>', '<?php echo $this->getSkinUrl('media/uploader.swf') ?>', <?php echo $this->getConfigJson('some_parameter_for_you') ?>);
    uploader.onFilesComplete = function(completedFiles)
    {
        completedFiles.each(function(file)
            {
                doSomethingWithTheResponse(file.response);
                uploader.removeFile(file.id);
            }
        );
        MediabrowserInstance.handleUploadComplete();
    }
    // hide flash buttons
    if ($('<?php echo $htmlId ?>-flash') != undefined)
    {
        $('<?php echo $htmlId ?>-flash').setStyle({float:'left'});
    }
//specify maximum file upload size (very important!)
    var maxUploadFileSizeInBytes = 10 * 1024 * 1024;
    var maxUploadFileSize = '10M';

 

Attention! $ is Prototype (not jQuery) in the example above.

We will need to configure the Flex uploader in the block class of the template file:

    public function getConfigJson($field)
    {
        $this->getConfig()->setParams(
            array(
                'form_key' => $this->getFormKey(),
                "field" => $field
            )
        );
        $this->getConfig()->setFileField('Filedata');
        $this->getConfig()->setUrl(Mage::getModel('adminhtml/url')->addSessionParam()->getUrl("*/*/upload", array("param1" => "value1")));
        $this->getConfig()->setFilters(array(
            'pdf documents' => array(
                'label' => Mage::helper('adminhtml')->__('Portable Document Format (.pdf)'),
                'files' => array('*.pdf')
            )
        ));
        return Mage::helper('core')->jsonEncode($this->getConfig()->getData());
    }     

    public function getConfig()
    {
        if(is_null($this->_config)) {
            $this->_config = new Varien_Object();
        }

        return $this->_config;
    }

You can specify multiple file filters with the setFilters method, not just one as in my example. Also, with the setUrl method you will set the target URL, which will do the processing of the upload. In my example I set it as */*/upload. This means that in the controller of the current page you will have to set something similar to this:

    public function uploadAction()
    {
        if (!empty($_FILES))
        {
            $result = array();
            try
            {
                $uploader = new Varien_File_Uploader("Filedata");
                $uploader->setAllowRenameFiles(true);

                $uploader->setFilesDispersion(false);
                $uploader->setAllowCreateFolders(true);

                $path = "put_your_path_to_save_here";//ex. Mage::getBaseDir('base') . DS ."my_uploads" . DS

                $uploader->setAllowedExtensions(array('pdf')); //server-side validation of extension
                $uploadSaveResult = $uploader->save($path, $_FILES['Filedata']['name']);

                $result = $uploadSaveResult['file'];
            }
            catch(Exception $e)
            {
                $result = array(
                    "error" => $e->getMessage(),
                    "errorCode" => $e->getCode(),
                    "status" => "error"
                );
            }             
            $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
        }
    }

Don’t forget to load the required javascript libraries. You can do it in your layout xml file:

   <your_layout>
        <reference name="head">
            <action method="addJs">
                <js>lib/flex.js</js>
            </action>
            <action method="addJs">
                <js>lib/FABridge.js</js>
            </action>
            <action method="addJs">
                <js>mage/adminhtml/flexuploader.js</js>
            </action>
        </reference>
   </your_layout>
   

That’s all folks!

Adding new action into controller in Magento

Sometimes you have to change the default functionality of Magento, either by modifying the core module (which is not recommended) or by writing your own module. The latter is described in many other websites, so I won’t write about that. But I feel important to write about such a simple thing like adding a new action into a controller.

Why? Because I’m just learning Magento and I have already spent too much time figuring out why it doesn’t work.

As many of you already know, Magento is based on Zend Framework. The basic mechanism of processing an URL is the following:

<protocol>://<host>/<controller>/<action>[/<parameters>]

<protocol> is for example http

<host> is your domain name ex. www.example.com

<controller> is the name of your controller

<action> is the name of your action

The rule is simple, the controller’s filename is <controller>Controller.php and the action has to be a function inside the controller with the name <action>Action.

Here’s an example:

http://www.example.com/hello/world

and it will call the worldAction in helloController.php.

These are the basics you need to know when starting to work with Magento. It is a little bit different but not so much.

The Magento team have made their system ultra-extra extensible, and that’s why it is so slow – at least the community edition. That is the reason why my local apache crashed many times while I tried  to debug with xdebug to understand how Magento works; and beside this, sometimes even Eclipse or Netbeans cannot resolve the correct class names.

I won’t go into the details of routings or other special stuff, I know there are plenty of ways to create a new action, but sometimes it is better to know the basics. In the case of Magento you will see something similar to what we have for Zend Framework:

<protocol>://<host>/[index.php/]<module frontName>/<controller>/<action>[/<parameters>]

example: http://www.example.com/index.php/myuniverse/hello/world

The basic logic is the same: you will find the worldAction in the helloController.php in your module’s folder.

Up to this point everything seemed to be clear for me. I opened the browser, entered the url and it redirected me to the home page. Tried to do things like

<?php
class ...._HelloController...
{
  ...
  public function worldAction()
  {
    echo "something";
    exit;
  }
  ...
}

but the “something” didn’t show up. I made a little research to make it work, tried different configuration changes in config.xml but it didn’t helped. I got a tip to make a route in the configuration, which would point a URL to a specific method of a class… what??! Does it seems complicated only for me? I said there must be an easier solution for this.

And the solution is really easy. You may have already observed that on every page (of the admin backend) you can find some junk parameters like …/key/0123456789abcdef0123456789abcdef/. Well, I thought that it is rubbish… it is not.

Suddenly, I said `Let me try to generate the URL to my page within an existing template with something like:

$this->getUrl("*/hello/world", array("myparam1" => "myvalue1"))

which resulted in a bulky, sausage-like  link:

http://www.example.com/index.php/myuniverse/hello/world/myparam1/myvalue1/key/0123456789abcdef0123456789abcdef/

then I opened it in the browser and tadamm!: it showed the “something”.

Briefly: you don’t have to modify your configurations, just simply add your action method into the controller (ex. worldAction into helloController.php) and access your page with the complete URL (which contains the […]/key/[…]/); you can generate the link with the getUrl() function.