Titon

For the past few years I've been working on a project called Titon — a PHP framework and a front-end library built on MooTools. Titon refers to anything back-end related as the "Framework", while anything front-end related as the "Toolkit". The Framework isn't full-stack in the modern sense, it's simply a collection of packages that can be installed through Composer. The Toolkit is a collection of modular UI classes and helpers written in HTML5, CSS3, Sass and MooTools 1.4.

A brief history

I started writing Titon back in September 2009, around the same time PHP 5.3 was released. The idea behind Titon was simply a learning lesson. It gave me a chance to learn namespaces, closures and all the new PHP functionality. It also permitted me to write systems I would never really write, like database abstraction layers, object relational mappers, caching and storage engines, internationalization and localization, routing, so on and so forth. It was also a great learning lesson on how to properly use interfaces and abstraction classes, while also practicing design patterns and improving with design principles like DRY, KISS, YAGNI, and many others.

Over the course of 3 years, the Titon codebase evolved into a fully fledged framework (albeit not 100% runnable). The architecture was rewritten about 3-4 times as I would try new, different and unique approaches. Classes and interfaces came and went. Functionality was stripped (YAGNI) or dumbed down (KISS). Features were completed or backlogged. Roadmaps were created and abruptly forgotten about. Writing a full-stack framework took time and eventually I stopped working on it many months at a time.

It was around 2012 when I jumped back onto Titon. With the recent release of PHP 5.4 and the ever increasing usage of Composer, it felt like the perfect time. Instead of building a full-stack framework (because do we really need another framework) like before, I decided to break it down into multiple smaller packages that can be installed through the Composer. This would encourage usability, promote decoupling and not require a developer to use a heavy framework for certain functionality. Over the course of the next year, I broke it down into 15 primary packages and 4 supporting packages.

Why am I releasing it?

Even though it was a learning lesson, these packages could still be beneficial to someone (or even you), hence the release. I don't expect Titon to compete with Symfony, CakePHP, Zend, or the many other frameworks, nor do I care. If a packages solves a problem you have, then perfect, go ahead and use it! If a package or Titon as a whole is never used, I won't mind either way. In the end, it taught me everything I currently know, and I couldn't be happier.

What are the Framework packages?

Like previously mentioned, Titon is decoupled into 15 primary packages and 4 supporting packages. A primary package is a collection of classes that provide functionality for a specific feature, for example, a model layer, route mapper, or caching engine. A supporting package is an optional dependency for primary packages that include additional functionality, for example, the MySQL driver for the Model package.

The following packages are available, fully functional and tested. They are split between PHP 5.3 and 5.4, as there was no reason to limit simplistic packages to 5.4 only.

PHP 5.3
  • Debug - Provides logging, debugging and advanced error and exception handling
  • Environment - Allows for multiple environment configuration and bootstrapping
  • Event - Notifies a list of objects during an event and allows for listener registration
  • Type - Implements class like functionality for arrays, strings, objects and enums
  • Utility - Provides convenience classes for basic tasks like validation, formatting, sanitization and more
PHP 5.4
  • Cache - Provides a data caching layer that supports multiple storage engines
  • Common - Provides global functionality like class traits and augmentation as well as dependency and configuration management
  • Controller - Provides controllers that handle the HTTP dispatch cycle and are loosely coupled with other packages
  • G11n - Implements localization and internationalization through message and locale bundles
  • HTTP - Provides classes for interacting with sessions, cookies and the request and response
  • IO - Permits file system manipulation through readers, writers and resource bundles
  • Model - Implements a lightweight database abstraction layer and an object relational mapper
    • MySQL - Enables the MySQL database driver
    • PostgreSQL - Enables the PostgreSQL database driver
    • SQLite - Enables the SQLite database driver
    • MongoDB - Enables the MongoDB database driver
  • MVC - Bundles the Model, View and Controller packages while adding support for dispatching and modularization
  • Route - Provides dynamic route handling, matching and mapping
  • View - Allows for template look-up and rendering through engines and helpers
What about the Toolkit?

The Toolkit is a collection of JavaScript classes and CSS modules known as components. Each component provides front-end functionality, like modals, tooltips and buttons. But doesn't this compete with Twitter bootstrap? In a sense yes, however, there are some major differences. The first being that Toolkit uses MooTools instead of jQuery (if you're one of the rare developers like me who don't like jQuery). The second being that Toolkit doesn't provide default styles like Bootstrap, it merely provides the functionality. This allows the developer – you – to integrate and customize the components at will.

The following components are currently available. Each component is either purely CSS or a combination of CSS and JavaScript.

JavaScript
  • Accordion - Provides collapsible support to a list of sections
  • Blackout - Displays a transparent black element over the document
  • Cache - Provides local and session storage within the class layer
  • Flyout - Displays nested flyout menus that appear below an element that activates it
  • LazyLoad - Provides an easy way to lazy-load images (inline and background) while scrolling
  • Modal - Displays dynamic modals that will display above the content
  • Pin - Pin an element in a container that stays within the viewport while scrolling
  • Popover - Displays dynamic notification elements over an element
  • Tabs - Provides tabbed support to an element containing navigation tabs and sections
  • Timers - Provides timer and interval management within the class layer
  • Tooltip - Displays dynamic tooltips over an element or the mouse cursor
  • TypeAhead - Displays a list of possible options below an input while typing
CSS
  • Animations - CSS3 transitions for specific animations: fade, slide, etc
  • Alert - Styles for block level notification messages
  • Button - Styles for generic cross-browser compatible buttons
  • ButtonGroup - Allows for the grouping of multiple buttons into 1 visual styled button
  • Icon - Allows for inline image sprites to be used at 12, 16, 24, 32, and 64 sizes
  • Label - Styles for inline tag labels
  • Badge - Styles for inline notification bubbles
  • Pagination - Styles for pagination lists
  • Visual - Provides visual aesthetics like gloss and glare over elements
What about a full application?

Nothing is stopping you from using Titon as a full application — hell, even the MVC package was built for this purpose. Since Titon is a collection of packages, there's no set guidelines on how to build an application, it's all up to how you want to piece it together. However, to make things easier, I've thrown together a skeleton application that you may use as a base.

What does the future hold?

In regards to the Framework, I have no plans to add anymore primary packages. I do have plans to add minor supporting packages, like Smarty and Twig support for the View layer. Any bugs, issues or feature requests I will handle of course. I would also like to increase unit testing and average around 90% code coverage for all packages.

The Toolkit however will receive full support and the inclusion of many more components. I currently use Toolkit on all my personal websites.

In the off chance that Titon becomes popular, I will provide in-depth documentation, a fully functional website, and reverse my decision on new packages.

How can you start using it?

By installing through Composer, or cloning the repository, or downloading the project. Since no official website exists, nor does any documentation, learning how to use each package can be tricky. Each repository contains a docs folder that provides basic documentation on each class in the repo. For any functionality that is not documented, I highly suggested reading the source code and its comments. And if no documentation exists for a specific class, let me know and I will provide one.

Using Toolkit requires some manual intervention as the source files need to be compiled. This allows for custom Toolkit builds (only requiring certain components) to be generated through Grunt. Instructions on how to do this can be found in the repository.

I will also be blogging about each package and how to use it, so expect those in the near future!

RFC proposal for getters and setters

If you haven't been following the PHP development lately, then you have been missing out. Recently, there was a vote on the PHP mailing lists about adding short syntax for arrays (ala Javascript), yet the devs vote against it with childish excuses. And then there was this one guy who forked the PHP project and patched it with speed improvements and features the users have been wanting (which I completely agree with). You can also view the PHP RFC Wiki on the list of *possible* features and the ones that were denied. As you can see, there is much happening in the PHP community, but nothing to show for it (yet).

However, my post today will be on the RFC suggestion for built in getters/setters. To keep it blunt, I really dislike the C# approach... it's, just not very PHP. Just seems odd to have floating curly blocks with a "get" and "set" in it, with no real defined scope block. On top of that, the "property" keyword is way too complicated for what it is trying to achieve. The one thing I do agree with though, is the readonly modifier. My suggestion is loosely based on the Traceur Compiler by Google syntax (they use get/set keywords instead of function, within the class).

class FooBar {
	public $value;
	protected readonly $_readOnly;
	protected static readonly $_static;
	public get value() {
		return $this->value;
	}
	final public set value($value) {
		$this->value = $value;
	}
	public get readOnly() {
		return $this->_readOnly;
	}
	public static get static() {
		return self::$_static;
	}
	public function noop() {
		return;
	}
}

Admittedly, my suggestion is a bit more verbose than the C# variant, and pretty similar to regular getValue() and setValue() methods, but there are a few key differences.

Method Naming

Technically, are they still considered methods? Regardless, when you are writing getters and setters, you should use the words "get" or "set" in place of "function". This dictates to the class that these methods should be used anytime a property is being read or written to. On top of this functionality, the visibility modifiers are in effect (public, protected, private). This allows you to write to protected properties using a public setter, or reading from private properties with a protected getter (while in the class scope of course). Final and static keywords work exactly the same as well. Below is a quick example.

$foo = new FooBar();
$foo->value = 'setter'; // calls set::value()
$foo->readOnly = 'readonly'; // throws an error/exception
FooBar::$static = 'static'; // throws an error/exception
echo $foo->value; // calls get::value()
echo $foo->readOnly; // calls get::readOnly()
echo FooBar::$static; // calls get::static() statically

Getters and setters are not required, but when implemented, they are automatically triggered. If a property is public, without a getter/setter, then getting/setting a value works like it normally would. The major difference with this proposal is allowing the getting/setting of non-public properties, and never having to write getValue() or setValue() (you just modify the property directly like the example above).

Read Only

One of the features within the original proposal that I did like, was the readonly keyword. This keyword can be applied to any class property to set it into a read-only state, which basically disallows the use of a set method. It also disallows setting a value to the property directly, using the old functionality. But this sounds like the final keyword right? Technically yes, the major difference is that you can overwrite a readonly value in a sub-class, and not with a final.

Abstract and Interfaces

These could also be used with abstract classes and interfaces, like so.

interface FooBar {
	public get value();
	public set value();
}
abstract class FooBar {
	protected $value;
	abstract protected get value();
	abstract protected set value();
}

Now this is just a personal preference and style, and is something I have been thinking about lately (I have ideas for other RFCs as well), so don't expect this to actually happen! I also didn't get too in depth, for example, when are magic methods called during this process? I will leave those out unless for some odd reason this makes it in (heh). Let me know what you think!

The fate of class suffixes in 5.3

Before PHP 5.3 was released, many programmers would suffix their classnames with the package and or module that it pertains to. For example, SessionHelper, UsersController, CommentModel, so on and so forth. But with the recent upgrade to namespaces, are these types of suffixes still required?

// Current Practice
SessionHelper();
// Namespace Practice
\app\libs\helpers\Session();
// Redundant Practice
\app\libs\helpers\SessionHelper();

That's one of many dilemma's I am running into right now when dealing with past practices and theories, and applying them to newer code. Namespaces make the suffix redundant as the package is now part of the class name (unless you are aliasing the namespace). The only deal breaking reason I can think of right now as to keep suffixes; is when you are editing multiple files (or browsing a folder), as it helps identify files from each other. But on the other hand, how many times are you going to have multiple files opened name User? Maybe twice for the model and controller.

I'm mainly posting this entry to get input from everyone else and what you think the approach should be. Right now I'm going down the path of not suffixing my classes, as the similar file name is not that much of a problem or hindrance to me. If you have any convincing arguments, let me hear them (especially since this will apply to my newer scripts)!

PHP Pro Tip: Don't close your PHP documents with ?>

Recently on my Twitter I mentioned this exact tip, "PHP Pro Tip: Don't close your PHP documents with ?>.", and got many responses asking why or if it's possible. I will briefly explain the benefits of this technique and when it applies. Many assumed I meant that you should never close your PHP scopes with ?>, but that's not the case, I was merely stating that the closing tag (at the very very bottom of your PHP file) does not need to be there.

If you are within a template file that has multiple opening and closing PHP tags, then of course it would be required to close those. If you have a PHP class or file that's purely PHP and consists of no front-end markup, then the closing tag at the bottom of the page is optional. It even says so in the official PHP.net documentation.

The closing tag of a PHP block at the end of a file is optional, and in some cases omitting it is helpful when using include() or require(), so unwanted white space will not occur at the end of files, and you will still be able to add headers to the response later. It is also handy if you use output buffering, and would not like to see added unwanted white space at the end of the parts generated by the included files.

Now onto the benefits to this technique. The main benefit is that it solves the "unwanted white space" at the beginning of the next document, causing it to error out and spew HTTP headers. It does so by keeping the PHP scope open at the end of the script, and allowing included files to continue within the scope and not fail. It also means you don't have to spend the time making sure there is no white space or new lines at the end of your files.

Very handy if you ask me. So just a heads up with a little tip. Enjoy :]

Why pure OOP, just for the sake of doing pure OOP

Lately all I have seen is the "Pure OOP is the way to go mentality" without much reasons to back up why its beneficial. I write OOP code, but I don't write overly verbose, bloated and cluttered OOP code either. I attend Zendcon, I have my PHP certification, I read PHP blogs on a daily basis, I have had multiple OOP discussions with other developers, but in the end I still ask the question, "Why do you spend so much time writing and separating your objects? When in the end its unnecessary as you are not extending them in the future anyways."

Before I begin, I want to do a quick review on how I got onto this topic. It started a few days ago when Brandon Savage posted his article Why Great Development Tools Don't Seem To Be Written In PHP, in which I agreed with him. Further into the comments, many users mentioned the PHP bug tracker Arbit Tracker. After downloading the source and browsing the code, I came to the following conclusion and posted this comment on Brandons entry:

After looking at Arbit... Why do people always need to use SO MANY files and classes to do such a basic task? Its unbelievable how bloated some projects can get. There is a thing with being to modular.

Just take a guess at how many files are required for a basic issue tracker... just guess. There are 2,077 files and 402 folders, and remember this is still an alpha version so that can grow even larger. Basically my first reaction was "Seriously? Do we really need all these files and classes to create a simple and basic bug/issue tracker". I have nothing against Arbit, nor the developers (They know there PHP for sure), but there is something terrible wrong about this in my opinion. This is a "3rd party script that is installable on a users machine", yet looks like a full blown framework and application. When I download a script to install on my machine, I want it to be lightweight, usable, easy and customizable. I find something really wrong about this when it takes this many classes to do such a basic task, and on top of that it requires multiple dependencies like EZ Components and CouchDB (and from what I could find, this wasn't even in the source! Now add more files into the final count). After my comment everyone seemed to post the same response: "Well of course, its a pure OOP project", and "This is what happens when you do it in true OOP", and "Nothing beats an OOP setup!".

I mentioned that a project does not need an abstract, an interface or even an exception for every class in its system, and I received this lovely little response.

If you want superior software then you use the standard and that (just) happens to be object oriented methodologies.

Drop object oriented methodologies and you drop way too many other natural benefits to software development; so enough of your bullsh*t okay?

I find this response laughable. Please tell me what those natural benefits are? To expand on classes if you want to customize it or create your own? To extend them even further? Dependency Injection? Multiple other reasons... You get my point. That's what abstract and interfaces are for. So why create them when YOU KNOW you will never extend them further, or even bother creating child classes. It seems everyone is in this mentality of "Ill do pure OOP just for the sake of doing OOP."

I can see when abstract and interfaces are required, like Zend Framework for example, but even then its overkill. Very rarely does anyone ever extend or use the abstract/interfaces in Zend. I've worked at many jobs and on many projects that utilized Zend, and have even worked with individuals that do the "Pure OOP" approach, and still I have not seen them extend objects like they are supposed to be, or use OOP to its fullest. I can only recall very few instances when people actually extended the objects, and it was primarily for Auth classes to customize to fit their application.

Another thing I dislike about pure OOP approaches is the amount of code you have to write to do such basic tasks. Take for example the routing components of Zend:

$this->getRouter()->addRoute('user', new Zend_Controller_Router_Route('user/:username', array('controller' => 'user', 'action' => 'info')));

I mean, whats so difficult about the following approach (below)? Why do you need to create a whole new object as an argument, when the object is just going to be a toArray() anyways and set as a property? Oh I know, its because you want to maybe use a Route_Regex class, or a Route_Hostname class. Now my question is, why would those even need to be their own class? Because they each do a different purpose and have their own methods that overwrite the abstracts? I guess that's where we disagree then. I honestly don't see a reason why these should be "split" up. The Router should manage all routes and package the class appropriately. Breaking up the classes isn't being "Pure OOP", its just being overly modular.

Say and think what you wish, but there's nothing wrong with the following piece of code either. But you'll probably find something wrong with static methods as well, seeing as how it doesn't add any OOP functionality.

Router::addRoute('user', 'user/:username', array('controller' => 'user', 'action' => 'info'));

I also have a problem with the amount of getters and setters I see everywhere. Have you not heard of __call, __get, __set, __isset, or __unset? But I digress, that topic is for another entry at another time.

I'll stop ranting now, its a matter of preference. Id also like to note that CakePHP (a non-pure OOP approach, but still OOP) has the same functionality and customization as Zend and Symfony (both pure OOP approaches). So why do you think Cake is inferior to the others? Personally, I think it has more beneficial and useful functionality.

Custom PHP Functions: Datetime functions

All of these functions can be found within the Titon Utility library.

It is now time for my second post, in my series of "Basic/Common PHP functions that all programmers should know". The first series was about basic PHP strings and with this issue I am going to tackle 5 more functions for date and time. As always, I try to make my functions short but powerful, enjoy!

If you have any ideas for a series you want to see, or a type of function, be sure to send me an email using the contact page (in the footer), thanks!

Days Between

This function finds the difference in days between two dates. Each date must be a unix timestamp; if not my function will try to convert it to one. This could be modified to find the difference in weeks, seconds, etc.

/**
 * Finds difference in days between dates.
 * 
 * @param int $start
 * @param int $finish
 * @return int
 */
public function daysBetween($start, $finish) {
	if (!is_int($start))	$start = strtotime($start);
	if (!is_int($finish))	$finish = strtotime($finish);
	$diff = $finish - $start;
	$days = $diff / (24 * 3600);
	return round($days);
}
Get Age

This is a pretty simple function, in that it will find the persons age depending on the year given and the current year. The birth year could either be a string of '1988' (4 numeric characters) or the full date 1988-02-26.

/**
 * Gets the age of an individual.
 * 
 * @param int $timeStamp
 * @return int
 */
public function getAge($timeStamp) {
	$seconds = time() - strtotime($timeStamp);
	$year = 60 * 60 * 24 * 365;
	return floor($seconds / $year);
}
Get Date/Time in Timezones

Now this is something that could be done in many numerous ways, but mine simply takes the timezone difference (-8, 0, +6, etc) as the second argument, and then returns a unix timestamp. This function does not have any input checking (so make sure your arguments are correct before hand) and does not apply Daylight Savings Time.

/**
 * Gets a unix timestamp in certain timezones.
 * 
 * @param int $timeStamp
 * @param int $timeZone
 * @return int
 */
public function timeInZone($timeStamp, $timeZone = -8) {
	return strtotime(gmdate('Y-m-d h:i:sa', $timeStamp + (3600 * $timeZone)));
}
Date within a Timeframe

This function will take a date and check to see if it was within a certain date range and return a boolean value. My function will attempt to convert non unix timestamps to unix; be sure to pass the data correctly. Also you can leave the 3rd argument empty ($finish date) and the current time() will be used.

/**
 * Checks to see if a timestamp was within a timeframe.
 * 
 * @param int $check
 * @param int $start
 * @param int $finish
 * @return boolean
 */
public function withinTimeframe($check, $start, $finish = '') {
	if (!is_int($check))	$check = strtotime($check);
	if (!is_int($start))	$start = strtotime($start);
	if (empty($finish)) {
		$finish = time();
	} else {
		if (!is_int($finish)) $finish = strtotime($finish);
	}
	if ($check >= $start && $check <= $finish) {
		return true;
	}
	return false;
}
Breakdown a timestamp

Now this next function is quite different then the previous ones, but is pretty powerful. This function breaks down the timestamp to find how many days, weeks, months, etc there are until the current time (using time()). This type of function is good for doing text like: Last comment 5 days, 3 hours ago.

/**
 * Breaksdown a timestamp into an array of days, months, etc since the current time.
 * 
 * @param int $timeStamp
 * @return array
 */
public function timeBreakdown($timeStamp) {
	if (!is_int($timeStamp)) $timeStamp = strtotime($timeStamp);
	$currentTime = time();
	$periods = array(
		'years'         => 31556926,
		'months'        => 2629743,
		'weeks'         => 604800,
		'days'          => 86400,
		'hours'         => 3600,
		'minutes'       => 60,
		'seconds'       => 1
	);
	$durations = array(
		'years'         => 0,
		'months'        => 0,
		'weeks'         => 0,
		'days'          => 0,
		'hours'         => 0,
		'minutes'       => 0,
		'seconds'       => 0
	);
	if ($timeStamp) {
		$seconds = $currentTime - $timeStamp;
		if ($seconds <= 0){
			return $durations;
		}
		foreach ($periods as $period => $seconds_in_period) {
			if ($seconds >= $seconds_in_period) {
				$durations[$period] = floor($seconds / $seconds_in_period);
				$seconds -= $durations[$period] * $seconds_in_period;
			}
		}
	}
	return $durations;
}

And there you have it, 5 functions dealing with date and time. Stay tuned for the next issue! And again, if you have ideas for functions, send me an email!

Custom PHP Functions: String functions

All of these functions can be found within the Titon Utility library.

It's now time for some PHP that isn't Cake related. This is the first part in a series of "Basic/Common PHP functions that all programmers should know". This series has to deal with manipulating strings. I try to make my functions short, sweet and powerful, and I hope you learn something from them.

Truncate

This function takes a long string and shortens it to a defined length and adds appends an ellipsis (or custom string) to the end. Instead of chopping a word in half (if the limit finished within it), it moves the pointer up to the previous space.

/**
 * Truncates a string to a certain length.
 * 
 * @param string $text
 * @param int $limit
 * @param string $ending
 * @return string
 */
public function truncate($text, $limit = 25, $ending = '...') {
	if (strlen($text) > $limit) {
		$text = strip_tags($text);
		$text = substr($text, 0, $limit);
		$text = substr($text, 0, -(strlen(strrchr($text, ' '))));
		$text = $text . $ending;
	}
	return $text;
}
Shorten

This function works similarly to truncate(), but instead of chopping off the end of the string, it chops out the middle. This is useful for shortening users long names or websites.

/**
 * If a string is too long, shorten it in the middle.
 * 
 * @param string $text
 * @param int $limit
 * @return string
 */
public function shorten($text, $limit = 25) {
	if (strlen($text) > $limit) {
		$pre = substr($text, 0, ($limit / 2));	
		$suf = substr($text, -($limit / 2));	
		$text = $pre .' ... '. $suf;
	}
	return $text;
}
Obfuscate

Now this function doesn't directly scramble the text and confuse the user, instead it scrambles the source code. This is useful for displaying emails or other strings that you don't want to show up directly in your source code.

/**
 * Scrambles the source of a string.
 * 
 * @param string $text
 * @return string
 */
public function obfuscate($text) {
	$length = strlen($text);
	$scrambled = '';
	for ($i = 0; $i < $length; ++$i) {
		$scrambled .= '&#' . ord(substr($text, $i, 1)) . ';';
	}
	return $scrambled;
}
Slugify

This function takes a string and makes it SEO and URL friendly (for example in the address bar for my blog posts). It lowercase's all words, replaces spaces with a dash, removes foreign/illegal characters and follows the guidelines for the best possible SEO. For example "Hello, my name is Miles Johnson!" would convert to "hello-my-name-is-miles-johnson".

/**
 * Rewrite strings to be URL/SEO friendly.
 *
 * @param string $text
 * @return string
 */
public function slugify($text) {
	$text = trim(strtolower($text));
	$text = str_replace(array('-', ' ', '&'), array('_', '-', 'and'), $text);
	$text = preg_replace('/[^a-zA-Z0-9\-_]/is', '', $text);
	$text = urlencode($text);
	return $text;
}
Listing

This final function takes an array of items and turns them into an ordered list with the last item having the word "and" in front of it instead of a comma. Very good for making lists.

/**
 * Creates a comma separated list with the last item having an "and".
 *
 * @param array $items
 * @param string $and
 * @return string
 */
public function listing($items, $and = 'and') {
	if (is_array($items)) {
		$lastItem = array_pop($items);
		$items = implode(', ', $items);
		$items = $items .' '. $and .' '. $lastItem;
	}
	return $items;
}

Now that's all I have for now, and I know you will use this in your code constantly just like I do! Be patient for my next series which will be dealing with basic date/time functions.

Riding the Frameworks

So for the past week I have been learning Symfony and CakePHP, both amazing PHP frameworks. I'm curious to learn a framework because I have many large scale projects I would like to build and it would just be easier to use a framework. Symfony is hosting this daily blog where each day it posts a new tutorial and within a month you should understand the framework. Its currently at day 5 and I already understand the structure of Symfony, albeit Propel is quite complicated.

Cake grabbed my interest first, simply because the structure and MVC is extremely easy to understand. The hardest part for me to grasp is the Model system and its hasMany, belongsTo, etc... but I am getting there. The documentation is also very easy to read, I read through the whole cookbook in about 5-6 hours and keep going back for examples and references. Ill admit though, the cookbook is a bit basic in that it doesn't explain some key features thoroughly, your best bet is to open the PHP files yourself and try and figure out what they do.

But right now I'm learning towards Cake, simply because its extremely lightweight compared to Symfony and I prefer its file structure and MVC. Ill give it to Symfony though, its YAML is the easiest thing to write and understand and it also encompasses a strong routing system. Ill be updating more along my PHP journey.