$file kills setup script

It is possible to change important and used variables inside the setup model while installing

I implemented a data-setup script today.

It starts with defining a variable:

$file = 'var/import/sample.csv';

The error

When magento was called, I got this error:

[message:protected] => Warning: Illegal string offset 'toVersion'  in app/code/core/Mage/Core/Model/Resource/Setup.php on line 641
[string:Exception:private] => 
[code:protected] => 0
[file:protected] => app/code/core/Mage/Core/functions.php
[line:protected] => 245
[trace:Exception:private] => Array
	[...]

I opened the Setup model and found this code snippet:

foreach ($files as $file) {
	[...]
    try {
        switch ($fileType) {
            case 'php':
                $conn   = $this->getConnection();
                $result = include $fileName;
                break;
           [...]     
        }

        if ($result) {
            $this->_setResourceVersion($actionType, $file['toVersion']);
        }
    } catch (Exception $e) {
        [...]
    }
	[...]
}

Debugging

I debbuged and at the beginning of the foreach $file is an array with the keys toVersion 0.1.10 and fileName with the path to my setup script.

After the $result $file was 'var/import/sample.csv'. It took a while until I realized, that it is the value I write into the variable, because I debugged the import script for a while. But then I wondered. WHY!?

Explanation

There is this small little line of code:

$result = include $fileName;

it includes the data/install script and the variable $file is assigned with my value. Especially the loop variable $file is overwritten.

Conclusion

Be careful with defining variables in setup scripts. I wanted to write a "bugfix" but thinking 10 minutes about the problem didn't develope a solution for the problem. There is no possibility in PHP to prevend the overwrite of this variable.

HAH! There is. I thought about changing the scope but didn't find a simple solution. but just implementing a method should do it!

Blog writing brings solutions. Thanks audience for help.

Hopefully you all know, what Rubber ducking is?

Array Union Operator

Use the Union Operator to fix a magento bug

These days I found a bug in magento.

The bug

Magento has a method in Mage_Core_Helper_Data to removeAccents:

public function removeAccents($string, $german=false)
{
	if (empty($replacements[$german])) {
        $subst = array(
            // single ISO-8859-1 letters
            192=>'A', 193=>'A', 194=>'A', 195=>'A', 196=>'A', 197=>'A', 199=>'C',
    		// [...] more characters
        );
		
        if ($german) {
			// umlauts
			$subst = array_merge($subst, array(
				196=>'Ae', 228=>'ae', 214=>'Oe', 246=>'oe', 220=>'Ue', 252=>'ue'
			));
		}

		// [...] replace the stuff and return it
}

As you can see the code is easy to understand. Magento builds up an array with the charaters which should be replaced as the keys and the replacement as the value.

If you want to replace german characters with the german replacements, e.g. ä with ae and Ü with Ue you can pass a second parameter to the method. When you do it, a few keys will be overwritten with the german replacement.

I tried it and the result was a mess. Why? Because of the following little sentence in the PHP doc on array_merge:

Values in the input array with numeric keys will be renumbered with incrementing keys starting from zero in the result array.

This error can't be unseen if anybody tried the code one time. But with Magento 2 and testing everything will hopefully be better.

The array union operator

After this long introduction I'll come to the array union operator +. Did you know it? I program for eight years PHP and I can't remember ever seen a + between two arrays.

The usage is simple:

$array1 = array('10' => 'test', '12' => 'foo');
$array2 = array('12' => 'bar', '13' => 'magento');
var_dump($array1 + $array2);
var_dump(array_merge($array1, $array2)); // UPDATE array_merge() was missing
// Result:
array (size=3)
	10 => string 'test' (length=4)
	12 => string 'foo' (length=3)
	13 => string 'magento' (length=7)
    
array (size=4)
	0 => string 'test' (length=4)
	1 => string 'foo' (length=3)
	2 => string 'bar' (length=3)
	3 => string 'magento' (length=7)        

This means that the array union operator merges the arrays considering keys and values. If the value exists in a following array it is ignored.

In comparison to array_merge the keys are ignored and the values are overwritten by later passed arrays.

The fix for the bug

Use the array union operator to merge the arrays, but be careful with the order of the passed arrays, reverse them.

if ($german) {
    // umlauts
    $subst = array(
        196=>'Ae', 228=>'ae', 214=>'Oe', 246=>'oe', 220=>'Ue', 252=>'ue'
    ) + $subst;
}

IE users are logged out by multiple uploader

Scenario

We upload images via Multiple-File-Uploader in the magento backend. The upload went on the first look well, the image is shown in the table under the other images. As I hopefully wrote here the images are loaded from the server in full size, but especally FROM THE server. This means the files were saved on the server.

Logout after submitting the form

After submitting the form, I saw the admin login. I didn't check what exactly happens here. Thanks to google I found the answer in the magento forum:

suhosin.session.cryptua = off 

This setting is in the standard .htaccess with this comment:

# disable user agent verification to not break multiple image upload

I have really NO idea, why everything works, when I turn on this option, but afterwards I wasn't longer logged out after uploading an image. So just change the setting to:

suhosin.session.cryptua = on 

Parameters of Varien_Data_Form?

Why do I write this? Because I had the problem a few hours ago that no form was rendered in my backend formular. And as a few of you may know, the FireGento GermanSetup Team met today. Noone of us knew instantly why. So here are a few tipps.

HTML Attributes

You can set the html attributes id, name, method, action, enctype, class and onsubmit. Especially method and enctype is needed for file uploads. With onsubmit you can implement more checks in javascript. And with action the target of the form is defined, as you should know.

Container yes or no?

As you can see in the code there is another parameter: use_container. With use_container you decied wether to wrap a <form> around your form elements and add a form_key.

Ikonoshirt_CustomAdminNotifications

Looking for an easy way to add your Magento_AdminNotifications? Here it is.

The readme is already in markdown and I think readable. So have a look. I pushed the extension to github.

Ikonoshirt_CustomAdminNotifications

As I wrote in my blog, it is important to keep the people who use our extensions up-to-date. Magento implemented a great feature to do this, the Mage_AdminNotification.

As I wrote, there should be an easy way to add RSS feeds to the existing one, here it is.

How to use

Install this module, install your own module and add a few lines to your Package/Extensionname/etc/config.xml. Just add a node to ikonoshirt/custom_rss_feeds/feeds with your RSS feed url.

<default>
    <ikonoshirt>
        <custom_rss_feeds>
            <feeds>
                <fbfeed>http://blog.fabian-blechschmidt.de/feed.xml</fbfeed>
            </feeds>
        </custom_rss_feeds>
    </ikonoshirt>
</default>

It is important, that the feed have to be an RSS feed. The following nodes are MUST per item:

  • date_added
  • title
  • description
  • url

The following SHOULD:

  • severity (int between 4 (NOTICE) and 1 (CRITICAL)) as showed in Mage_AdminNotification_Model_Inbox. If no severity is present it is 4.
    const SEVERITY_CRITICAL = 1;
    const SEVERITY_MAJOR    = 2;
    const SEVERITY_MINOR    = 3;
    const SEVERITY_NOTICE   = 4;

How to not use

Please don't spam your customer with offers, giftcodes, etc. If he likes your software and extensions, he'll come back and check for other interesting stuff. The notifications are NO advertising channel - as I already mentioned in my blog post.