Claudiu Persoiu

Blog-ul lui Claudiu Persoiu


Archive for the ‘PHP’ Category

Passing Magento Developer Plus certification

with 3 comments

Over an year ago, I started working on the Magento platform. In last year’s spring, a colleague from Optaros took the Magento Developer Plus certification exam. Since then, I began to like the idea of taking the certification exam, more as a motivation to learn the ins and outs of Magento.

Few months ago I was enrolled into a company study group for the certification. This was the first time I was sponsored for a certification (yes, until now everything was with my money). Preparing in a study group was a whole different experience.

Those who have more experience in a field balance the situation for the others and can give better examples from their own experience. It’s easier to understand from concrete examples then to try to imagine the scenarios yourself.

The certification is available through Prometric. So when you decide that you’re ready you can go to the website to purchase the voucher and schedule the exam.

The price for a voucher is 260$, not exactly cheap, but if you get to convince your boss to pay, it probably won’t be so bad. 🙂

But let’s get to the more interesting subject, the preparation.

Materials
Magento is not doing very good on this subject, there are very few materials and they are not centralized.

My sources were:
Magento® Certified Developer Plus Exam Study Guide – it is compulsive to read the guide and try to find answers to all the questions in it;
Magento training – especially Fundamentals of Magento Development
– blogs – I don’t want to give any names, there are a lot of people that write about the problems that they encounter and blog about the exam.

Unfortunately there isn’t a way like for PHP, ZF and Symfony where you can find all you need in one place, basically it depends on your luck and searching skills, there isn’t an “official version”. Things become weird when you find different approaches that are version specific.

How did I prepare
I began with the video training. It’s not perfect by it’s very helpful. I think the problem with most certifications is that you don’t get to work with all the available modules, just like in PHP you don’t get to work that much with sockets and streams.

Even though you don’t get the code and sometimes it is hard to follow and transcribe the examples, I think that the video tutorials are one of the most important sources at the moment.

Secondly, with the Study Guide in my hand, I began to try to answer the questions from it. When I joined the Study Group, the work divided between all the members in the group. My advantage was that it was the second generation of the group and we could profit from the documentation already developed by the first group.

If you’re preparing by yourself, I think the most important thing is to start, that’s the hardest part. And if you don’t know where to start, Google search the Magento questions, there are already a lot of people that are posting the explanations.

Answers for the questions from the first chapters are the easiest to find. As the number of the chapter is getting bigger, the number of Google results decreases.

But after the first questions, you should understand what is all about and in theory you will no longer need the documentation.

Use Mage::log(Varien_Debug::backtrace(true, false)); for stack trace and xdebug (http://xdebug.org/) to see what’s going on behind the scene. With patience, all the questions find their answers.

Because it was a group, the study was easier for me, but even so, to be sure of the explanation I has to dive deep in the code.

The exam
Some of the questions are difficult, but there are also accessible ones. The questions in the exam are off all levels of difficulty.

For Plus, the exam takes 2h not 2.5h as it is specified in the guide.

If you opted for Plus, there are 11 questions from Enterprise and advanced difficulty questions, of which 7 correct ones are required to pass. Basically this is the difficulty difference. For this questions it matters how much Enterprise experience you have.

In the guide for each exam, the questions are broken in percentages for each chapter.

Because in the non Plus certification there are no Enterprise questions, you only have to answer the necessary percentage from the full exam in order to pass and it’s not required to have a certain percentage from a certain chapter.

Things that are done regularly are analyzed in detail, it is important to understand how each function that is approached in each chapter works and what is the purpose of all those tags in the xml files.

Usually there are things you work with, or at least with which there is a good probability you have been working from the modules listed in the guide.

Post exam
Before you leave the room you’ll know if you’ve passed or not. When you exit the room you’ll receive a printed paper with the correct number of questions from each section from the total number .

In case you haven’t been successful you’ll receive by mail from Magento a voucher with a discount for a future attempt. They state that you should study at least 3 more weeks before you try again. Anyway, after you’ve taken the exam you’ll have a better view over your overall knowledge for a future attempt.

After few days (3 in my case) you will be able to see your profile on the Magento website as a reference.

The diploma got to Romania in about a month, the delivery address is the one from the Magento website account.

Best of luck!

Written by Claudiu Persoiu

16 February 2013 at 8:23 PM

Posted in Magento,PHP

Tagged with , , ,

There is life without PHP 6 – 2012 retrospective

with 3 comments

Another year has passed without native unicode support for PHP. Yes, PHP6 is not here yet, in case anybody was still asking…

But, the version that is now here is PHP 5.4. With this version only refinements were added, there weren’t changes as big as there were on PHP 5.3. In PHP 5.4, the big addition are “traits” and, my favorite, the new version for closure.

As the keywords for last year were Drupal and Magento, this year the keyword was only Magento.

A couple of months ago, more or less forced by the circumstances, I’ve taken the Magento Plus certification exam. For this certification, Optaros, my employer, had a major influence. We had been more or less made to take the exam and we also had to be part of a company level study group.

I haven’t been part of a study group since faculty, and I must admit that I’ve forgotten how useful it is. Colleagues with more Magento experience (unlike me who I’ve been working with Magento for a little more than an year), had helped a lot to clarify issues and to document them.

But more about this in another blog, that will follow shortly (I hope)…

Anyway, after studying Magento in so much detail, I must admit that I have a lot more respect for the platform. After you analyze the backend architecture, a different picture is emerging. The architecture is very interesting and quite flexible, which makes you overlook some of it’s shortcomings.

Now that a new year has begun, I wish I’m going to publish more, I think in the last period I haven’t been very “productive” when it comes to publishing, either text or code.

Also this year I want to take at least another certification exam. As the Magento certification was set only for this year, I still have a lot of options on my plate.

That’s about all for 2012 and plans for 2013.

I wish you an excellent 2013!

Written by Claudiu Persoiu

14 January 2013 at 9:54 AM

Posted in Diverse,PHP

Tagged with , ,

Overwriting and deactivating Observers in Magento

with 2 comments

Sometimes we need to overwrite an observer. The first way that usually comes in mind is overwriting the model. Usually is named Observer.php, because this is the “best practice”.

And NO, you don’t have to overwrite the model. Observer.php doesn’t extend anything anyway and usually contains all of the module’s observers, so you can’t overwrite the same observer in more than one module.

How it works?
In magento when a new observer is added, it must have an unique identifier. This identifier is the key!

Actually, there is another element: “area”. When Mage::dispatchEvent(…) is performed, events will be dispatched using “area” and “identifier”.

For example, the admin notification system, which is observing “controller_action_predispatch”, will run:

=> "global"(area)
=> "controller_action_predispatch"(event)
=> "adminnotification"(identifier)

then:

=> "adminhtml"(area)
=> "controller_action_predispatch"(event)
=> "adminnotification"(identifier)

If the event was in the frontend area, it would be: “global” then “frontend”.

Overwriting
Overwriting is in fact a observer defined in the same config area as the original event (global, frontend or adminhtml), attached to the same event and with the same identifier as the original observer (e.g. adminnotification).

Let’s say we have to overwrite “adminnotification”. This observer is in Mage/AdminNotification. The unique identifier is defined in etc/config.xml:

...
  <adminhtml>
...
    <events>
      <controller_action_predispatch>
        <observers>
          <adminnotification>
            <class>adminnotification/observer</class>
            <method>preDispatch</method>
          </adminnotification>
        </observers>
      </controller_action_predispatch>
    </events>
...
  </adminhtml>
...

From the example above we can see:
– area: adminhtml
– event: controller_action_predispatch
– identifier: adminnotification

The module activation file will be: app/etc/modules/CP_AdminNotification.xml

<?xml version="1.0"?>
<config>
  <modules>
    <CP_AdminNotification>
      <active>true</active>
      <codePool>local</codePool>
      <depends>
        <Mage_AdminNotification/>
      </depends>
    </CP_AdminNotification>
  </modules>
</config>

I’ve added dependencies because without the original module, this module will be useless.

There’s a “best practice” to name a module that is overwritten with the same name as the original module.

The configuration file for this module, will contain practically everything you’ll need for the overwriting: area, event and identifier. The file is located in app/code/local/CP/AdminNotification/etc/config.xml:

<?xml version="1.0"?>
<config>
  <modules>
    <CP_AdminNotification>
      <version>0.0.1</version>
    </CP_AdminNotification>
  </modules>
  <global>
    <models>
      <cp_adminnotification>
        <class>CP_AdminNotification_Model</class>
      </cp_adminnotification>
    </models>
  </global>
  <adminhtml>
    <events>
      <controller_action_predispatch>
        <observers>
          <adminnotification>
            <class>cp_adminnotification/observer</class>
            <method>overwrittenPreDispatch</method>
          </adminnotification>
        </observers>
      </controller_action_predispatch>
    </events>
  </adminhtml>
</config>

The observer should contain all the new logic. The file is in app/code/local/CP/AdminNotification/Model/Observer.php, just like you would probably expect from the structure above.

<?php

class CP_AdminNotification_Model_Observer {

  public function overwrittenPreDispatch(Varien_Event_Observer $observer) {
    // noua logica din observer
  }
}

Disabling
Disabling is preaty similar to overwriting, the difference is in the config and the fact that an observer file is not needed anymore, because there isn’t a new logic.

The new config.xml file is:

<?xml version="1.0"?>
<config>
...
  <adminhtml>
    <events>
      <controller_action_predispatch>
        <observers>
          <adminnotification>
            <type>disabled</type>
          </adminnotification>
        </observers>
      </controller_action_predispatch>
    </events>
  </adminhtml>
</config>

Written by Claudiu Persoiu

17 May 2012 at 9:59 PM

Posted in Magento,PHP

Tagged with ,

My pink elePHPant in the room

without comments

happy elePHPants

My elePHPants family!

My elePHPants collection has just doubled, now I have 2!

I wanted an pink elePHPant, to keep company to my old elePHPant.

Also this time I’ve turned to eBay. A quick search found another elePHPants breeder, this time is: Herman J. Radtke III. This time I’ve ordered it directly from his site, without eBay, only because eBay would calculate the shipping fee wrong.

Even with the right shipping fee, the new elePHPant wasn’t exactly cheap:

$ RON
ElePHPant 16.16 55,51
Shipping to RO 16.95 58,23
Postal fee (customs) 0.6 1.95
Total: 33.71 115,69

Not exactly cheap taking into consideration that the price for an elePHPant is about 5 euros in bulk.

But now I have a happy elePHPant family!

Written by Claudiu Persoiu

17 April 2012 at 10:01 PM

Posted in Diverse,PHP

Tagged with ,

Magento – Create a custom shopping cart price rule

with 2 comments

This is not a tutorial about setting up a Shopping Cart Price Rule in Magento, but rather about implementing a new one.

A new type of rule in Magento needs a couple of things:
– modify the admin area to add the new rule using an observer for adminhtml_block_salesrule_actions_prepareform,
– a way to apply the new rule using an observer for salesrule_validator_process.

Let’s build an example. Let’s say there is a Shopping Cart Price Rule that offers different discounts according to the number of products in the cart. The value that’s going to be used for the discount increment ($step) will be calculated. The first product will not receive a discount, the second product will receive a discount of $step, the third product will have a discount of 2*$step, until the maximum discount value will be reached. The following products will have a maximum discount. Ex:
Discount Amount = 50
Discount Qty = 5
Step = Discount Amount / Discount Qty = 10

Discount outcome:
– 0% prod 1
– 10% prod 2

– 50% prod 6
– 50% prod 7

The first step is the module activation using the file: app/etc/modules/CP_ProductNrDiscount.xml

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <CP_ProductNrDiscount>
            <active>true</active>
            <codePool>local</codePool>
        </CP_ProductNrDiscount>
    </modules>
</config>

The first observer, adminhtml_block_salesrule_actions_prepareform, must be in the “adminhtml” section of the config, because it will involve the admin. This observer will have access to the admin form, in order to modify it.

The second observer, salesrule_validator_process, can be in the “frontend” or “global” section of the config. If it’s in the frontend section, it will only apply to the frontend section. If it’s in the global section it will also apply to backend. Usually, global is necessary when there are actions on the cart in the backend.

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <CP_ProductNrDiscount>
            <version>0.0.1</version>
        </CP_ProductNrDiscount>
    </modules>
    <global>
        <models>
            <productnrdiscount>
                <class>CP_ProductNrDiscount_Model</class>
            </productnrdiscount>
        </models>
        <events>
            <salesrule_validator_process>
                <observers>
                    <productnrdiscount>
                        <type>model</type>
                        <class>productnrdiscount/observer</class>
                        <method>salesruleValidatorProcess</method>
                    </productnrdiscount>
                </observers>
            </salesrule_validator_process>
        </events>
    </global>
    <adminhtml>
        <events>
            <adminhtml_block_salesrule_actions_prepareform>
            <observers>
                <productnrdiscount>
                    <type>model</type>
                    <class>productnrdiscount/observer</class>
                <method>adminhtmlBlockSalesruleActionsPrepareform</method>
                </productnrdiscount>
            </observers>
            </adminhtml_block_salesrule_actions_prepareform>
        </events>
    </adminhtml>
</config>

As you can see above, there must be an Observer model that will have the two methods which modify the admin and apply the discount.

<?php
/**
 * Number of product discount module
 *
 * @author Claudiu Persoiu http://blog.claudiupersoiu.ro
 */
class CP_ProductNrDiscount_Model_Observer {

    // The new rule type
    const PRODUCT_NR_DISCOUNT = 'product_nr_discount';

    /**
     * Add the new rule type to the admin menu
     *
     * @param Varien_Event_Observer $observer
     */
    public function adminhtmlBlockSalesruleActionsPrepareform
              (Varien_Event_Observer $observer) {
        // Extract the form field
        $field = $observer->getForm()->getElement('simple_action');
        // Extract the field values
        $options = $field->getValues();
        // Add the new value
        $options[] = array(
            'value' => self::PRODUCT_NR_DISCOUNT,
            'label' => 'Product Number Discount'
        );
        // Set the field
        $field->setValues($options);
    }

    /**
     * Apply the discount
     * The discount will be applied for at least 2 products increasing
     * with a "step" for each product, where "step" is
     * maximum discount / number of products.
     *
     * @param Varien_Event_Observer $observer
     */
    public function salesruleValidatorProcess(Varien_Event_Observer $observer) {

        // $item typeof Mage_Sales_Model_Quote_Item
        $item = $observer->getEvent()->getItem();
        // $rule typeof Mage_SalesRule_Model_Rule
        $rule = $observer->getEvent()->getRule();

        // Number of products
        $qty = $item->getQty();

        // We must check the rule type in order to isolate our rule type
        if($rule->getSimpleAction() == self::PRODUCT_NR_DISCOUNT && $qty > 1) {

            // Extract rule details
            $discountAmount = $rule->getDiscountAmount();
            $discountQty = $rule->getDiscountQty();

            // Discount step
            $step = $discountAmount/$discountQty;

            // Discount calculation
            $discount = 0;
            for($i = 1; $i < $qty; $i++) {
                $itemDiscount = $i * $step;
                // If the discount is bigger then the maximum discount
                // then the maximum discount is used
                if($itemDiscount > $discountAmount) {
                    $itemDiscount = $discountAmount;
                }

                $discount += $itemDiscount;
            }
            // Effective discount
            $totalDiscountAmount = ($item->getPrice() * $discount)/100;

            // Discount in percent for each item
            $item->setDiscountPercent($discount / $qty);

            // Setting up the effective discount, basically this is the discount value
            $result = $observer->getResult();
            $result->setDiscountAmount($totalDiscountAmount);
            $result->setBaseDiscountAmount($totalDiscountAmount);

        }
    }

}

This observer will run at each request if there are items in cart that for which the rule is applicable. If the discount should be applied only for specific products, there can be filtered using the rule’s “Conditions” tab, just as you would normally do.

Written by Claudiu Persoiu

8 March 2012 at 9:37 PM

PHP 5.4 was released!

without comments

PHP 5.4 was released!

Even though is already yesterday news… literally, yesterday 1 March was released.

The complete list of changes is available on php.net.

I’m sorry that we still don’t have scalar type hinting in this version. The only change to type hinting was the “callable” word was added, about which I’ve talked in the closure in PHP 5.4  blog.

Another interesting thing is that this time register_globals and magic_quotes_gpc were really removed, so the old PHP 4 apps don’t get to be compatible anymore with the help of a couple of flags in php.ini.

Also the hex2bin() function was added, of course is not that important, but is interesting that the  bin2hex() function existed since PHP 4. 🙂

Written by Claudiu Persoiu

2 March 2012 at 9:43 PM

Posted in PHP

Tagged with , ,

Magento native stack trace

with 5 comments

There are moments when you need to see the stack trace, to know how a certain point was reached. There are two native functions for that in PHP: debug_backtrace() si debug_print_backtrace. The first one returns an array and the second will print the stack trace to the screen.

The problem is that this functions must be customized for Magento, because it is very possible that when you’re running debug_backtrace()  you can run out of memory before you can send the output to a log file.

Magento has a native function for that purpose: Varien_Debug::backtrace([bool $return = false], [bool $html = true], [bool $withArgs = true]). In order to send the resulting stacktrace to a log file you simply all it with:

Mage::log(Varien_Debug::backtrace(true, false));

This technique is very useful when you need to see where an certain object is initialized, and what methods were executed up to that point.

Written by Claudiu Persoiu

25 February 2012 at 11:48 AM

Posted in Magento,PHP

Tagged with , , ,

PHP 5.4 – Closures the right way!

with 5 comments

The concept of closure was introduced in PHP 5.3, with the new “more traditional” syntax for anonymous functions.

PHP 5.3

In PHP 5.3, a closure will rely on the term “use”, which was passing the variables to the anonymous function, making it a closure.

The problem is that the anonymous function will only be able to access the variables that have been passed with “use”. When it comes to objects, there are passed by reference by default, but scalar variables (int, string, etc.) are passed by value, as this is the default behavior in PHP 5+:

$scalar = 5;

$closure = function () use ($scalar) {
     return 'Scalar: ' . $scalar . PHP_EOL;
};

echo $closure(); // Scalar: 5

$scalar = 7;

echo $closure(); // Scalar: 5

Another problem is that you cannot pass $this when the anonymous function is declared inside an object, so only the public method and properties can be accessed inside the closure.

PHP 5.4

In PHP 5.4 the keyword “use” is optional, and the entire environment where the function was created is available inside the function.

The advantage is that when the anonymous function is created inside another function or method, the anonymous function has access to the environment where it was created, even after the execution of the environment is over. The objects from this environment will be unset, only after the last reference to the closure will be unset:

class testClass {

        private $changeableVar = 1;
        private $bigVar;

        public function __construct() {
                // Allocate a big variable so we can see the changes in memory
                $this->bigVar = str_repeat("BigWord", 5000);
        }

        /**
         * A method that returns the closure
         */
        public function closure() {

                return function () {
                        // Display the value of a private property of the object
                        echo 'Private property: ' . $this->changeableVar.PHP_EOL;

                        // Change the value of a private property of the object
                        $this->changeableVar = 2;
                };
        }

        /**
         * Method that displays a private property
         */
        public function showChangeableVar() {
                echo 'Private property in method: ' . $this->changeableVar.PHP_EOL;
        }

}

// Memory befor the objects is created
echo "Memory: " . memory_get_usage() . PHP_EOL; // Memory: 229896

// Create object
$testObj = new testClass();

// Create closure
$closure = $testObj->closure();

// Execute closure
$closure(); // Private property: 1

// Displaying the current value of the private property
$testObj->showChangeableVar(); // Private property in method: 2

// Memory befor object will be unset
echo "Memory: ". memory_get_usage() . PHP_EOL; // Memory: 266240

// Unset the object
unset($testObj);

// Memory after the object was distroyed, there is no big difference in memory
echo "Memory: ". memory_get_usage() . PHP_EOL; // Memory: 266152

// Run closure after the object in which it was created was unset
echo $closure(); // Private property: 2

// Unset closure and with it the object environment
unset($closure);

// Memotry after the las reference to the object (closure) is unset
echo "Memory: " . memory_get_usage() . PHP_EOL; // Memory: 230416

Callable type hinting

Another new feature introduced in PHP 5.4 regarding closures is the new “type hint”: “callable”. Actually callable is referring to any anonymous function, and even to a new way of calling a method of an object:

<?php

// A function that uses type hinting
function typeHinting(callable $a) {
     echo $a() . PHP_EOL;
}

// A closure
$closure = function () {
     return __FUNCTION__;
};

// Call the type hinting function with the closure
typeHinting($closure); // {closure}

class testClass {
     public function testMethod() {
          return __METHOD__;
     }
}

// A mock object
$testObj = new testClass();

// The new way of calling object methods
$objCallable = array($testObj, 'testMethod');

// Call type hinting function with the new method calling way
typeHinting($objCallable); // testClass::testMethod

I believe that only now we can really say that PHP supports closures, the right way!

Written by Claudiu Persoiu

11 February 2012 at 5:10 PM

Posted in PHP

Tagged with , , , ,

Magento dead end – Breadcrumbs

without comments

In one of my adventures in the Magento code. I’ve encountered the following problem: I had to add a link to the breadcrumb.

As the documentation is not so great, after a little debugging (not a lot), I’ve got in to the core Mage_Page_Block_Html_Breadcrumbs.

The method is quite self-explanatory: addCrumb($crumbName, $crumbInfo, $after = false). Since I was there, I took a look inside:

function addCrumb($crumbName, $crumbInfo, $after = false)
{
  $this->_prepareArray($crumbInfo, array('label', 'title', 'link', 'first', 'last', 'readonly'));
  if ((!isset($this->_crumbs[$crumbName])) || (!$this->_crumbs[$crumbName]['readonly'])) {
    $this->_crumbs[$crumbName] = $crumbInfo;
  }
  return $this;
}

What’s interesting is the $after parameter, as you can see, even though it has a default value, is not used anywhere. The rest work’s as expected, probably this is why people don’t complain so much about it.

Written by Claudiu Persoiu

3 February 2012 at 10:03 PM

Posted in Magento,PHP

Tagged with ,

PHP 5.4 Alpha 1 is here!

without comments

Three days ago, that is on 28-06-2011 the PHP 5.4 alfa 1 version was announced on ww.php.net!

Basically in this release are the things that were made for PHP 6 and did not make it in PHP 5.3, next to some other new features.

Some of the most interesting new features are:

Traits

A new OOP feature. Basically for horizontal code reuse, that is inheriting of methods instead of extending classes.

trait Inharitable {
    public function test() {
        echo 'Class: ' . __CLASS__ . ' Method: ' . __METHOD__ . PHP_EOL;
    }
}

class A {
    use Inharitable;
}

class B {
    use Inharitable;
}

$a = new A();
$a->test(); //Class: Inharitable Method: Inharitable::test

$b = new B();
$b->test(); //Class: Inharitable Method: Inharitable::test

Traits in PHP 5.4 are the new namespaces of PHP 5.3, that is the most interesting feature in PHP 5.4.

Scalar type hinting

Up to PHP 5.3 there was type hinting only for classes, interfaces and arrays. With PHP 5.4 type hinting can be used for scalar data types like: int, string, float, book and resource.

function test(string $var) {
  echo $var;
}

$a = 'aa';
test($a);

Unfortunately on this alpha version on my computer I get: Catchable fatal error: Argument 1 passed to test() must be an instance of string, string given, called in .. on line 58 and defined in … on line 52

What can I say… it is still an alpha…

Closures

Yes, I know, there are closures in PHP 5.3 too, but there are not the same. In PHP 5.3 if you wanted a closure you had to use the keyword use and then specify the variables that the lambda functions will have access to.

In PHP 5.4 it’s beginning to look more like JavaScript, in a good way:

class closureTest {

    private $a;

    function test() {
        $this->a = 'object var';
        return function () {
            echo $this->a;
        };
    }
}

$a = new closureTest();
$b = $a->test();
$b(); // object var
unset($a);
$b(); // object var

Closure in the right way, with a lambda function the way it should be! Just like lambda functions existed even before PHP 5.3, but only after the new syntax they’ve become popular, now there was closures time.

This are some of the things that I find most interesting, but there are only a part of the new features that PHP 5.4 brings!

It’s likely that before the end of this year the final version will be ready.

I’m curious if with the final version of PHP 5.4 a new certification will come out, taking in consideration that the changes are not major.

Written by Claudiu Persoiu

1 July 2011 at 8:27 AM