Category Archives: php

Magento: eav attribute frontend input types

Sometimes you are looking for a specific frontend input types of the eav attributes, but you don’t have a full list. You can find the types in lib/Varien/Data/Form/Element. Here they are:

  • Button
  • Checkbox
  • Checkboxes
  • Collection
  • Column
  • Date
  • Editor
  • Fieldset
  • File
  • Gallery
  • Hidden
  • Image
  • Imagefile
  • Label
  • Link
  • Multiline
  • Multiselect
  • Note
  • Obscure
  • Password
  • Radio
  • Radios
  • Reset
  • Select
  • Submit
  • Text
  • Textarea
  • Time

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.

Running Phpunit PHAR under Windows

Installing the Phpunit sometimes is not that easy. Especially when we want to do it quickly and under Windows.
There are a couple of ways doing it, but it is not well documented how to use it with a PHAR under Windows. For those who don’t know what is a PHAR, it is a PHp ARchive, which in practice is a zip file containing the whole structure of a site, and you can run it easily like a simple php file.
Running the Phpunit test can be done in several ways: using just command line, or using an external tool like Ant.
First of all you have to place your phpunit.phar in a path ex. c:mypath. Then configure Phpunit xml file. Example:

<phpunit>
  <testsuites>
    <testsuite name="my test">
      <file>c:/work/tests/SomeTest.php</file>
      <file>c:/work/tests/AnotherTest.php</file>
    </testsuite>
  </testsuites>
</phpunit>

I named it tests.xml and put it in folder c:worktests. You can write your own test files and place it wherever you want (in my build file they are placed in c:worktests). Example:

class SomeTest extends PHPUnit_Framework_TestCase
{
    public function testPushAndPop()
    {
        $stack = array();
        $this->assertEquals(0, count($stack));

        array_push($stack, 'foo');
        $this->assertEquals('foo', $stack[count($stack)-1]);
        $this->assertEquals(1, count($stack));

        $this->assertEquals('foo', array_pop($stack));
        $this->assertEquals(0, count($stack));
    }
}

Now you can run it with:
PATH_TO_PHPphp.exe c:mypathphpunit.phar -c c:workteststests.xml.

That’s it. Additionally, if you want this to be part of an Ant build, there is a simple way doing it:

1. You must have java to be able to run Ant
2. Create a build.xml for Ant. Example:

<project name="MyProject" basedir="PATH_TO_PHPUNIT_PHAR">
	<description>
		simple example build file
	</description>
	<target name="phpunit" description="Run unit tests with PHPUnit">
		<exec executable="PATH_TO_PHP/php.exe" failonerror="true">
			<arg value="phpunit.phar"/>
			<arg value="-c"/>
			<arg value="c:/work/tests/tests.xml"/>
		</exec>
	</target>
</project>

3. Run: ant.bat phpunit

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();

How to find out the real cause of the boring RuntimeException in ZF2

Nowadays I’m just getting annoying error stack traces from zend framework 2 with a message like:

PHP Fatal error:  Uncaught exception 'ZendViewExceptionRuntimeException' with message 'ZendViewRendererPhpRenderer::render: Unable to render template "error"; resolver could not resolve to a file' in C:worksrcvendorzendframeworkzendframeworklibraryZendViewRendererPhpRenderer.php:451

and naturally the stack trace doesn’t even shows where the real problem happens.

I tried to put the problematic code lines in a try-catch block, but the same happened: uncaught exception. That was really weird, because I tried to catch Exception, which should be every exception’s parent class. Later I found out that since the current file is in a specific namespace, then I have to specify the exact class type of the Exception class. For example:

<?php
namespace SomeName;
class Whatever
{
    try
    {
        //some erroneous code
    }
    catch (Exception $e)
    {
        echo $e;
    }

}

If you would try to catch Exception, then the exception class should be SomeNameException, so that’s why you have to use it like Exception, so php will try to find the class in the root namespace.

 

Setting the doctype in Zend Framework 2

I recently had to change the doctype in a Zend Framework 2 environment. It was kind of difficult to find the answer so I share with you. Simply set the doctype before “running it” in index.php like this:

<?php
/**
 * This makes our life easier when dealing with paths. Everything is relative
 * to the application root now.
 */
chdir(dirname(__DIR__));

// Setup autoloading
include 'init_autoloader.php';

$doctypeHelper = new ZendViewHelperDoctype();
$doctypeHelper->setDoctype($doctypeHelper::HTML5);

// Run the application!
ZendMvcApplication::init(include 'config/application.config.php')->run();

The possible doctypes are:

XHTML11            
XHTML1_STRICT      
XHTML1_TRANSITIONAL
XHTML1_FRAMESET    
XHTML1_RDFA        
XHTML1_RDFA11      
XHTML_BASIC1       
XHTML5             
HTML4_STRICT       
HTML4_LOOSE        
HTML4_FRAMESET     
HTML5              
CUSTOM_XHTML       
CUSTOM

That’s all folks.

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.

Frameworks vs. traditional coding

In the last few years the usage of frameworks became a must. In my opinion there are three types of coder:

1. who loves frameworks

2. who doesn’t care too much

3. who hates frameworks

The big question is: why to love/hate frameworks? Well, because they are smart.

A few years ago, in 2005, when I started learning php the best and most used browser was IE6 (internet explorer version 6). As you may know it is a very silly browser and you have to write the code carefully to achieve your goals. Most pages were very cubic-like, and they were contructed from tables… and tables in tables. At that time the frameworks still had the egg shells on their bottoms. Even Php was in the same boot: version 5.0.0, the brand new object oriented, rewritten Php.

Some guys have decided to write some rudimentary frameworks. But wait-wait-wait… what is a framework? You can read it in this Wikipedia article or just briefly: it is a software which controls the flow of your program, it is extensible and last but not least it structurates your code. Hmm… you could ask me now: ok, but what flow are you talking about? and why to extend a code? or even better: what does it mean to extend a code?

Let me answer these. The frameworks have some drawbacks: they have some strict rules which must be followed; all these rules together creates the flow. This means that a predefined logic will always run before your code. Naturally this can be a good thing but also a bad one.

Let me give you a few examples:

Zend framwork [php]:

a URL like: www.example.com/animals/dogs by default will be parsed and it will run your dogsAction method in your AnimalsController class.

Smarty [php template framework]:

in your template when you are using for example {$myVariable} it will be transformed into a value set previously in a php file with $smarty->assign(“myVariable”, “my value”);

jQuery [javascript]:

by using $(‘input[name=first_name]’) the framework finds the input tag with the name “first_name”. You could say now that you can do it with a traditional javascript method by using document.querySelector… well yes, but not before IE8.

And here we are: the frameworks have pros! They have such functionalities which are natively not supported by the system. The javascript example with jQuery will work even on IE6!

As you can see, I’m using as examples the internet explorer browser. This is because it is the slowest, silliest and most featureless browser which is used by millions of people; and when you want to write a cool website, it should work on most of the browsers. Don’t understand me wrongly: in my opinion the IE6-8 is dead, but still tons of people are using them.

And we arrived to the extensibility… It means to write your code in the same style as the framework: structured. Most of the Php frameworks separate different type of logic into separate files: html from php logic. Since a few years we hear about the MVC. The MVC separates into three: model = everything related to an object; view = html related; controller = a class which interacts with models and views. Separating the logic doesn’t mean that you won’t have php code in it. It means that it will be a minimalistic php: ifs, loops, variables. Why is it good for you? It is easier for you to find different portions of code and you can work with others in the same project in the same time without overwriting each other.

Another good thing on frameworks are the plugins. There are many plugins for the basic frameworks. Why to reimplement the wheel? Just use it and you’re done.

Are there any drawbacks? Well, there are… The frameworks are usually slower than the pure coding. I’ve been benchmarking Mysql from Php: PDO vs. non-PDO. The non-PDO version of the same script worked 10% faster. Zend Framework uses PDO, so by start it is slower a little bit. But don’t panic, we are talking about micro seconds. On a heavy framework like Magento, well… it is slow enough, so it needs a dedicated machine anyway.

When to use traditional coding and when to use frameworks? Well, it depends. If you are writing simple things like hello world, then don’t use a framework! On small pages you can use them partially, for example a javascript framework (jQuery, Prototype, Mootools, YUI etc.). In other cases it is recommanded to use a framework (Zend Framework, Symfony, CodeIgniter, Cakephp, Magento etc.).

There is one more thing. By learning the “language” of a framework, you will be able to work on a project (written in the same framework) which was written by someone else.

If you are starting to work with the framework, try to do it everything in their way. So if you use Zend Framework, then don’t create manually forms, but create ZendForm. This way you can add validation of the fields easily.

Also, it is good to know that sometimes you have to create such functionalities of your site, which is not supported natively by the framework. In these cases you have to “hack” the framework somehow. Sometimes a simple thing needs a week of researching, while you could write it in the traditional way in five minutes.

In my opinion, anyone can write structured code without a framework, but it is good to know the other way too.

 

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.