Apparently komposta.net become famous today, who needs google analytics and webmaster tools when you wake up in the morning and u see that ~300 comments have been posted overnight (lol). Since September 2012 ~900 comments have been submitted. Only 14 of them are not spam, 4 of them are mine ;) and 300 were posted yesterday. A month ago i added a honeypot solution to the komposta comments system and it's working great but it's obvious some time limit catch has to be added to prevent this aggressive spam behavior. Some other fan factor they only target posts with popular keywords like twitter and zend.

spamAttack.png

Bots found me pretty fast because i set a redirection from my old site to komposta.net for about 2 months until t3-design.com domain expired. I kinda regret it now...

-----Edit: 12 hours later
It's still on, i wonder what will happen if i turn comments off for these 3-4 targeted posts... Next update tomorrow

spamAttack2.gif

-----Edit12 hours later
Turning commenting off for the targeted posts did the trick, i am gonna turn it back on to see if they gave up...

I 've been to alot of interviews lately and i always promote myself as a php programmer. The truth is i don't like people who fill their resume with a huge list of programming languages just because they happened to use them briefly at some point in their life either as a hobby or as part of their studies. Apparently and as pointed by friends, i am stupid i don't show all aspects of my skills. So here is the very first application i have build which isn't written in php.

Cakebox is an archives manager for optical media. I am a hoarder when it comes to tv series, animes and movies, i don't like to delete stuff and since hdds used (???) to be super expensive i wrote a simple application to easily find cd's/dvd's in mountains of cakeboxes. The application started its life as a Java desktop application named `CakeBox Collector` after the movie `Bone Collector`. Basically it's a database application with categories and entries with title and files list, with search and all the basic crud forms. It used the excellent H2 database and was build upon the swing framework. 

Last year and after 4 years i first started Cakebox i decided to port the application to C# for various reasons. Netbeans dropped support for the swign framework, i was really bored and because i thought the whole task would later help me with mobile applications. So after a slight name change and only about a week later Cavebox was born. I used the very cool alternative to Visual Studio, SharpDevelop and for database i used SQLite and the ADO.Net adapter. I tried to change as little as possible in the UI because i thought it would be cool to see them side by side and i really liked the original compact design. Below there are two animated gifs showing both applications can you spot the differences ;)

cavebox.gif cakebox.gif

I don't want to get into the fight which is better but still I was impressed with the low memory footprint and startup times. Of course there were a few things C# doesn't have and i missed them during the port procedure but there were also a lot of things that made C# much easier to live with. Overall i think both languages have their merits and despite the recent hatred toward Java and Oracle nobody can dispute the fact that pretty much everyone has used or is using with or without their knowledge a device/application working with Java.

Cakebox and Cavebox will find their way into github pretty soon...

Lithium models are very flexible, schema can be lazy loaded by the first call to Model::schema(), unless it has been manually defined in the model subclass. Below there is an example of a model with predefined schema 

class UserGroups extends \lithium\data\Model
{
	protected $_schema = array(
		'id' => array('type' => 'id', 'length' => 10, 'null' => false, 'default' => null),
		'title' => array('type' => 'string', 'length' => 64, 'null' => false, 'default' => null),
		'description' => array('type' => 'string', 'length' => 255, 'null' => false, 'default' => null),
		'admin' => array('type' => 'integer', 'length' => 1, 'null' => false, 'default' => 0),
		'resources' => array('type' => 'string', 'length' => null, 'null' => false, 'default' => null),
	);

	protected $_meta = array(
		'key' => 'id',
		'locked' => true,
		'source' => 'user_groups'
	);
}

If you leave the schema configuration empty,lithium will retrieve the information directly from the data source. Which is nice until you understand that this extra step will be taken every time the model is initialized, which is a no no. That's why I am going to show you how to cache the model's schema. Firstly we need to set up a connection and the cache storage, here is some basic configuration:

use lithium\data\Connections;
use lithium\storage\Cache;

Cache::config(array(
	'default' => array(
		'adapter' => 'File',
		'strategies' => array('Serializer')))
);

Connections::add('default', array(
	'type' => 'database',
	'adapter' => 'MySql',
	'host' => 'localhost',
	'login' => 'root',
	'password' => '',
	'database' => 'database',
	'encoding' => 'UTF-8'
));

You probably have those two already in your application's bootstrap files, here is the piece of code that does the schema caching

Connections::get('default')->applyFilter('describe', function($self, $params, $chain) {
	if(!Environment::is('production')) {
		return $chain->next($self, $params, $chain);
	}

	$key = 'schema_' . md5(serialize($params['meta']));
	if(!$result = Cache::read('default', $key)) {
		$result = $chain->next($self, $params, $chain);
		Cache::write('default', $key, $result, '+1 month');
	}
	return $result;
});

By using Lithium's filters we can hook into the data source describe method to intercept default behavior. Firstly there is a check to skip caching if we are not in production environment. Then the system checks if schema has  already been in cache by using the model's meta as a unique key. If not, we allow the default procedure to run and we write the result to cache. 

Some notes
Recently Lithium's model and pretty much all data classes have been heavily updated, in many cases breaking backward compatibility. One of them is the model schema, when fully initialized is now an object instead of a simple arrray. The above snippet was written for the latest version in the dev branch but it will probably work for previous versions as well.

The best practice when writing a model is to manually define the schema. If you follow this principle I am not sure the above snippet will improve  much your app's performance. Initialize object vs retrieve object from cache. Maybe with a more advance cache adapter like APC???

Let me know how this worked for you!

I have mixed feelings about 2012, it wasn't all bad but it certainly wasn't all fun fun fun. Here are some highlights. Very early i was super happy because after a period of three years of laziness  i was finally through university and i was preparing myself to serve mandatory military the coming spring as every other young male in Greece. Unfortunately the following months until May i had a serious health issue which sent me to hospital a couple of times and my precious 4 months of vacations turned into a very stressful period for me.

Anyway May came and my military service started. I have to admit it was better than i thought, living 9 months with no serious worries except what's for dinner and what's my next work duty isn't bad especially if you consider the alternative, which was looking for a job in the worst possible period in Greece going through the worst part of the economical crisis. Unfortunately that came to an end pretty fast as well as i broke my leg. I guess that was my bad since i am not exactly fit. After 2.5 months i was early discharged from military which some people found fortunate, but then again i couldn't walk at all from early    June to late August, so yeah crutches in summer time in Greece, lucky me. Actually i went to the beach many times for rehabilitation, it's not fun trying to walk with crutches on hot sand barefoot. I guess it was if you were watching me! I almost forgot my favorite moment with crutches, my university graduation ceremony which i would have missed if i hadn't broken my leg. Now try to imagine, a nice summer hot morning me with my crutches trying to climb the stairs to get to the stage to receive my degree. I am laughing my ass off right now but trust me i never felt more uncomfortable in my life.

It was about August 15th when i decided to get up from bed and do some actual work. The result, is what you see komposta.net and komposta cmf. On September i started looking for a job as a web developer. I am still looking if you are wondering. I got a little depressed while doing that, because there are not many job offers for all the demand out there and some of them are complete scam. I remember going for an interview for a PHP Developer and they started asking me if i know Ruby. After a while i politely asked them, if you want someone who knows how to code in Ruby why do you ask for a senior PHP Programmer in the job description. The answer was complete BS and the real reason was that they wanted a programmer who could be trained and of course he could be paid much less than a senior programmer. Even though after the interview i politely denied the offer they kept calling me for days to accept the job. :)

Fortunately i took some freelance works and that's what i have been doing for the last 3 months. It's not much but i am not completely broke and i managed to make it until now. I am sure 2013 will be a much better period for job hunting in Greece, so yeah i am little happy i managed to avoid taking up a job i don't really like but then again i am still living with my parents. Even when i was free i tried to stay busy as much as possible with personal projects like komposta and Sum+my.

2012 was tough for many people around the world, i truly believe next year will be much better. Here is my resolutions for 2013

  1. Advance as a php freelance programmer
  2. Get a job i actually like
  3. Do both 1 & 2
  4. Make komposta.net popular
  5. Publish komposta cmf on github
  6. Travel as much as possible
  7. Combine 8 with an F1 race
  8. Run without fear about my broken leg
  9. Do 6 & 7 again
  10. Improve my writting skills in english (thx a lot for reminding me T4Co!)

 I wish you all a very Happy New Year 2013!!

FMScout: Twitter Spotlight is another project for fmscout.com i recently finished. The purpose of the plugin is to show status updates from multiple twitter users in a quick and fancy way. The plugin is built to work with the new Twitter Api1.1 rate limits and with the proper configuration it's possible to actually show tweets from a big number of accounts without worrying about getting banned from twitter. Currently fmscout.com is only fetching data from ~15 accounts with ~40 to be the ultimate goal but going tripple digits is possible with longer Cache TTL policy.

tweets0.png tweets1.png

It involved a lot of javascript code, and the js plugin is based on JQuery and JsRender to render all the on the fly html code. The tweets appear in multiple tiles which get flipped randomly every x seconds. All tiles and twitter accounts get the same "spotlight" by shuffling them like a deck of cards instead of randomly picking one every time. My javascript was a little rusty and this project was a lot of fun to build and see in action.

Tweets: Twitter Spotlight

  • PHP: Cotonti Plugin
  • Javascript: JQuery Plugin
  • Site: www.fmscout.com
  • Finished in 4 days after the work request

I have already introduced you to this application, and i already told you about the porting process to Zend Framework 2 but that's not all. Since i finished the first version which only worked for Greek documents, i always wanted to add support for the English language and extend it further more.

So after a few weeks of work and research here it is with a brand new name, Sum+my, which stands for Summarization Methodology Yardstick.

summy_home.png summy_admin_documents.png summy_admin_terms.png  

 

Changelog v2.0

  • Brand New Appearance based on Twitter Bootstrap
  • Ported Application to Zend Framework 2.0
  • Added Support for English Language
  • Added Stemmer Test Page
  • Fixed typos in the Greek Stemmer, improved accuracy a lot!
  • Summaries are now cached, to avoid double posting, the links are by no means permanent!

 summy_admin_home.png summy_stemmer_en.png summy_changelog.png

It's probably the work i am most proud because it's so out of my element, so give it a try you might  actually find it a great tool for everyday tasks and let me know if you have any ideas to improve it further or why not start adding support for more languages. For that you might also want to check the docs of the Sum+my

 

I finished yesterday porting Sum+my to zf2, it will be online after some new features and further development. The process wasn't very hard and you don't have to master zf2 before you begin or even to finish the task. There are already a lot of resources about zf2 and to be able to see code from real life applications from the modules.zendframework.com is a huge bonus. In my case it was a very small application with only 5-6 controllers with a few extra controller plugins, acl + auth + the 15 classes based on Zend\Filter, and it took about 5 hours of work, mostly reading and copy/paste.

First of all performance impressions, out of the box with zero optimization, zf2 is a little friendlier on memory but a little worse on speed. The differences are small but noticeable, i can't give you excact numbers cause i couldn't bother with extensive tests so take my opinion or leave it.

Secondly some tips:

  1. If you are building multi-modular applications avoid doublicate configurations, otherwise you will often be stuck wondering why some changes don't take effect.
  2. The code hasn't changed that much, zf2 hasn't been rewritten from scratch with a few exceptions, so you will often end up wondering what's up with all the fuss about zf2 being hard to start with 
    $error = false;
    $return = $this->params()->fromQuery('return');
    if($this->getRequest()->isPost())
    {
    	$username = $this->params()->fromPost('username');
    	$password = $this->params()->fromPost('password');
    	$return = $this->params()->fromPost('return');
    
    	if($username != '' AND $password != '')
    	{
    		$adapter = $auth->getAdapter();
    		$adapter->setIdentity($username)
    				->setCredential(hash('SHA256', $password));
    
    		$result = $adapter->authenticate();
    		if($result->isValid())
    		{
    			$auth->getStorage()->write($adapter->getResultRowObject(null, 'password'));
    			if($return)
    			{
    				return $this->redirect()->toUrl(base64_decode($return));
    			}
    			return $this->redirect()->toRoute('default', array('controller' => 'index', 'action' => 'index'));
    		}
    	}
    	$error = true;
    }
    

    zf2 vs zf1

    if($this->getRequest()->isPost())
    {
    	$username = $this->_request->getParam('username');
    	$password = $this->_request->getParam('password');
    
    	if($username != '' AND $password != '')
    	{
    		$adapter = new Zend_Auth_Adapter_DbTable(Zend_Db_Table::getDefaultAdapter());
    		$adapter->setTableName('user')
    				->setIdentityColumn('username')
    				->setCredentialColumn('password')
    				->setIdentity($username)
    				->setCredential(hash('SHA256', $password));
    
    		$auth = Zend_Auth::getInstance();
    		$result = $auth->authenticate($adapter);
    		if($result->isValid())
    		{
    			$auth->getStorage()->write($adapter->getResultRowObject(null, 'password'));
    			$returnUri = $this->_getParam('returnUri');
    			$this->_helper->redirector->gotoUrlAndExit($returnUri);
    		}
    	}
    	$this->view->loginFailed = true;
    	$this->view->returnUri = $this->_getParam('returnUri');
    }
  3. The default route you will find in the skeleton app is very basic, so to at least achieve the main function of zf1 default route /controller/action/id use the bellow route, it also supports extra query params, if you call the url helper with route name 'default/query'
    'default' => array(
    	'type' => 'Segment',
    	'options' => array(
    		'route' => '/[:controller[/:action]][/:id]',
    		'constraints' => array(
    			'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
    			'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
    			'id' => '([0-9]+)?'
    		),
    		'defaults' => array(
    			'__NAMESPACE__' => 'Application\Controller',
    			'controller' => 'Application\Controller\Index',
    			'action' => 'index',
    			'id' => false
    		),
    	),
    	'may_terminate' => true,
    	'child_routes' => array(
    		'query' => array(
    			'type' => 'Query',
    		),
    	),
    ),
  4. If you stepped on a bug there is a good possibility you are not the first one to discover it, check the zf2 github as much as possible.
  5. Use the zf2 classmap generator to make autoloading a hell of a lot faster.

 

That's all for now, i will continue posting about ZF2, my opinion about it has improved a lot since i started porting one of my old zf1 applications and check back maybe i will start posting some very interesting tutorials about Zend Framework 2

 

fmsdb.png

FM Social scouting aka codename FMSDB was a project i did almost 18 months ago for fmscout.com but never went live for legal reasons. All the difficulties and delays are finally over and it will go public hopefully this week. FMSDB is practically a database for football (soccer) players and clubs based on the video game Football Manager. Except all the personal information and game statistics every profile page has comments and ratings support hence Social Scouting and photo galleries as well. Until the project goes officially live that's all i can say but here is a couple of screenshots. The project is live you can check it online www.fmscout.com/players.html

 fmsdb_player_search.png fmsdb_player_profile.png

The application is build as a module for Cotonti cms, it involved mostly php/mysql code and data mining which is something i always like. Originally image galleries were hosted by imageshack but since last year they changed their policy and galleries had to be rewritten from scratch, talk about snafu right ? that's one piece of code i won't be reusing any time soon. ;p The past few weeks we also did the beta testing and small fine-tuning a year overdue.

Day number two of porting this application to zend framework 2. I only had a couple of hours today but still i have a couple of things i actually want to talk about. I keep encountering things that are not that much different from ZF1 like Zend\Navigation or Zend\Paginator. I was quite surprised i got them working in seconds.

In the app i have a paginated list of documents, and below is how the code changed:

Zend Framework 1

$db = Zend_Db_Table_Abstract::getDefaultAdapter();
$select = $db->select()->from('document', $orders)->order(array("$order $way"));
$paginator = Zend_Paginator::factory($select);
$paginator->setDefaultItemCountPerPage($perpage);
$paginator->setCurrentPageNumber($this->_getParam('page'));

Zend Framework 2

$db = $this->getServiceLocator()->get('db');
$select = new Select('document');
$select->columns($orders)->order("$order $way");
$paginator = new Paginator(new DbSelect($select, $db));
$paginator->setDefaultItemCountPerPage($perpage);
$paginator->setCurrentPageNumber($page);

 

 Which if you exclude all the Use Statements you have to add on top it's not bad, i actually think it pretty much the same. It would be nice to be able to get the Select object from the adapter but it's not a big deal. The second thing of the day was how actively the ZF2 is developed. I found a couple bugs today working with v2.0.3. The most important was with the Zend\Mvc\Router\Http\Query which was adding the controller, action and namespace parameters to the query string, instead of only adding the extra parameters it was receiving. But guess what download the latest version from github and voila bugs are gone. (Lithium are you there... ;p). That really made my day, i make it a habit not following popular trends or rooting for the underdogs, see my history. I started learning php with LDU cms probably the most unkown cms of all and now choosing Lithium for Komposta Core instead of one of the most popular frameworks like Zend or Symphone or CakePHP for pete sake. So it felt great to go from the disappointing moment  of finding a bug to see that i was fixed in a minute. People are whining how much ZF2 changed and that it got a bit Java-ish but today at least, in my mind ZF2 will succeed because of the active developers and contributors.

zf2.pngI 've been following zf2 from the very first beta versions mainly reading presentations, tutorials and occasionally i browsed the code especially the skeleton application to see how the project progressed. So far i wasn't very impressed with it, the common view as i understand it is that it's not quite there yet and that it needs to be refined more before people really start to jump in and port their old applications to the new framework.

Today thought i started porting my BA thesis application from ZF1 to ZF2 as i plan to extend it  and add new features. The application consists of 5 controllers, a few plugins/helpers and the main engine that produces automatic summarization for Greek language which is a bunch of filters also written in ZF1. Beside that there are Users and Administration systems in place to easily manage the internal data.

I actually managed to accomplice more than i thought for day one. I got the front-end controllers and the summarization engine working with ZF2 quite easily. But still some things really bothered me. The most annoying thing of the day is the new Zend\Db it's obvious that they tried to enforce the Model part of the new MVC concept and it's not there not by a mile not when you have to inject every custom model with the TableGetAway which has to also be injected with the Db\Adapter.  

class Module
{
    // getAutoloaderConfig() and getConfig() methods here

    // Add this method:
    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'Album\Model\AlbumTable' =>  function($sm) {
                    $tableGateway = $sm->get('AlbumTableGateway');
                    $table = new AlbumTable($tableGateway);
                    return $table;
                },
                'AlbumTableGateway' => function ($sm) {
                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                    $resultSetPrototype = new ResultSet();
                    $resultSetPrototype->setArrayObjectPrototype(new Album());
                    return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
                },
            ),
        );
    }
}

I am pretty sure there is a smarter way to go that people already use in their modules but that official example is a joke. In my case there are about 4 mysql tables and in the current code base so i didn't bother with models since the system is quite predictable about future features and queries so i prefered the direct approach, here is an example of ZF1 vs ZF2 for running raw queries.

 Zend Framework 1.11

$db = Zend_Db_Table::getDefaultAdapter();
$docu = $db->fetchOne("SELECT COUNT(*) as unprocessed FROM document WHERE processed = 0");

Zend Framework 2.0.3

$db = $this->getServiceLocator()->get('db');
list($docu) = $db->query("SELECT COUNT(*) as total FROM document WHERE processed = 0")->execute()->current();

So my first day wasn't very positive. It was easy to port basic stuff and start working but on the other hand i am not seeing many advantages so far. Keep in touch as i will post daily about my experience with zf2.