Getting Developer’s Perception on PhalconPHP

Getting Developer’s Perception on PhalconPHP

VitaliyKoziyPhalconPHP Framework is insanely fast in performance – that really matters. It is a C-extension to PHP, and its source is written in C . Phalcon shows the highest performance benchmark among others, with the lowest memory usage – according to System Architect (Performance benchmark of popular PHP frameworks). [/testimonial]

 

PhalconPHP Development Is A Densely-Featured Process

At the moment of writing this article, the relevant version of Phalcon Framework is 1.3.4. There is the version 2.0 coming out soon. I have to mention that the version 2.0 will be fully compatible with older versions. It means, that you won’t get any problems updating to a newer version. After updating, you will be able to choose whether to use new version features or continue supporting your project with version 1.3 features.
By the way, you may already use Phalcon 2.0 Alpha 1.

Phalcon and OS

Phalcon PHP development perfectly works on the following operating systems:

  • Windows
  • Linux/Solaris/Mac
  • FreeBSD

I won’t talk about installing the framework, you may read about this here. But, I have to mention that Phalcon also works with IIS (you may review the installation process here or here).

Webserver

In order to be able to work with the framework you may use:

  • Apache
  • Nginx
  • Cherokee

If you have a choice what to choose, Phalcon Community recommends you to use Phalcon + Nginx + PHP-FPM, this bundle will help you to get the best results. The oldest PHP version recommended is 5.3.11. By the way, Phalcon 2.0will work with PHP 5.6 as well, which is awesome!
There is no need to explain how to create an application, as it is already explained in the following documentation.
I just want to add that in order to create the project it’s highly recommended to have the following components installed:

Phalcon Developer Tools will help you to create the skeleton of the project. In Windows, I suggest you to add the path for already installed Phalcon Developer Tools to the system PATH variable. It will allow you to run Phalcon command in Command Line via a random directory. Also, by using Phalcon Developer Tools you allowed to generate models and controllers.

So, now we have the skeleton of our project. For the right flexibility in development process, add the following env-variable in your virtual host settings:

Apache: SetEnv APPLICATION_ENV name_of_variable
Nginx: fastcgi_param APPLICATION_ENV name_of_variable;

I set dev as a name_of_variable – that is for local development; stage for test server and prod for production.

Settings for Version Control System – I suggest all the files that have to be ignored to write as below:

*-dev.php
*-stage.php
*-prod.php

In that case, the file with the name db-dev.php automatically will get ignored, and you won’t be bothered that somebody may change it.

So, why we needed env-variable? We needed it for the right configuration connection at the appropriate server. The following piece of code will show you database config connection on every server:

if (isset($_SERVER[‘APPLICATION_ENV’])) {
switch ($_SERVER[‘APPLICATION_ENV’]) {
case ‘dev’:
$db = require_once (ROOT_DIRECTORY . ‘config’ . DIRECTORY_SEPARATOR . ‘db-dev.php’);
error_reporting(E_ALL);
break;
case ‘stage’:
$db = require_once(ROOT_DIRECTORY . ‘config’ . DIRECTORY_SEPARATOR . ‘db-stage.php’);
break;
default:
$db = require_once (ROOT_DIRECTORY . ‘config’ . DIRECTORY_SEPARATOR . ‘db-prod.php’);
break;
}
} else {
exit(‘Please set ENV in your virtual host configuration. ‘);

It also allows controlling error output.

When I started working on the project, I faced the problem ‘What type of the project I need to choose, Micro application or the full version?’
The first thing you should pay attention to is that Micro is designed for writing API projects without view template usage. There are none in Micro. There is no beforeExecuteRoute() method, that I lacked as well. Sure you may create an event via EventManager that will start before the action runs.
Working for some time with Micro, I finally moved the project to the full version of the application.

Routing

You should put all the routes into separate file, and connect it via the services. Here I faced the problem that the website did not want to run on routes. The reason was that I had to add the namespace to the routing first. There are two ways. The first one is to input namespace to the every route:

$router->add(“/login”, array(
‘namespace’ => ‘Backend\Controllers’,
‘controller’ => ‘login’,
‘action’ => ‘index’

The second way is to install the default namespase. It is usually used for connecting router in services:

$di->set(‘router’, function() {
$router = new \Phalcon\Mvc\Router(false);
$router->setDefaultNamespace(‘\Controllers’);
$router->removeExtraSlashes(true);
include ROOT_DIRECTORY . ‘config’.DIRECTORY_SEPARATOR.’routes.php’;
return $router;
},true);

Router is a tricky thing. It works perfectly with REST. So, you may clearly see how should you connect to the following action:

$router->addPost(…),$router ->addGet(),$router ->addPut(…),$router ->addDelete(…).

You may also allow two different HTTP methods to connect

$router->add(“/products/update”)->via(array(“POST”, “PUT”));

In the actual routes.php file you may set the logic. Logic is set with the help of:

  • anonymous functions:

$router ->get(‘/api/robots’, function() {
… … …
});

  • regular functions:

function say_hello($name) {
echo “Hello! $name”;
}
$router->get(‘/say/hello/{name}’, “say_hello”);

  • controllers:

$router->add(
“/admin/users/change-password”,
array(
“controller” => “users”,
“action” => “changePassword”,
)
);

Working with Models and Databases

In order to generate the model, you may use Phalcon Developer Tools, using the following command – phalcon create-model –table-name products, where products is the name of the table. But, you will need to input connections manually, using hasMany, hasOne, belongsTo, hasManyToMany commands.
All the models I use came from class BaseModel extends \Phalcon\Mvc\Model. Here I have initialized the following Behavior:

  • delete by id method (unfortunately, when there is no formed object that has to be deleted, this type of a method – deleteById($id – is absent in the framework).
  • call DI method, that returns \Phalcon\DI::getDefault().

There are After and Before model methods – beforeValidate(), afterSave() etc.

Database Requests with Connection

First you have to set a database connection

$connection = new \Phalcon\Db\Adapter\Pdo\Mysql(array(
“host” => “localhost”,
“username” => “root”,
“password” => “sigma”,
“dbname” => “test_db”,
“options” => array(
PDO::MYSQL_ATTR_INIT_COMMAND => “SET NAMES \’UTF8\'”,
PDO::ATTR_CASE => PDO::CASE_LOWER
)
));

1) Request using unnamed pseudo variables.

sql = “SELECT * FROM robots WHERE name = ? ORDER BY name”;
$result = $connection->query($sql, array(“Wall-E”));


2) Request using pseudo variables with the names

$sql = “INSERT INTO robots(name, year) VALUES (:name, :year)";
$success = $connection->query($sql, array("name" => "Astro Boy", "year" => 1952));

The performance of $connection->query($sql); returns Phalcon\Db\Result\Pdo Object, so for getting the results, you should do $result->fetch() - it will pull the first record. And in order to handle all the data, you should perform the following:

while ($robot = $result->fetch()) {
echo $robot["name"];

In the log you may see, that the request to the database is performed only once, only while при $connection->query($sql);
Using $connection->query($sql); allows you to rule the process of returning data types

Constant Description
Phalcon\Db::FETCH_NUM
Phalcon\Db::FETCH_ASSOC
Phalcon\Db::FETCH_BOTH
Phalcon\Db::FETCH_OBJ
Return an array with numeric indexes
Return an array with associative indexes
Return an array with both associative and numeric indexes
Return an object instead of an array
$result = $connection->query($sql);
$result->setFetchMode(Phalcon\Db::FETCH_NUM);

3. Using fetchAll() returns all the results and fetchAll() as a result in the form of arrays


$robots = $connection->fetchAll($sql);
$robot = $connection->fetchOne($sql);

4. Using execute(). This method is used for INSERT, DELETE,UPDATE

$sql = "INSERT INTO robots(name, year`) VALUES (‘Astro Boy’, 1952)”;
$success = $connection->execute($sql);

As we may see in examples 2 and 4 – there is a INSERT query is performed. The difference is that for random query, even for SELECT $connection->execute($sql); it always returns true\false, comparing to $result = $connection->query($sql); but in case of INSERT $result->fetch(), it returns empty array.

5. PHQL queries

  • Queries as an example of the class Phalcon\Mvc\Model\Query
$query = new Phalcon\Mvc\Model\Query(“SELECT * FROM Cars”, $di);
$cars = $query->execute();
  • Use of Phalcon\Mvc\Model\Manager
$di->set(‘modelsManager’, function() {
return new Phalcon\Mvc\Model\Manager();
});
$cars = $this->modelsManager->executeQuery(“SELECT * FROM Cars”);
  • Use of Phalcon\Mvc\Model\Query\Builder()

You may use the one that is already installed into di modelsmanager

(‘modelsManager’, function() {
return new Phalcon\Mvc\Model\Manager();
});
$robots = $this->modelsManager->createBuilder()
->from(‘Robots’)
->join(‘RobotsParts’)
->order(‘Robots.name’)
->getQuery()
->execute();

Or you may install it into di Phalcon\Mvc\Model\Query\Builder()

$di->set(‘builder’, function() {
return new \Phalcon\Mvc\Model\Query\Builder();
});
$robots = $this->getBuilder()
->from(‘Robots’)
->join(‘RobotsParts’)
->order(‘Robots.name’)
->getQuery()
->execute();

6. Active Record

  • Finding Records

$cars = Cars::find(array(“order” => “name”));

$robot = Robots::findFirst();

$robots = Robots::query()
->where(“type = :type:”)
->andWhere(“year < 2000”)
->bind(array(“type” => “mechanical”))
->order(“name”)
->execute();

$robot = Robots::findById($id);

$robot = Robots::findFirstByName($name);

Phalcon knows how to choose data by feature names, the last example shows it, it’s construction is findFirstBy ().
The difference between Robots::FindById($id) and Robots::FindFirstById($id) is that the first one will return the object with the following type – Phalcon\Mvc\Model\Resultset\Simple and the second one will return Robots object. So, in that case, while using beforeDelete() from FindById(), the certain problems may occur. Read more.

  • Save/Update/Inser/Delete
$robot->save(); – creates when there is no record and updates when the record exists
$robot->update(); – updates the record
$robot->create(); – creates the record
$robot->delete(); – deletes the record

Unfortunately, there is no such method as deleteByID(), so in order to delete the record, you should pull it out first, and then delete.

$robot = Robots::findFirstById($ud)
$robot->delete();

IDE

When working with Phalcon in IDE, I was really confused by framework method autocompletes absence. This issue was resolved for two IDEs – Netbeans and Sublime Text.
For Netbeans, add the path of installed Phalcon Developer Tools into the path to include. It should look like this:
path_to_phalcon-devtools\ide\1.3.2\Phalcon\
For Sublime Text, there is a special plugin you may use in order to resolve that problem.

In order to raise my own level of Phalcon development, I suggest that you use the Phalcon forum and visit GitHub. In those repositories, you may send pull requests with bug fixes or with new version of documentation:)

Related Posts

Leave a reply