Advertisement

2016-09-29

Migrating a SVN repository to Git (Bitbucket)

Migrating a SVN repository to Git (Bitbucket)

Preface

This article explains how to migrate a SVN repository to Git. Although this guide uses BitBucket as the Git repository, you can easily adjust the steps to migrate to a different Git repository provider.

I was recently tasked to migrate a repository from SVN to Git (BitBucket). I have tried the the importer from BitBucket but it failed due to corruption in our SVN repository.

So I had no other alternative than to do things by hand. Below is the process I have used and some gotchas.

Authors

SVN stores just a username with every commit. So nikos could be one and Nikos could be another user. Git however stores also the email of the user and to make things work perfectly we need to create an authors.txt file which contains the mapping between the SVN users and the Git users.

NOTE The authors.txt file is not necessary for the migration. It only helps for the mapping between your current users (in your Git installation).

Phalcon 3.0.0 released

Phalcon 3.0.0 final (LTS) released

The Phalcon team is very excited to share some news with our community!

The last few months, we have been working hard to push 2.1 out, which contains significant enhancements as well as some API changes that require attention so as not to break compatibility with your application.
On top of that we have been working in making Zephir PHP7 compatible so that you can enjoy Phalcon in your PHP7 application. Some news first though:

Versioning

Given a version number MAJOR.MINOR.PATCH, increment the:
* MAJOR version when you make incompatible API changes,
* MINOR version when you add functionality in a backwards-compatible manner, and
* PATCH version when you make backwards-compatible bug fixes.
* Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.

Since 2.1 has many API changes, we decided that it would be best to not release it as is and start using SemVer to better communicate with the community and keep track of our releases.

2.1 is dead, all hail 3.0

As mentioned above, 2.1 will not be fully backwards compatible. As a result, we are changing the version number to 3.0.

PHP version support

The Phalcon team takes security very seriously and thus have decided to provide support to PHP versions that are supported. As of 3.0, PHP 5.3 and 5.4 will be deprecated. We are making a small exception to this rule and will continue to support 5.5 for a little while, but since its support has expired a few days ago, it will too be deprecated in a future release.

The goodie bag

So what does 3.0 offer? The changelog is extensive as you can see. Below are highlights of the changes as well as areas you need to concentrate.

• PHP 5.3 and 5.4 are fully deprecated.
You can compile the code on your own, but we will not be able to support it nor can we guarantee that it will work as you expect it to. PHP 5.3 support expired mid 2014 and 5.4 expired mid 2015. We need to ensure our applications have all known vulnerabilities on the PHP side fixed and patched, thus we will not support any unsupported PHP version. This excludes PHP 5.5, whose support expired a few days ago. We will deprecate 5.5 in a future release but will make sure that you all know beforehand so that you can prepare.

INCOMPATIBLE: You will need to upgrade your PHP installation to 5.6. You can always continue to use the Phalcon version you are using, but in 3.0 support for PHP 5.4 has been deprecated and we cannot guarantee that PHP 5.5 will be fully functional.

APPLICATION

• Phalcon\Cli\Console and Phalcon\Mvc\Application now inherits Phalcon\Application.
This change makes the interfaces more uniformed and offers additional functionality to the respective applications (cli/mvc)

BEANSTALK

• Added \Phalcon\Queue\Beanstalk::ignore().
Removes the named tube from the watch list for the current connection.

• Added \Phalcon\Queue\Beanstalk::pauseTube().
Can delay any new job being reserved for a given time.

• Added \Phalcon\Queue\Beanstalk::kick().
It moves jobs into the ready queue. If there are any buried jobs, it will only kick buried jobs. Otherwise it will kick delayed jobs.

// Kick the job, it should move to the ready queue again
if (false !== $job->kick()) {
$job = $this->client->peekReady();
}

• Added \Phalcon\Queue\Beanstalk::listTubeUsed().
Returns the tube currently being used by the client.

• Added \Phalcon\Queue\Beanstalk::listTubesWatched().
Returns a list tubes currently being watched by the client.

CACHE

• Added Phalcon\Cache\Frontend\Msgpack.
MsgPack is a new frontend cache. It is an efficient binary serialization format, which allows exchanging data among multiple languages like JSON.

use Phalcon\Cache\Backend\File;
use Phalcon\Cache\Frontend\Msgpack;
// Cache the files for 2 days using Msgpack frontend
$frontCache = new Msgpack(
[
'lifetime' => 172800,
]
);
// Create the component that will cache 'Msgpack' to a 'File' backend
// Set the cache file directory - important to keep the '/' at the end of
// of the value for the folder
$cache = new File(
$frontCache,
[
'cacheDir' => '../app/cache/',
]
);
// Try to get cached records
$cacheKey = 'robots_order_id.cache';
$robots = $cache->get($cacheKey);
if ($robots === null) {
// $robots is null due to cache expiration or data do not exist
// Make the database call and populate the variable
$robots = Robots::find(['order' => 'id']);
// Store it in the cache
$cache->save($cacheKey, $robots);
}
// Use $robots
foreach ($robots as $robot) {
echo $robot->name, "\n";
}

• Fixed bug of destroy method of Phalcon\Session\Adapter\Libmemcached

• Added Phalcon\Cache\Backend\Memcache::addServers to enable pool of servers for memcache

CRYPT

• Mcrypt is replaced with openssl in Phalcon\Crypt#11530
Due to the lack of updates for mcrypt for a number of years, its slow performance and the fact that the PHP core team decided to deprecate mcrypt as soon as possible (version 7.1 onward), we have replaced it with the much faster and supported openssl.

• Default encrypt algorithm in Phalcon\Crypt is now changed to AES-256-CFB

BACKWARDS INCOMPATIBLE: Backwards compatibility from openssl to mcrypt is problematic if not impossible. We had to remove several methods that are no longer applicable. Additionally the rijndael-256 from mcrypt is no longer valid in openssl. The default encryption algorithm is AES-256-CFB

If you have data that has already been encrypted with mcrypt, you will need first to decrypt it before upgrading to 3.0 and then encrypt it again using 3.0 and therefore openssl. Failure to do so will result in loss of data. A port is available in the incubator. Please see the code here

DATABASE

• Dropped support of Oracle #12009
Support of Oracle has been dropped from the Phalcon Core for the following reasons:
•• The lack of Oracle maintainer
•• The lack of relevant experience among the Phalcon Core Team
•• Weak support or interest from the community
•• Incomplete implementation that creates only the illusion of support for Oracle
•• Some issues hampering for the support of PHP 7 in Phalcon

Oracle components will be ported to the Phalcon Incubator. If the adapter receives support and enhancements from the community, we will consider making it part of the core again.

DI

• Phalcon\Di is now bound to services closures allowing use Phalcon\Di as $this to access services within them. Additionally, closures used as handlers inMvc\Micro are now bound to the $app instance

• Added ability to spoof the HTTP request method.
Most browsers do not support sending PUT and DELETE requests via the method attribute in an HTML form. If the X-HTTP-Method-Override header is set, and if the method is a POST, then it is used to determine the 'real' intended HTTP method. The _method request parameter can also be used to determine the HTTP method, but only if setHttpMethodParameterOverride(true) has been called. By including a _method parameter in the query string or parameters of an HTTP request, Phalcon will use this as the method when matching routes. Forms automatically include a hidden field for this parameter if their submission method is not GET or POST.

• Added support of CONNECT, TRACE and PURGE HTTP methods.
- CONNECT: A variation of HTTP tunneling when the originating request is behind a HTTP proxy server. With this mechanism, the client first requests the HTTP proxy server to forward the TCP connection to the final endpoint. The HTTP proxy server then establishes the connection on behalf of the client.
- TRACE: A method used for debugging which echoes input back to the user. Note that this method is dangerous, since it introduces a risk whereby an attacker could steal information such as cookies and possibly server credentials.
- PURGE: Although not defined in the HTTP RFCs, some HTTP servers and caching systems implement this method and use it to purge cached data.

• Refactored Phalcon\Http\Request::getHttpHost.
Now it always returns the hostname or empty an string. Optionally validates and cleans host name #11921

• Renamed Phalcon\Http\Request::isSoapRequest to Phalcon\Http\Request::isSoap and Phalcon\Http\Request::isSecureRequest to Phalcon\Http\Request::isSecure.
Left the originals functions as aliases and marked them deprecated.

CAUTION: Any references to isSoapRequest need to be renamed to isSoap. Any references to isSecureRequest need to be renamed to isSecure.

• Added \Phalcon\Loader::registerFiles and \Phalcon\Loader::getFiles.
registerFiles registers files that are "non-classes" hence need a "require". This is very useful for including files that only have functions. getFiles
returns the files currently registered in the autoloader

$loader->registerFiles(
[
'fuctions.php',
'arrayFunctions.php',
]
);

MODELS

• Changed constructor of Phalcon\Mvc\Model to allow pass an array of initialization data

ROLES

• Added Phalcon\Acl\RoleAware and Phalcon\Acl\ResourceAware Interfaces. Now you can pass objects to Phalcon\Acl\AdapterInterface::isAllowed as roleName and resourceName, also they will be automatically passed to function defined in Phalcon\Acl\AdapterInterface::allow or Phalcon\Acl\AdapterInterface::deny by type

• Phalcon\Acl\AdapterInterface::allow and Phalcon\Acl\AdapterInterface::deny have 4th argument - function. It will be called when using Phalcon\Acl\AdapterInterface::isAllowed

• Phalcon\Acl\AdapterInterface::isAllowed have 4th argument - parameters. You can pass arguments for a function defined in Phalcon\Acl\AdapterInterface:allow or Phalcon\Acl\AdapterInterface::deny as associative array where key is argument name

VALIDATION

• Phalcon\Mvc\Model\Validation is now deprecated in favor of Phalcon\Validation
The functionality of both components is merged into one, allowing us to reduce the codebase while offering the same functionality as before.

PHP7

Phalcon 3.0 supports PHP7! In subsequent releases we will focus on the development of the framework to implove the compatibility and take advantage of the performance enhancements that PHP7 offers. You can install the framework in php7 using the usual installation instructions.

Support

Phalcon 3.0 Long Term Support (LTS) version is out, and it’s packed with new features to help you better create web applications with PHP. This version of the framework will be maintained for 3 years from now.

Acknowledgments

We want to greatly thank everyone who has contributed to accomplish and achieve the completion of this release. Special thanks to our friends around the world that have made possible this release:

Conclusion

Phalcon 3.0 takes a step forward towards a modern framework for PHP. We'll continue working making it more useful and performant for developers. Thank you once more to our wonderful community and users!

Installation

You can install Phalcon 3.0 for either PHP 5.5/5.6/7.0 using the following instructions:

As always, many thanks to everyone involved in this release and thanks for choosing Phalcon!

<3 Phalcon Team

2015-10-29 21:15:00

Setting up AWS RDS MySQL replication offsite

Preface

Recently I worked on setting up replication between our AWS RDS instance and a server running as a MySQL slave in our location. Although the task was not difficult, there are quite a few areas that one needs to pay attention to.

In this blog post, I am going to outline the process step by step, so that others can benefit and not lose time trying to discover what went wrong.

Setup

Master Setup

There is little to do on our master (RDS). Depending on the database size and update frequency, we will need to set up the maximum retention time for the bin logs. For a very large database we need to set a high number, so that we are able to export the database from the master, import it in the slave and start replication.

You can use a different number of hours; I am using 24 for this example.

Slave Setup

I am assuming that MySQL is installed on the machine that has been designated as the slave, and also that that machine has ample space for the actual data as well as the binary logs that will be created for the replication.

Edit my.cnf

The location of this file is usually under /etc or /etc/mysql. Depending on your distribution it might be located elsewhere.

Note: The configuration file will contain a lot more entries but the ones above are the ones you need to pay attention to.

bind-address: We need to comment this line so that we can connect to the instance from somewhere else in the network. Keep this line if you are going to work only on the slave machine and allow no connections from elsewhere.

general_log_file: The location of your query log file. You can disable this (see next entry) but it is always good to keep it on at least at the start, to ensure that replication is moving smoothly. Tailing that log will give you a nice indicator of the activity in your database.

general_log: Enable or disable the general log

log_error: Where to store the errors log

log_slow_queries: Where to store the slow queries log. Especially helpful in identifying bottlenecks in your application

log-queries-not-using-indexes: We want this because it can help identifying potential bottlenecks in the application

server-id: A unique ID for your slave instance.

log_bin: Where the binary replication logs are kept

expire_logs_days: How long to keep the replication logs for

max_binlog_size: Maximum replication log size (per file)

Once you set these up, restart your MySQL instance

/etc/init.d/mysql restart

Download the SSH Public Key for RDS

In your slave server, navigate to /etc/mysql and download the rds-combined-ca-bundle.pem file. This file will be used by the slave to ensure that all the replication traffic is done using SSL and nobody can eavesdrop on your data in transit.

NOTE You can put the rds-combined-ca-bundle.pem anywhere on your slave. If you change the path, you will have to modify the command to connect the slave to the master (shown further below) to specify the exact location of the key.

Import timezone data

This step might not be necessary depending on your MySQL installation. However since RDS works with UTC, you might find your replication breaking because your slave MySQL instance cannot understand the UTC timezone. The shell command you need to run on your slave machine to fix this is:

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql

Creating the RDS related tables

RDS uses its own tables to keep track of the replication status and other related data such as the replication heartbeat, configuration etc. Those tables need to be present in the mysql database of your slave in order for the replication to work.

NOTE I am not 100% that all of these tables are needed. I have seen only the rds_heartbeat2 and rds_replication_status used. You can experiment with these when you enable replication and add each table in turn if needed. You can confirm whether the above are correct for your instance by connecting to the master and taking a mysqldump of the mysql database.

Replication

Replication user

We need to create a user in our master database that will have the appropriate rights to perform all the replication related actions. We need these commands to be run on the master. For this example I am creating a user called rpluser with the password 424242:

Keep those values handy (File and Position) since we will use them to instruct the slave where to start requesting data from the master (binlog file and position).

mysqldump

Take a database dump of all the databases in RDS (exclude information_schema and mysql). If your database can afford a bit of downtime you can use the --opt flag in mysqldump, which will lock all tables until the backup completes. If not, you can use the --skip-add-locks flag. More information about mysqldump options can be found here

Repeat the process of creating the database, using it and sourcing the dump file until all your databases have been imported.

NOTE There are other ways of doing the above, piping the results directly to the database or even using RDS to get the data straight from it without a mysqldump. Whichever way you choose is up to you. In my experience, the direct import worked for a bit until our database grew to a point that it was timing out or breaking while importing, so I opted for the multi step approach. Have a look at this section in the AWS RDS documentation for more options.

Connecting to the master

Once your restore has been completed it is time to connect our slave to the master. In order to connect to the master from the slave we need to verify the following:

The name of the RDS instance (for the command below I will use myinstance.rds.amazonaws.com)

The name of the replication user (we chose rpluser)

The password of the replication user (we chose 424242)

The master log file (see above, we got mysql-bin-changelog.000123 from show master status;)

The master log file position (see above, we got 171819)

The location of the SSL certificate (we used /etc/mysql/rds-combined-ca-bundle.pem)

The command we need to run on the slave MySQL server is (newlines added for readability):

References

Using Traits to add more functionality to your classes in PHP

Traits are a mechanism for code reuse in single inheritance languages such as PHP.

A Trait is similar to a class, but only intended to group functionality in a fine-grained and consistent way. It is not possible to instantiate a Trait on its own. It is an addition to traditional inheritance and enables horizontal composition of behavior; that is, the application of class members without requiring inheritance. Source

Traits have been introduced in PHP 5.4.0. However, a lot of developers have not yet embraced them and taken advantage of the power that they offer.

As mentioned above in the snippet of the PHP manual, Traits are a mechanism to reuse code, making your code more DRY.

Let's have a look at a real life example of how Traits can help you with your Phalcon project, or any project you might have.

Models

With Phalcon, we have model classes which represent pretty much a table in our database, and allows us to interact with a record or a resultset for the needs of our application.

Scenario

We have an application where we need to store information about Companies. Each Company can have one or more Customers as well as one or more Employees. We chose to store that information in three different tables.

For each Employee or Customer, we need to store their first name, middle name and last name. However we also need to be able to show the full name in this format:

<Last name>, <First Name> <Middle Name>

Using custom getter

In each model we can use a custom getter method in the Phalcon model to calculate the full name of the record.

Customer

The above introduces a problem. If we want to change the behavior of the getFullName we will have to visit both models and make changes to the relevant methods in each model. In addition, we are using the same code in two different files i.e. duplicating code and effort.

We could create a base model class that our Customer and Employee models extend and put the getFullName function in there. However that increases the class extensions and could lead to maintenance nightmares.

For instance we will have to create the base model class that only Customer and Employee models extend but what would happen if we need common functionality for other models? We will need to then create another base model class and so on and so forth. If we end up piling all the common functionality into one base model class then we will end up with functions that would not apply to all of our models and thus a maintenance nightmare.

NOTE: We can also use the afterFetch method to create a calculated field which will be available for us to use. We can use either the getter or the afterFetch like so:

Traits

We can use a trait to offer the same functionality, keeping our code DRY. Since a Trait is not a class that can be instantiated by itself, we attach it to wherever we need to, in this case the Employee and Customer models.

Conclusion

Traits can be very powerful and helpful allies, keeping our code very flexible and reusable.

Give it a try!

2015-10-04 13:26:00

Building the Phalcon Blog (i)

This is the first of a series of posts, describing how we built the Phalcon Blog (and this one of course). The intention is to showcase some of the features of Phalcon and discuss the reasons behind implementing the code in such a way. I will amend this post with the links of the future posts once I post them.

These series will focus initially on the Phalcon blog (Github) and will then expand on this blog (Github). In the very near future all the features available in this blog will be available in the Phalcon one :)

As I mentioned in a previous post, Andres and I were not 100% satisfied with Tumblr, the blogging platform that we have used for a few years for the purposes of the Phalcon blog. So we decided that it would not only be beneficial for us to build something of our own, but also for the community, since the software is open sourced and available for everyone to use.

Bootstrapping process

In this post I am going to concentrate on bootstrapping the application. By bootstrapping I do not mean using the Bootstrap open source library, despite the probably misleading image on the right.

Bootstrapping is the class (in our case) that handles pretty much everything that our application needs to run prior to executing actions. This entails

Conditional execution between the normal app and the CLI one

Application Paths

Configuration Files

Loader (and composer autoloader) setup

Error handling

Routes

Dispatcher

Url

Views

Main View

Simple View (for emails, RSS/Sitemap etc.)

Cache

Utils

Post Finder class

Some of the above components are also registered in the DI container for further use in the application.

Implementation

In other applications we have open sourced such as Vokuro, we have pretty much always included a couple of files in our index.php; one for the loader and one for the services as demonstrated here.

There is nothing wrong with the above approach. We did however consider the fact that the particular index.php file has 3 different file inclusions and if we wanted to tinker with the setup of the application we would have to open all three.

We opted for one file containing all of our services and application bootstrap. In addition to that, we altered the design so that later on we can add a CLI application without much effort and heavy refactoring.

NOTE: The CLI application has been implemented on this blog and will very soon be merged to the Phalcon repository. We will cover that functionality in a future post.

index.php

Having one file that performs all the necessary initialization tasks a.k.a. bootstrapping our application allows us to have a much smaller index.php file. (comments removed to preserve space)

We create a new bootstrap application and pass in it a DI container. For this part of the application the FactoryDefault DI container is used. However we will be able to inject a Phalcon CLI DI container for the CLI application we will discuss later on.

Bootstrap.php

Our bootstrap class contains all the code we need to run the application. It is a bit shy of 400 lines which according to PHP Mess Detector is not something we want to be doing because it increases complexity and if we are not careful it will create a mess :). We opted to ignore that rule and left the file as is because once we had everything working as we wanted, we were not going to be messing with that file again.

Constants

We use several constants throughout the application.

K_PATH - the top folder path of our installation

K_CLI - whether this is a CLI application or not

K_DEBUG - whether we are in debug/development mode. In this mode all volt templates are being created at every request and cache is not used.

K_TESTS - whether we are running the test suite or not (test suite is not implemented yet)

Configuration

The configuration is split into two files. The git tracked base.php (under /var/config/) contains an array of elements that are needed throughout the application, such as cache settings, routes etc. The config.php located in the same folder is installation dependent and is not tracked in git. You can override every element that exists in base.php.

/**
* The configuration is split into two different files. The first one
* is the base configuration. The second one is machine/installation
* specific.
*/
if (!file_exists(K_PATH . '/var/config/base.php')) {
throw new \Exception('Base configuration files are missing');
}
if (!file_exists(K_PATH . '/var/config/config.php')) {
throw new \Exception('Configuration files are missing');
}
/**
* Get the config files and merge them
*/
$base = require(K_PATH . '/var/config/base.php');
$specific = require(K_PATH . '/var/config/config.php');
$combined = array_replace_recursive($base, $specific);
$config = new Config($combined);
$di->set('config', $config, true);

Loader

The loader uses the namespaces defined in the base.php and config.php. Additionally the composer autoloader is included to offer functionality needed from the composer components we have.

/**
* We're a registering a set of directories taken from the
* configuration file
*/
$loader = new Loader();
$loader->registerNamespaces($config->namespaces->toArray());
$loader->register();
require K_PATH . '/vendor/autoload.php';

Logger

The logger is set to create a log file every day (with the date as the prefix).

Error handler

We decided to have no errors thrown in the application even if those are E_NOTICE. A simple isset() in most cases is more than enough to ensure that there are no E_NOTICE errors thrown in our log. Any errors thrown in the log files slow our application down, even if the errors are suppressed using the php.ini directives. We also set the timezone to US/Eastern in that file. That particular piece could become configurable and stored in the config.php. Finally we specify a custom error handler, to offer verbosity in errors thrown as well as log metrics when in debug mode.

Dispatcher

The dispatcher is instantiated with a listener, attaching to the beforeException event of the dispatcher. A custom plugin NotFoundPlugin is used to send output to the 404 page. Using the plugin allows us to reuse it anywhere in the application. This implementation is very beneficial when developing multi module applications.

NOTE: For the CLI application later on, we will need the CLI dispatcher.

Cache

The cache component is configured using the config.php. We can define the parameters in that file and thus use say the File cache for our local/development machine and a more advanced cache (Memcached for instance) for the production system.

References

Every microsecond counts!

Preface

One of the primary factors that always needs to be taken into consideration when designing and implementing an application is performance. In this day and age of information overload, everything is about speed. If your website is slow (more than a second or two) to appear on the browser, most likely your visitors will leave and go elsewhere. If the application you designed/implemented is slow, it will use more resources (memory/cpu) and thus cost more money to run. Time is money.

The Nanosecond

I have the highest admiration for Grace Hopper, a pioneer computer scientist who invented the first compiler for a computer language and paved the way for the evolution of programming languages in general. In a video she describes the value of a nanosecond in computer terms. I encourage you to click the link and watch it, it might give you a better perspective on why your application must be as fast as possible.

This Blog

As I wrote in a previous post, a new version of this blog has been launched, based on work done for for the Phalconblog. While in development mode, metrics that are printed in the logger. The output looks something like this:

As you can see there is room for improvement. Granted these results come from my local installation, where the debugMode is set to 1, which means that there is no caching and everything gets recalculated on every request. Still, if I can make this local installation perform as fast as possible, then on the production server it will be even faster.

The first few lines show a relatively OK response (2.7-3.0 seconds) but a high usage in memory. This had to be rectified and looking at the code, I managed to refactor the PostFinder class and reduce the memory consumption significantly. Removing objects and referenced objects in them made a huge difference. Arrays work just fine for my purposes.

Additional optimizations led to dropping the execution time to just above 2.0 seconds and the memory consumption below 1Mb.

There are still a lot of things I can try (and will) both on the application level as well as the server level. I am aiming to reduce the execution time to below 1 second and I will for sure share the results and the tools/techniques used.

I hope you enjoy the performance increase (however noticeable). More to come in the near future.

References

New Blog (again), new look, hopefully more posts

The excuse

It has definitely been a very long time since I last blogged. Just like my previous hiatus, a lot of personal issues arose that would not allow me the luxury to devote time for this blog.

Things managed to settle down for a bit, so hopefully I can start posting more frequently.

New look

For those that have been following this blog (all 3 of you), you will notice that the look and feel has changed significantly. I decided that I needed a fresh look so after evaluating many platforms and blog related software, I opted for the in house version.

Many of you know that I have been heavily involved in the Phalcon Framework, where I serve as a member of the core team. For the blogging needs of the project, we were using Tumblr but were not 100% satisfied. So a couple months back we decided to write our own blogging software based on Phalcon!

The results can be seen on our blog, which is also open sourced on Github.

For my own purposes I modified the codebase, adding new functionality and modifying it somewhat for my needs. The changes are also on Github and will soon be propagated to the Phalcon repository for everyone to use. This software requires some libraries loaded by composer and of course Phalcon loaded on your web server. The content is served using Markdown.

As far as the look is concerned, I tried (really did) but nothing came close to what I wanted. Since I am not a CSS developer by any means, I purchased this template by the guys that created Bootstrap. The result IMHO is really nice, responsive and clean. I hope you like it too!

Future

I intend on posting more content in the next few weeks. The goal is to post one article (minimum) per week. Other than technology, I am going to focus on Phalcon related posts, sharing experiences, tips and tricks.

Missing...

This blog software is still under construction. I have a few things that I need to address such as:

Pagination

RSS feeds

Posts by tag

Posts by archive

Comments - disqus integration

Tests!!!!

Some of those are already in place but I need to make sure that they work as expected

I hope you like the new look and stay tuned for more content.

2013-09-15 12:00:00

Let the RDBMS do more than just store data

One of the common "mistakes" that programmers (and have been guilty as charged many a times in the past) is not to use the tools that are available to them to the maximum extent possible.

A common example is using the RDBMS of your choice to only store and retrieve data, without taking advantage of its power and its features to the full extent.

A RDBMS can do much, much more. One can use triggers that can auto update fields (as I will demonstrate in this blog post), log data into tables, trigger cascade deletes etc.; stored procedures can compute complex data sets, joining tables and transforming data; views can offer easier representations of data, hiding complex queries from the actual application. In addition, such features, like stored procedures/views, can offer security enhancements as well as maintainability to an application. Execution for instance can be restricted to particular groups/logins, while changing the stored procedure/view only requires a change on the database layer and not the application itself.

In this blog post I will show you a simple example on how one can transfer some of the processing of an application to the RDBMS. I am using MariaDB as the RDBMS and PhalconPHP as the PHP framework.

The RDBMS

Each table of my database has several common fields that are used for logging and reporting as well as recording status.

There is not much I can do with the user ids (created/updated) or the deleted column (see also notes below regarding this). However as far as the dates are concerned I can definitely let MariaDB handle those updates.

By using skipAttributes, I am instructing the Phalcon model not to update those fields. By doing so, I am letting my triggers worry about that data.

Conclusion

It might seem a very trivial task that I am delegating but in the grand scheme of things, the models of an application can be very complex and have a lot of logic in them (and so might controllers). Delegating some of that logic in the RDBMS simplifies things and also increases performance of the application, which now requires just a bit less computational power.

NOTES

For a soft delete feature i.e. automatically updating the deleted field when a DELETE is called, a trigger will not work. Instead one can use a stored procedure for it. See this Stack Overflow answer.

2013-06-25 12:00:00

Voting for Phalcon as a cPanel feature woes

Those that have been following my blog and posts on Google+ know that for the last year or so I have been involved heavily in PhalconPHP, a C based PHP framework, which delivers its functionality as an extension loaded on the web server.

I was honored a few months ago when I became a member of the Phalcon Team and have since tried my best to evangelize Phalcon and to help as much as possible with scheduling NFRs for development, helping in the forum, unit tests, blog posts etc.

One of the most difficult issues that Phalcon is facing is helping developers installing it on their machines. This of course does not mean that it is really difficult to install. The installation is basically three commands (or if you are on a Windows box you just download the DLL, add the relevant directive in the php.ini and restart the web server).

However since a lot of people are using shared hosting, they do not have access to the command line where sudo or su are available so that that Phalcon can be installed. This is left to the hosting company and some are very reluctant to install anything at all. I used to own a hosting company and I can assure you that it is indeed a hassle if a handful of clients ask for a library or an installation that is not part of the "norm". You have to maintain it, you have to ensure that it will not interfere with other packages on the server or hinder other clients that reside on the same hosting box.

A few months ago I approached cPanel through their ticketing system, in an effort to make Phalcon an option for the extensions that can be installed and loaded through their EasyApache application.

At the time I was granted a development account for the software so that I can try and create an installation script and also was prompted to go to http://features.cpanel.net/ and open a new feature request regarding this (the request is here). The purpose of this exercise is for cPanel to get a feel of what features the community needs and address them. In my communications with them I received the following (emphasis mine):

Our EasyApache has multiple locations to add includes, or post hooks to compile third party libraries/software during a build, or after a build has completed. That being said, the extensions that we ship to be configured are maintained by the PHP & PECL groups. To answer the question as far as integration on all servers running cPanel, I would recommend creating a feature request for this, and allowing the community to vote for this:

And so I did. I created the feature request and we also advertised this in our community via our forum and our blog post.

The feature received well over 180 votes, making it the third most requested feature in cPanel. Also if you follow the link, one of the engineers of cPanel requested additional information which was provided by myself and others.

As time went by, I visited the feature and requested an update but never got a reply back. More and more votes kept on coming in so it was really a waiting game at that time.

All of a sudden though a week ago, one of our users in the forum asked in our Forum why the feature request in cPanel has only 7 votes. This came to us as a surprise so I went and checked it out. Lo and behold the vote counter was at 7 and not at 180+. Assuming that this was some sort of a glitch, I opened a ticket with cPanel and inquired about this.

A short time later I received a reply from a Vice President of Operations stating (emphasis mine):

Our feature request system was designed for features requests from our customers and in reviewing this feature it was determined that most (if not all of the votes) came from an outside source. In an effort to validate this we polled a number of shared hosting providers that we work closely with and this was not a feature they wanted.

While cPanel wants feedback from the general community, our focus is to deliver new features that our Partners and customers are asking for.

We always appreciate community support and will keep an eye on this feature. Decisions for new features are made by both reviewing this feature request system and talking with Partners and customers. To date out of about 15 conversations, not a single Partner or customer told us this was something that was important to them and thus we adjusted the votes to what we felt was more in line with the community using our system.

I have a couple of issues with the above reply.

For starters there was no communication and no warning that would have indicated what was going to happen with our votes. cPanel decided on this on their own. They do have the right to do so, it's their software after all, but a little courtesy would have gone a long way.

The definition of "customers" is different to me than it is to cPanel. As customers cPanel defines their partners and hosting companies, the ones that purchase their software. Myself on the other hand considers customers also the end user, me and you who visit a hosting company and purchase services from them. If we do not exist, then a hosting company and subsequently cPanel does not exist either.

cPanel asked a number of their partners who have not heard of Phalcon before, and as such they acted based on that premise. What would have happened if their sample was a different one? Say they asked partner X instead of partner Y? The bias of statistics is based on the sample one chooses and at times (such as this one) it could lead to false results.

In my reply I pointed out the above, stating that a customer should effectively be the end user and if not, at least their voice should be heard. The reply that I got was as follows:

Thanks for the reply and understanding. In reviewing the votes that came in, most appeared to be brand advocates of Phalcon and it was very difficult to discern the legitimacy of the votes. Had the votes come from active users of forums.cpanel.net (where most of the users originate from) or we were able to relate them back to some sort of hosting entity, we would have left the votes.

From the outside looking in the votes just appeared to come from Phalcon users without ties to cPanel & WHM. What I would encourage you to do is the following:

Have your users ask their hosting provider about it.

Remove the blog links and tweets and allow the feature to grow it's own set of wheels.

If this feature is truly in high demand from customers of cPanel, Inc. they will naturally vote for it.

We do appreciate your support and ongoing efforts to get this in front of us. The massive amounts of votes and comments it received, put it on our developers radars and we will continue to monitor the situation.

So in essence, if we want to achieve our objective, i.e. get Phalcon as an available extension for cPanel, we need to advise the community (but be careful to Remove the blog links and tweets and allow the feature to grow it's own set of wheels.) to contact their hosting companies (that use cPanel) to in turn contact cPanel and request Phalcon to be included as an extension.

The fallacy of the above is that developers of Phalcon will not choose hosts that offer cPanel because they cannot install the application. If they cannot install the application they will not use hosts that offer cPanel, thus they cannot ask their hosts to include Phalcon as a cPanel extension, and so goes the chicken and egg situation.

I totally respect cPanel's decisions - I don't agree with them but I do respect them. It's their house their rules as they say. I am however saddened by the fact that we never got any communication or warning that our votes were removed. A bit of communication there would have definitely saved a lot of frustration at least for our community.

Concluding, if anyone has a cPanel hosting account and wants to see Phalcon available as an extension, feel free to contact your host and request it to be included as an available extension.

2013-07-25 Update: A great analogy and reply has been posted by Andres in the Phalcon Forum.

2013-05-27 12:00:00

2013 Memorial Day

Once again we celebrate Memorial Day in the USA.

A very special day, dedicated to remembering and honoring all those men and women in uniform that fought for freedom. Freedom that nowadays - in most cases - is taken for granted.

A personal thank you to all of those that paid the ultimate price, with their life, so that my family, myself, my neighbors, my co-patriots can enjoy what we have today: our freedom.