SpinOneSolutions | I waste my time so that you don't have to…

Jan/11

31

Magento Admin Form POST with form_key

The other day I was trying to help someone create a Form in the admin side of Magento that would simply POST to a Controller and capture some data. I thought it’d be fairly simple, I’ve done it before; I thought.

Turns out I had done it before, but I’ve always used the built in Magento Form widgets, never specified a custom .phtml template and actually tried to write the Form code by hand. It’s a little more tricky than I anticipated, but we struggled through it and finally found the catch.

The “catch”, as it were, is that you have to send a hidden “form_key”. This lets Magento know that you are who you say you are and not some spoofer posting malicious code to your backend.  Let’s get started.

Let’s presume that I’ve got a Module Spinonesolutions_Helloworld in it I’m going to make a block:

/app/code/local/Spinonesolutions/Helloworld/Block/Adminhtml/Adminform.php

class Spinonesolutions_Helloworld_Block_Adminhtml_Adminform extends Mage_Adminhtml_Block_Template {
public function __construct() {
    parent::__construct();
    $this->setTemplate('helloworld/form.phtml');
    $this->setFormAction(Mage::getUrl('*/*/new'));
  }
}

It’s easily seen that I’m referencing a .phtml template within my Block for the presentation so let’s make that file as well:

/app/design/adminhtml/default/default/template/hellworld/form.phtml

<form action="<? echo $this->getFormAction(); ?>" method="POST">
<input type="text" id="var1" name="var1" />
<input type="submit" id="submit" name="submit" />
</form>

Lastly we need a Controller to handle the POST and to render our Block:

/app/code/local/Spinonesolutions/Helloworld/controllers/Adminhtml/AdminformController.php

class Spinonesolutions_Helloworld_Adminhtml_AdminformController extends Mage_Adminhtml_Controller_Action {

public function indexAction() {
  $this->loadLayout();
  $block = $this->getLayout()->createBlock('spinonesolutions_helloworld/adminhtml_adminform','admin_form');
  $this->getLayout()->getBlock('content')->append($block);
  $this->renderLayout();
}

public function newAction() {
  die('here I am!');
}
}

OK, that’s it for the architecture.  Let’s wire it all up with some XML in config.xml.  Note this is partial, not a full module definition:

<blocks>
<spinonesolutions_helloworld>
<class>Spinonesolutions_Helloworld_Block</class>
</spinonesolutions_helloworld>
</blocks>
<admin>
<routers>

<adminhtml>
<args>
<modules>
<Spinonesolutions_Helloworld before="Mage_Adminhtml">Spinonesolutions_Helloworld_Adminhtml</Spinonesolutions_Helloworld>
</modules>
</args>
</adminhtml>
</routers>
</admin>

Now, if you visit */admin/adminform/index you should see your super simple Form.  If you hit submit your Form will certainly post, but instead of seeing the die output you’ll be redirected to the Dashboard.  This because we haven’t sent through the authentication required by Magento’s internal routing system that will validate our form.  Let’s change form.phtml so that we can POST successfully.

<form action="<? echo $this->getFormAction(); ?>" method="POST">
<input type="hidden" name="form_key" value="<? echo $this->getFormKey(); ?>" />
<input type="text" id="var1" name="var1" />
<input type="submit" id="submit" name="submit" />
</form>

That’s all there is to it!  Notice the “form_key” hidden variable.  That’s the key to submitting Forms in the Magento admin.

· · ·

Jan/11

28

Drupal sess_read() causes logout

Affects: Drupal 6.20

If you try to read a value from a session that has not been set your Drupal user will be logged out.

Example:

sess_write('myValue',TRUE);
echo sess_read('myValue');

OK

echo sess_read('myValue');

NOT OK, user is logged out.

Sometimes, you’ve got a situation where you want to have a globally available static function.  Most often this occurs (for me) in a debugging context.  Recently I wanted to have FirePHP available from anywhere in my project so I made use of the lib folder.

Unlike just about every other article on this site, for this one we’re going to be considering the folder /lib.  Note that this folder is NOT within local, but resident in the root.  As such changes here should be put within their own sub-folders so that they too will survive an upgrade.

It’s really quite easy to create your class, just follow the usual Magento naming conventions. I’m going to create Spinonesolutions_Devel_FirePHP so all I do is create the file: /lib/Spinonesolutions/Devel/FirePHP.php.  Note the similarity to Model naming.

In here I create my class definition:

<?php
class Spinonesolutions_Devel_FirePHP {
  public static function send($var, $label = "DEBUG", $style = "LOG") {
    if (Mage::getIsDeveloperMode()) {
      $request = new Zend_Controller_Request_Http();
      $response = new Zend_Controller_Response_Http();
      $channel = Zend_Wildfire_Channel_HttpHeaders::getInstance();
      $channel->setRequest($request);
      $channel->setResponse($response);

      /*
      * Start output buffering
      */
      ob_start();

      Zend_Wildfire_Plugin_FirePhp::send($var, $label, $style);

      /*
      Style     Description
      LOG     Displays a plain log message
      INFO     Displays an info log message
      WARN     Displays a warning log message
      ERROR     Displays an error log message that increments Firebug?s error count
      TRACE     Displays a log message with an expandable stack trace
      EXCEPTION     Displays an error long message with an expandable stack trace
      TABLE     Displays a log message with an expandable table
      */

      /*
      * Flush log data to browser
      */
      $channel->flush();
      $response->sendHeaders();
    } else {
      return null;
    }
  }
}

Now I can call Spinonesolutions_Devel_FirePHP:send() anywhere in my project.  Sweet!

· · ·

Dec/10

22

The List of Awesome

Dec/10

15

Magento config.xml Cron Job

It’s possible to setup process to run on a schedule provided that your server is setup to run cron. All internal cron jobs are run from a single page/script call. You’ll need to setup your server to either; make a request to /cron.php or execute /cron.sh.

The time delta that you set here will be the minimum delta for your Magento jobs.  IE: If your server’s cron  requests /cron.php every ten minutes and you create a cron job within Magento to run every five minutes, you shouldn’t be surprised to see it running every ten minutes instead of every five.

This won’t be a huge deal for all of you who are administering your own box, but for those of you on a shared box; you’ll likely be limited to a certain minimum delta which you’ll want to be aware of.

Setting up a cron job is actually really simple so lets take a look.  The configuration lives in config.xml, which shouldn’t be a surprise for you module developers.  Using my default example module Spinonesolutions_Helloworld:

/app/code/local/Spinonesolutions/Helloworld/etc/config.xml (partial)

<config>
...
<crontab>
<jobs>
<spinonesolutions_helloworld>
<schedule><cron_expr>*/10 * * * *</cron_expr></schedule>
<run><model>spinonesolutions_helloworld/observer::foobar</model></run>
</spinonesolutions_helloworld>
</jobs>
</crontab>
...
</config>

You can do a Google search on cron schedules in order to figure that part out, it’s outside the scope of this article.  The only other piece that deserves explanation is the static method call between the run tag.  As you’d expect my example call is referencing Spinonesolutions_Helloworld_Model_Observer (/app/code/local/Spinonesolutions/Helloworld/Model/Observer.php). This file doesn’t need to contain anything except for a class definition and a static method.

/app/code/local/Spinonesolutions/Helloworld/Observer.php

<?php
class Spinonesolutions_Helloworld_Model_Observer {
  public static function foobar() {
  }
}

That’s it.  Your static method will now be called on the schedule that you set!

· ·

Older posts >>

Theme Design by devolux.nh2.me