Learning Phalcon PHP - Sample Chapter
Learning Phalcon PHP - Sample Chapter
$ 49.99 US
31.99 UK
P U B L I S H I N G
pl
C o m m u n i t y
E x p e r i e n c e
D i s t i l l e d
Sa
m
ee
Calin Rada
Preface
Phalcon is the fastest PHP framework out there, and it is delivered as a C extension.
More than that, you will find it very easy to learn. This book will present in detail the
most common and useful parts of Phalcon PHP, as well as guide you to lean towards
making the right decision when developing a Phalcon-driven application.
Learning Phalcon PHP is an interesting journey that starts with guides for installing
the required software and preparing the working environment and project structure,
and continues with a step-by-step approach development of each module.
By the end of this book, you will have developed a simple but fully functional news
website and gained advanced knowledge on how Phalcon works.
Preface
Before starting, we assume that you are using a *nix environment. Personally, I feel
comfortable with Debian distributions, especially Ubuntu, which I am using on a
daily basis; so, the installations steps that we will talk about are for Ubuntu. The
OS is a matter of personal choice, but I highly recommend any *nix distribution for
development. (Even Microsoft decided to open source their ASP.NET for Linux early
this year)
For other types of OS, you will have to search their official documentation, in terms
of "how to". This book is intended to be about Phalcon and tutorials on installing
different software on different kinds of OS are out of the scope of this book.
[1]
http://docs.phalconphp.com/en/latest/
reference/install.html#windows
http://docs.phalconphp.com/en/latest/
reference/install.html#mac-os-x
http://docs.phalconphp.com/en/latest/
reference/install.html#freebsd
Senior developers might not agree with me on certain subjects or certain techniques
and/or recommendations. In general, as a developer, I think you should analyze
what is suitable for you and develop a platform according to your (or client)
requirements. In addition, most importantly, there is no such thing as "The Perfect
Solution". There is always room for improvement.
PHP
MongoDB
MySQL
GIT
Redis
Phalcon
Installing PHP
You have probably already installed PHP on your system since you are reading this
book. However, just in case you haven't, here are the simple steps to quickly install
the latest PHP version (Phalcon is running on PHP version >= 5.3). I recommend you
to use the Personal Package Archive (PPA) from Ondej Sur (https://launchpad.
net/~ondrej/+archive/ubuntu/php5) because it has the latest PHP version
available on it:
$ sudo add-apt-repository ppa:ondrej/php5
$ sudo apt-get update
[2]
Chapter 1
If you don't want to use this step, you can simply install PHP from the official
repositories:
$ sudo apt-get install php
Apache will be installed by default with PHP. However, if you want Nginx instead
of Apache, you must install PHP in a certain order.
The following command will automatically install PHP and Apache. If you don't
need/want to use Apache, please skip using this command:
$ sudo apt-get install php5 php5-fpm
The php5-cgi package fulfills the dependencies that would otherwise be fulfilled
by Apache.
Installing Nginx
To install the Nginx web server, we need to execute the following commands:
$ sudo add-apt-repository ppa:nginx/stable
$ sudo apt-get update
$ sudo apt-get install nginx
Installing MySQL
MySQL is probably the most widely spread RDBMS system with a market share that
is greater than 50 percent. Since we are going to use it to develop our project, we
need to install it by executing the following command:
$ sudo apt-get install mysql-server
Installing Redis
Redis is an advanced key-value storage/cache system. We are going to use this
mostly for our session and to cache objects to improve the speed of our application.
Let's install it by executing the following commands:
$ sudo add-apt-repository ppa:chris-lea/redis-server
$ sudo apt-get update
$ sudo apt-get install redis-server
$ sudo apt-get install php5-redis
Installing MongoDB
MongoDB is a document database (NoSQL database) system. We will use this to
store data that is accessed frequently. Let's install it:
$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv
7F0CEB10
$ echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart
dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list
$ sudo apt-get update
$ sudo apt-get install -y mongodb-org
$ sudo service mongodb start
$ sudo apt-get install php5-mongo
Installing Git
Git is a distributed version control system that we will use to track changes to our
application and much more. We will install Git by executing the following command:
$ sudo apt-get install git
I strongly recommend that you use the latest versions of all software
as much as possible.
Installing Phalcon
Now that we have installed all the required software, we will proceed with the
installation of Phalcon. Before we continue, we must install some dependencies:
$ sudo apt-get install php5-dev libpcre3-dev gcc make php5-mysql
[4]
Chapter 1
For Windows systems and more details about how to compile the extension on
different systems, please check the latest documentation at http://phalconphp.
com/en/download.
Now, we can clone the repository and compile our extension:
$ git clone --depth=1 git://github.com/phalcon/cphalcon.git
$ cd cphalcon/build
$ sudo ./install
$ echo 'extension=phalcon.so' | sudo tee /etc/php5/mods-available/
phalcon.ini
If everything goes well, you should be able to see Phalcon in the list of PHP
installed modules:
$ php -m | grep phalcon
Of course, if you want, you can use another folder. Let's create a test file in our
public folder under the root directory with some PHP content:
$ cd /var/www/learning-phalcon.localhost/public
$ echo "<?php date();" > index.php
Apache
Let's switch to the default directory where Apache holds the configuration files
for the available websites, using the command line: $ cd /etc/apache2/sitesavailable/. After that, perform the following set of steps:
1. Using your favorite editor, create a file named learning-phalcon.localhost
for apache version < 2.4 or learning-phalcon.localhost.conf for apache
version >= 2.4:
$ vim learning-phalcon.localhost.conf
[5]
3. Then, switch to the public folder and add a file named .htaccess to it:
$ cd /var/www/learning-phalcon.localhost/public
$ vim .htaccess
5. This will not work unless you have enabled mod_rewrite. To do so, execute
this command:
$ sudo a2enmod rewrite
6. Now that we have configured our virtual host, let's enable it:
$ sudo a2ensite learning-phalcon.localhost
$ sudo service apache2 reload
Chapter 1
Nginx
If you choose to use Nginx (which I recommend, especially because it can serve
more concurrent clients with higher throughput, and it serves static content more
efficiently) instead of Apache, here is what you need to do:
Locate the config folder of Nginx (in Ubuntu, it is installed under /etc/nginx/).
Create a file named learning-phalcon.localhost in your sites-available folder
(by navigating to /etc/nginx/sites-available):
$ cd /etc/nginx/sites-available
$ vim learning-phalcon.localhost
In some environments, you might need to edit your php.ini file and set
cgi.fix_pathinfo = 0.
Please edit and save your host file (check The host file section), then open your
browser and type http://www.learning-phalcon.localhost/. At this point,
you should see a page that shows the current date/time.
There are many possible methods to install and configure PHP and Apache/Nginx.
Feel free to do a simple Google search and choose one that fits you better, if my
method is not the optimal one for your needs.
Assuming that everything went well until now, we will go further by learning a little
bit about Phalcon's internals.
[8]
Chapter 1
Please note that images in this book might contain the text http://
learning-phalcon.dev. You need to ignore that and use http://
learning-phalcon.localhost as suggested in the chapter.
Logger
Crypt
Flash
[9]
View
Cache
Session
When you need to access the "mail" component, in a controller for example, you can
simply call it:
<?php
$mail = $this->getID()->get('mail');
// or
$mail = $this->getDI()->getMail();
If you need to create your own DI, Phalcon or the DiInterface interface must
be implemented to replace the one provided by Phalcon, or you must extend the
current one.
These are just a few dummy examples so that you can have an idea about Phalcon's
DI by the time we start our project. In the meanwhile, please take your time and read
the official documentation that can be found at http://docs.phalconphp.com/en/
latest/reference/di.html.
Chapter 1
Okay. So, how do we use the request component? Easy! Do you remember that we
talked about built-in components in the DI section? The request component is one of
them. All we need to do is get the DI. Here is an example of how to get and use the
request component:
<?php
class ArticleController extends \Phalcon\Mvc\Controller
{
public function searchAction()
{
$request = $this->getDI()->get('request');
// You can also use $request = $this->request; but I don't
// recommend it because $this->request can be easily overwritten
// by mistake and you will spend time to debug ... nothing.
$request->getMethod(); // Check the request method
$request->isAjax(); // Checks if the request is an ajax
request
$request->get(); // Gets everything, from the request (GET,
POST, DELETE, PUT)
[ 11 ]
These are just a few common methods that are built into the request component.
Let's continue with the next important componentResponse.
/**
* Redirect by HTTP to another action or URL
*
* @param string $location
* @param boolean $externalRedirect
* @param int $statusCode
* @return \Phalcon\Http\ResponseInterface
*/
public function redirect($location, $externalRedirect,
$statusCode);
[ 12 ]
Chapter 1
The preceding example sets a header named APIKEY with the value as
AWQ23XX258561. Sending headers is a common approach when you develop APIs.
You can send any type of headers and overwrite current headers using this method.
Content related methods: setContent() and setJsonContent(). Let's take for
example the following code:
<?php
public function testContentAction()
{
// First, we disable the view if there is any
$this->view->disable();
// Set a plain/text or html content
$this->response->setContent('I love PhalconPHP');
// OR
// Set a json content (this will return a json object)
$this->response->setJsonContent(array(
'framework' => 'PhalconPHP'
'versions' => array(
'1.3.2',
'1.3.3',
'2.0.0'
)
));
// We send the output to the client
return $this->response->send();
}
[ 13 ]
When you need to send any JSON content, you should set the header as
application/json using the built-in method in the response object:
<?php
$this->response->setContentType('application/json', 'UTF-8');
Now that we know the basics about response/request components, we might find
ourselves in a situation where we may need to log different things, such as errors.
For this, we need to check the logger component.
2. Create a method that will throw an exception, catch it, and log it, as follows:
<?php
public function testLoggerAction()
{
try {
$nonExistingComponent = $this->getDI()->get(
'nonExistingComponent');
$nonExistingComponent->executeNonExistingMethod();
} catch (\Exception $e) {
$this->logger->error($e->getMessage());
return $this->response->redirect('error/500.html');
}
}
[ 14 ]
Chapter 1
In the preceding example, we try to execute a nonexistent method, and our code
will throw an exception that we catch. It will log it and then redirect the user to a
friendly error page, error/500.html. You will notice that our logger component
calls a method named error. There are other methods that are implemented, such
as, debug, info, notice, warning, and so on.
The logger component can be transactional. (Phalcon stores the logs temporarily
in memory, and later on, it writes the data to the relevant adapter.) For example,
consider the following code snippet:
<?php
$this->logger->begin();
$this->logger->error('Ooops ! Error !');
$this->logger->warning('A warning message');
$this->logger->commit();
[ 15 ]
Of course, you are probably never going to use it this way. The preceding example
just demonstrates the power of this component. You might have noticed that there
is a new DI method called flash. We are going to talk about it next.
Chapter 1
In our view, we will render the messages using the getContent() method or
content() in the template engine Volt (we'll cover this later in the chapter).
If we need to redirect our user to another page (let's call it registerSuccess), then
we need to use the flash session method; otherwise, the message will not appear.
<?php
The register template will contain a form with method post and action pointing
to the create method. The create method will look something like this:
<?php
public function createAction()
{
if ($errors) {
$this->flashSession->warning('Please fix the following errors: ');
foreach($errors as $error) {
$this->flashSession->error($error);
}
} else {
$this->flashSession->success('You have successfully registered
on our website');
}
return $this->response->redirect('/register');
}
In the preceding example, we set the messages in the session using the
flashSession method, and we redirect the user back to the register page. In order
to render the messages in our view, we need to call the method flashSession()>output();.
The recommended way is to forward the request with the help of
dispatcher, not using redirects. If you use redirects, the user will
lose all the data that he or she filled in the form.
[ 17 ]
However, sometimes, this code is not apt if you need to translate the URLs into
multiple languages, or if you need to name the URLs in a different way to how
they are defined in the code. Here is a usage example for the router component:
<?php
$router = new \Phalcon\Mvc\Router();
// Clear the default routes
$router->clear();
$st_categories = array(
'entertainment',
'travel',
'video'
);
$s_categories = implode('|', $st_categories);
$router->add('#^/('.$s_categories.')[/]{0,1}$#', array(
'module' => 'frontend',
'controller' => 'post',
'action' => 'findByCategorySlug',
'slug' => 0
));
[ 18 ]
Chapter 1
In the preceding example, we map all the categories to the controller post and action
findByCategorySlug. The router component allows us to use regular expressions
for our URLs. With preg_match, this can be represented as follows
$url = 'http://www.learning-phalcon.localhost/video';
preg_match('#^/(entertainment|travel|video)[/]{0,1}$#', $url);
The getParam() method has three parameters. The first one is the name that we
are searching for, the second parameter is an array of filters that can be applied
automatically, and the third parameter is the default value in case the requested
name does not exist or is not set.
We will discuss models in the next chapter. This was just a simple example of how
you can use the router.
The router also supports a precheck of the request method. You may be used to
check whether the method is POST, DELETE, PUT, or GET, like this:
<?php
if ($_SERVER['REQUEST_METHOD'] == 'post') {
// process the information
}
[ 19 ]
While this is perfectly correct, it is not very friendly for our code. Phalcon's router
has this capability by which you can add the right type of request that you are
expecting, without the need to check this in your code:
<?php
// Add a get route for register method within the user controller
$router->addGet('register', 'User::register');
// Add a post route for create method, from the user controller
$router->addPost('create', 'User::create');
This is the basic usage of the router. As always, please read the documentation in
order to learn everything about this component.
You can find out more about routing on the official documentation
at http://docs.phalconphp.com/en/latest/reference/
routing.html.
Chapter 1
'name' => 'Learning Phalcon'
)
);
$config = new \Phalcon\Config($st_settings);
// Get our application name:
echo $config->app->name; // Will output Learning Phalcon
The config object can be converted back to an array by using toArray() method:
<?php
$st_config = $config->toArray();
echo $config['app']['name']; // Will output Learning Phalcon
Another useful method for this object is the merge method. If we have multiple
configuration files, we can easily merge them into one object:
<?php
$config = array(
'database' => array(
'adapter' => 'Mysql',
'host'
=> 'localhost',
'dbname'
=> 'test_database',
),
'app' => array(
'name' => 'Learning Phalcon'
)
);
$config2 = array(
'database' => array(
'username' => 'john',
'password' => 'johndoe',
)
Now, the $config object will have the same content as it did before.
There are two other adapters that are not implemented yet (YAML
and JSON), but you can use them if you clone Phalcon's incubator
repository (https://github.com/phalcon/incubator). This
repository contains a collection of adapters/helpers that might be
integrated in Phalcon in the near future.
[ 21 ]
3. Next, we need to create a view template that must look like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><?php echo $pageTitle; ?></title>
</head>
<body>
<?php foreach($posts as $post) { ?>
<p><?php echo $post->getPostTitle(); ?></p>
<p><?php echo $post->getPostContent(); ?></p>
[ 22 ]
Chapter 1
<?php } ?>
</body>
</html>
Simple, isn't it? This component also supports hierarchical rendering. You can have a
base layout, a general template for posts, and a template for a single post. Let's take,
for example, the following directory structure:
app/views/
- index.phtml
- post/detail.phtml
This component also allows you to pick different templates to set a render level,
disable or enable the view, and much more.
Phalcon has a built-in template engine named Volt. If you are familiar with PHP
template engines such as Smarty or Twig, you will want to use them for sure. Volt
is almost identical to Twig, and you will find it very usefulit is inspired by Jinja
(http://jinja.pocoo.org/). You can even use your own template engine, or any
other template engine that you can find there.
[ 23 ]
In order to enable the Volt template engine, we need to make a small modification
to our view service, and we need to create a Volt service; here is how to do this:
<?php
$di['voltService'] = function($view, $di) use ($config) {
$volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
if (!is_dir($config->view->cache->dir)) {
mkdir($config->view->cache->dir);
}
$volt->setOptions(array(
"compiledPath" => $config->view->cache->dir,
"compiledExtension" => ".compiled",
"compileAlways" => false
));
$compiler = $volt->getCompiler();
return $volt;
};
// First, we setup the view in the DI
$di['view'] = function () use ($config) {
$view = \Phacon\Mvc\View();
$view->setViewsDir($config->view->dir);
$view->registerEngines(array(
'.volt' => 'voltService'
));
return $view;
};
By adding this modification and voltService, we can now use this template engine.
From the inheritance point of view, Volt acts a little bit differently. We first need
to define a main layout with named blocks. Then, the rest of the templates should
extend the main layout, and we need to put our content in the same blocks as the
main layout. Before we look at some examples, I will tell you a little bit about Volt's
syntax, the details are as follows.
[ 24 ]
Chapter 1
The syntax to extend a template (this should be the first line in your
template):
{% extends 'layouts/main.volt' %}
The list is long. Additionally, you can use expressions, comparison operators, logic
operators, filters, and so on. Let's write a simple template to see how it works:
<!-- app/views/index.volt -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block pageTitle %}Learning Phalcon{% endblock%}</title>
</head>
[ 25 ]
You can read the full documentation for the view component at
http://docs.phalconphp.com/en/latest/reference/
views.html and for Volt at http://docs.phalconphp.com/
en/latest/reference/volt.html.
[ 26 ]
Chapter 1
If you check Phalcon's incubator, there are many available adapters, such as Redis,
Database, Memcache, and Mongo. You can also implement your own adapter.
You can read the official documentation at http://docs.phalconphp.
com/en/latest/reference/session.html.
[ 27 ]
4. If the user table has relations, the ORM will repeat each of the preceding
steps for each relation.
To solve this problem, we will save the post object into our caching system.
Personally, I use Redis and Igbinary. Redis is probably the most powerful tool,
since it stores the data in memory and, saves the data on disk for redundancy. This
means that every time you request the data from cache, you will get it from memory.
Igbinary (https://pecl.php.net/package/igbinary) is a replacement for the
standard php serializer. Here is an example cache service:
<?php
$di['redis'] = function () {
$redis = new \Redis();
$redis->connect(
'127.0.0.1',
6379
);
return $redis;
};
$di['cache'] = function () use ($di, $config) {
$frontend = new \Phalcon\Cache\Frontend\Igbinary(array(
'lifetime' => 86400
));
$cache = new \Phalcon\Cache\Backend\Redis($frontend, array(
'redis' => $di['redis'],
'prefix' => 'learning_phalcon'
));
return $cache;
};
[ 28 ]
Chapter 1
The cache component has the following methods that are commonly used:
<?php
// Save data in cache
$this-cache->save('post', array(
'title' => 'Learning Phalcon',
'slug' => 'learning-phalcon',
'content' => 'Article content'
));
// Get data from cache
$post = $this->cache->get('post');
// Delete data from cache
$this->cache->delete('post');
Summary
In this chapter, we installed the required software, created the configuration files
for the web servers, and you learned a little bit about Phalcon's internals. In the
next chapters, we will learn by example, and everything will be much clearer.
Take your time, and before going further, read a little bit more about anything in
which you don't have experience.
In the following chapter, we will look at how to set up the MVC structure and the
environment for our project.
[ 29 ]
www.PacktPub.com
Stay Connected: