Versioning. For lazy people.

I am a pretty lazy guy and therefore I want to do all things with as little trouble as possible. Usually , I don’t plan a certain methodology for my projects, instead , I use an organic approach. If things are needed, they will be added to my ‘methodology’.

One of the most important issues for me is versioning . It doesn’t matter whether you are using svn , git , or whatever, it’s only important to be able to version via tags ( I use tags) or other mechanisms .

When you work from time to time on a particular project, you will certainly loose track of what you do and you will probably forget most of your code.   For me it’s important to know the differences between versions, even if I don’t plan them.

The standard versioning system is composed of 3 digits : like x.y.z . Most of the people think these numbers are random , or incremental , but they are not. For example if product A has the version 1.1.0 and the next version is 1.1.1 , i will know that some bugs have been fixed.  A changelog will  further detail this . If the next version will be 1.2.0 I know that some new features will be added to the product. If the new version will be 2.0 I know product A will go trough major changes and most of the base code will be rewritten and improved (also means backwards compatibility is broken).  And finally , if product A is versioned 0.y.z , I will know that the product is not considered ready yet.

How do I use this in my projects?

If I work on small things , bug related stuff, I will increase the minor ( z) . So from 0.1.0 I will go to 0.1.2 .

If I add new features, I will increase the middle digit (y). So from 0.1.0 I will go to 0.2.0 .

If I finish a first stable and complete version, I will go from 0.1.0 to 1.0.0 .

At deploy

Let’s say my current version is 0.1.2 and  the new version is 0.2.0 . My site being www.example.com , I find it convenient to create the following subdomains : sandbox and history.

First , I will place the new version ,  0.2.0 in the sandbox environment. All the testing will be done there. If everything looks ok,  example.com  contents  will move to history, and sandbox will move to the live site, example. com

So at this point, the environments will be as follow:

example.com - 0.2.0
sandbox.example.com - 0.2.0
history.example.com  -  0.1.2

If anything goes wrong , I will easily revert example.com to 0.1.2 , using the history environment.

Having versioning in place , allows you to see all the changes that took place in time , and also provide snapshot of your application from the past.  If you provide meaningful description to your commits, you will be able to generate a nice automated text that will build your changelog.

Hope this helps.

Using a decorator for caching purposes

In my previous post I  gave some examples on  how caching can evolve.   However , what annoys  me in the  second and third approach is that I have some extra code and  dependencies  which are not really related to my class.  The examples bellow detail how you can use a decorator to cache another class.

class Foo
{
    public function getExpensiveData()
    {
        return 1;
    }
 
    public function getNotSoExpensiveData()
    {
        return 0;
    }
 
    public function getUnbelievableExpensiveData($param)
    {
        //no hardware in the world can scale this
        sleep(1000);
        return 'string';
    }
} 
 
class Foo_Decorator_Exception extends Exception{};
 
class Foo_Decorator
{
    private $source = null;
 
    public function __construct(Foo $foo)
    {
        $this->source = $foo;
    }
 
    public function __call($method , $args)
    {
        $tag    = $method.serialize($args);
        $result = null;
        switch($method) {
            case 'getUnbelievableExpensiveData':
            case 'getExpensiveData':
                if ( !Cache::isCached($tag)) {
                    Cache::save( $this->_call($method , $args),$tag );
                }
 
                $result = Cache::load($tag);
                break;
            default :
                $result = $this->_call($method , $args);
                break;
 
        }
 
        return $result;
    }
 
    private function _call($method, $args)
    {
        if ( !is_object($this->source) ){
            throw new Foo_Exception("No delegate object set");
        }
 
        $delegate        = $this->source;
        $method_variable = array($delegate, $method);
        $callableName    = "";
 
        if ( is_callable( $method_variable, false, $callableName )){
            call_user_func_array($method_variable, $args);
        } else {
            throw new Foo_Exception("Function missing in both decorate and delegate object");
        }
 
    }
}

Three simple php caching tehniques

No talking . Just examples

class Foo
{
    private static $_bar = null;

    private function getBar()
    {
        if ( null == self::$_bar) {
            //very expensive operation
            self::$bar = $this->expensiveOperation();
        }

        return self::$bar;
    }

    private function expensiveOperation()
    {
        return 1+1;//wow
    }
}

Extending the example

class Foo
{
    private function getBar()
    {
        if ( !this->isCached()) {
            //very expensive operation
            $this->saveCache($this->expensiveOperation);
        }

        return $this->getCache();
    }

    protected function saveCache($value)
    {
        file_put_contents($this->getCachePath(),$value);
    }

    protected function getCache()
    {
        return file_get_contents($this->getCachePath());
    }

    protected function isCached()
    {
        return is_file($this->getCachePath());
    }

    private function getCachePath()
    {
        return '/path/to/somefile.txt';
    }
    private function expensiveOperation()
    {
        return 1+1;//wow
    }
}

Final example

class Cache
{
    public static function isCached($tag)
    {
        return is_file(self::isFile(self::getCacheFile($tag)));
    }

    public static function save($value , $tag)
    {

        $file = self::getCacheFile($tag);
        file_put_contents($file , $value);
    }

    public static function load( $tag)
    {
        $file = self::getCacheFile($tag);
        return file_get_contents($file);
    }

    private static function getCachePath($tag)
    {
        return "/path/to/somefile_$tag.txt";
    }
}

class Foo
{
    public static function getBar()
    {
       if ( !Cache::isCached('my_tag')) {
            //very expensive operation
            Cache::save($this->expensiveOperation(),'my_tag');
        }
        return $this->load('my_tag');
    }

    private function expensiveOperation()
    {
        return 1+1;//wow
    }
}

All three examples are variations of the same technique.
Of course , the  file_get_contents thing is used for the example's sake only

A short look on nwire

nwire is a new eclipse for extension, and it allows you to  explore your code.  When I say explore , I really mean explore. It’s not a static stuff where you watch a diagram.  More about this in the youtube presentations .

This is a must have extension for devs who do a lot of refactoring , as you can see everything , including what uses or changes a variable , which in softwares like wordpress is a bless. Some pics bellow.

Notice: Indirect modification of overloaded property ..

You get this because you have the __get method set up , and you are trying to access an array that is not declared.

class a {
 //      private $stuff = array();
 public function foo()
 {
     $this->stuff['asd'] = 'foo';
 }

 public function __get($name)
 {
     return null;
 }
$a = new a();
$a->foo();

The above code will result in :

Notice:  Indirect modification of overloaded property a::$stuff has no effect

I think this happens only for 5.2.x . More details here.

I encountered this bug while refactoring a set of classes. The property got lost from the parent , who had a __get method set , and was called from the child class.

Uploading a image in php with curl

In the latest years we (php programmers) have spent a lot of time  behind classes and frameworks ,  making all our repetitive tasks available in simple and understandable forms like :

$image = new Image('/var/www/image.jpg');
$image->upload('http://www.somesite.com/upload.php');

However , when the Image class can not be used ,  most of use will google for  “how to upload an image with php curl”.

The following snippet of code can be used to upload a image:

$url = 'http://somesite.com/upload.php;
$file = 'image.jpg';
$curl  = curl_init($url);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POSTFIELDS,
             array('image' => "@$file;type=image;type=image/jpeg"));
$resp = curl_exec($curl);

Note the @ before the file. It will extract the binary contents of file , so be wary of your php memory limit.

Adding custom admin config options in Magento

I had  a problem   related to the admin configuration options in Magento. (not 100% resolved yet) .  It took me  some time to figure it out.  To have your magento module add it’s own configuration options in the sytem area , there are (theoretically) some simple steps to follow. However , I obtained the access denied screen when I tried to view the configuration options. If you have caching enabled, you will only get a blank screen. (How cool is that?)

One quick solution is to go to Magento->System->Roles , edit the Administrator group and set the permissions to All again.  Searching for a bug  related to this problem , I have found that the solution is allready posted here , so I’ll skip the rest of the details. Be sure NOT TO uncheck all the permissions and then save, or you  will not have to edit the database to restore your permissions  ( How cool is that? A store owner has to pay a programmer to fix the mess if he screws permissions).

If you accidentally found my post while trying to discover how you can create custom admin config options in Magento,  you can download a blank magento module (description here ), which can be used as a template for your admin configuration options.  Be adivsed that it still has the above mentioned problem.

K.

Some integration plugins are pure crap

I recently stumbled uppon a Wordpress integration plugin for Magento , which was actually hosted on Magento main site. The plugin required both Mangento and Wordpress to be edited. Which is crap. That’s not a wordpress integration, that’s wordpress hackintegration .

Because both Magento and Wordpress have to be edited, neither can be upgraded anymore. And because you actually include and run Wordpress code for each Magento request , a Wordpress error will stop Magento from working.

And finally , wordpress content is only included and displayed within mangento , but not integrated.

Such lame plugins should never be posted.

Kman , one step closer to a release

Warning: Bad English , proceed with caution

KMan started as a toy for one of my personal projects. What I needed was something that could read rss feeds and notify me when something interesting shows up. In time , I also wanted him to learn from the feeds. For example , kman reads feeds and after a while I ask him about mvc, and he sums up some facts. The bot should also direct me to various sources of information based on some keywords(mvc for examle) . The implementation evolved, and now you can implement various applications based on it.

Potential – Sample Applications

This bot is not just about fun , it’s intended to be useful. For example , suppose you have an internal jabber server. You can customize this bot to the extent that your team can log the progress without the web browser or get a list of available tasks , etc. This can be easly be implemented using commands(which are described later).

Another example , if your computer is behind a firewall ,you can control it via a bot connected to a gmail account(of course ,you have to be careful so that it will listen only to you). You can also index your documents , movies , etc and query the bot for them (using Lucene or something like that)

And , as I stated allready ,you can create an application that monitors some rss feeds and announces you when new feeds are available. Before reading them , you will be able to ask the bot few things about the posts and decide if the post is worth reading. This feature is not complete yet, but you can get a glimpse of it as described later.

How can the bot be used like this?(Key Features)

Megahal

First of all ( in time it will be the least important) it will be provide a 100% megahal implementation. For the moment , it provides only a partial implementation.

Megahal implementations are based on Markov chains (math stuff),which enable you to generate content based on previously parsed content. For example , if megahal encountered the word A followed by the word B , and at some point , the word B followed by the word C , it will be able to generate A B C , or A B, or B C. Being based on math , rather than on rules , it’s language independent.

Here is an example after feeding the bot with two wiki pages related to aliens,predators and leonidas:


A trio of Predators seen aboard their spacecraft  is available  under the
assumption that Leonidas gave the Predator's face, as shown in Predator.

Here is what you can get by feeding the bot with an irc log and some dune quotes and then providing a keyword that will be the base for the generated responses:


you>feed http://en.wikiquote.org/wiki/Dune
kman>Mmmmm , that was good
you>feed http://www.irclog.org/freenode/php/2006-05-10/page1.html
kman>Mmmmm , that was good
you>CMS
kman>There is no substitute  on CMS' s 'try to remember,
there is no substitute for intelligence.
you>CMS
kman>Seeing this and telling of it, he made the audacious leap  based CMS
for editing and maintaining around 50 pages, with support for password
protected areas, printer friendly versions
of all was the price we paid was the basic
trust that he made the audacious leap of decision.

A final example , here is what I can get after feeding the bot with my homepage:


Php Megahal
you>feed http://www.webuml.com
kman>Mmmmm , that was good
you>webuml
kman>You can find here my blog ,some  experiments (various tests that i do for
 personal use) and most of the intersting stuff i found on the net and became
 part of my never ending training, which covers:
PHP5 Zend Framework Adobe Flex More Links     2007 webuml .
you>blog
kman>Until then , this site will act as my  my blog , some  experiments (various
 tests that i do for personal use) and most of the intersting stuff i found on
the net and became part of my never ending training, which covers: PHP5 Zend
 Framework Php Frameworks(in general) OOP/OOD Until time will allow me to focus
 on webuml, this site will act as my personal site.

In the future , I will have a Term Extractor that will tie your sentence with the next response, right now I am using random stuff : “What can you tell me about CMS?” can generate sentences based on any word from the question. The Term Extractor will be based on Markov Chains as well , so it can be used in any language. This will be a key feature for previewing your rss feeds via your bot.

Flexibility

Megahal is not everything about this bot , there will be several other ‘brains’(infobots are scheduled) available or combinations. You will be able to use any of them , under any supported protocol. Here is how you can setup a cli bot:


$kman  = new Kman_Communicator_Cli();
$brain = new Kman_Megahal_Brain();
$kman->setBrain($brain);
$command = new Kman_Communicator_Command_Demo();
$kman->addCommand($command);

We will talk about commands later , for now here is how you would setup a gmail bot:


$kman = new Kman_Communicator_Xmpp('talk.google.com', 5222, 'user',
'password', 'xmpphp', 'gmail.com');
$command = new Kman_Communicator_Command_Demo();
$kman->addCommand($command);
$command = new Kman_Communicator_Command_Say();
$kman->addCommand($command);
$megahal = new Kman_Megahal_Brain();
$kman->setBrain($megahal);
$kman->connect();

As you can figure , it doesn’t matter what kind of protocol or brain you are using, you can achieve several results by using the same code base. You can build several different bots while sharing some of the code.

Extensibility

You can customize or add new features to the bot without having to know about how all is made. You have seen in the previous snippets something about a command, here is what say command does:


Php Megahal
you>say moo
kman>moo

and here is how it is implemented:


class Kman_Communicator_Command_Say implements SplObserver
{
    public function update(SplSubject $subject)
    {
        $message  = trim($subject->getMessage());
        if(!strpos($message," ")) {
            return;
        }
        list($command,$what) = explode(' ',$message);
        if($command == 'say')
            $subject->setResponse($what);
    }
}

You will receive something that implements the SPLSubject interface. As a side note , this tehnique is a design pattern , called the Observer Pattern, and you can read about it here. The full interface will be available in the future , but right now , I don’t want extensions to be strongly coupled to my code(even my own).

If you haven’t figured it already, whenever Kman receives a message , your command will be called and you can do whatever you want there , based on the received message or other factors.

So far, you have seen that you can use cli and xmpp. You can add any other protocols you may desire, and the bot will work the same . To do this , you have to extend an abstract class, called Kman_Communicator_Abstract , or you can implement something from scratch (You can use Kman_Communicator_Interface as a guideline or better , implement it.) Here is how the cli engine is implemented:


class Kman_Communicator_Cli extends Kman_Communicator_Abstract
{

    public function connect()
    {
        $handler = fopen("php://stdin","r");
        $message = "Hello";
        echo "Php Megahal ";
        $bye     = null;
        while ($message != $bye) {
            echo "you>";
            $message  = fgets($handler);

            $response = $this->getResponse($message);

            if($response) {
                $this->send($response);
            } else {
                $this->send('moo moo baa baa , me stupid');
            }

        }
    }

    protected function send($message)
    {
        echo 'kman>',$message ;
    }
}

Not so difficult , is it? In the future(next weekend perhaps) , I will also hook the irc protocol.

How can you get the code

svn checkout http://kman.googlecode.com/svn/trunk/ kman-read-only

There is no documentation at the moment, only some examples found in the scripts directory. The API is subject to changes(until the first release) , but not major changes. The project uses some code from Zend_Framework, New Bsd License and xmpphp, which is under GNU License.

That’s it for now, I will come back with 0.1 .