Explore this website

Stalk me on the internet

Search

  • How to cache static files with Apache
  • How to create a PHPixie helper to create dynamic names for javascript & CSS files
  • How to cache dynamic named files with Apache

Required

  • Nothing

Tutorial

Inspired by HTML5 Boilerplate.

I mentionned javascript and CSS files, but you can do this tutorial for any kind of files (xml, json, png, jpg, …). Actually, you must apply this tutorial to most of the files you serve.

The Setup

Go to your public .htaccess. Under PHPixie, the file is located in project/web/.htaccess.

The default PHPixie .htaccess comes with these lines :

/web/.htaccess

You will need to add the following lines at the beginning :

/web/.htaccess

So what are ETags and Expire headers ?

ETags

ETags are part of the HTTP protocol sent by Apache to tell if a file has been modified since the last time it was requested.
Every time a returning user requests the server, Apache replies with “The file you have in cache is outdated, here is the new one.” or “I won’t send you the file, use the one in cache”.

This means the first time a user comes on your website, he will retrieve every files possible; let’s say he receives 800Kb from the server. The second time, if most of the files did not change on the server, it will only send him the necessary, maybe something like 230Kb.

Here is a screenshot of the use of ETags :

Network stats with ETags

You can see that the server responses are only a few bytes (“transfered” column) once the files are cached.

Now, why would we disable this feature ? Because Expire headers are even greater and can be used alone.

The problem with ETag is that the user still requests the server for each files. In the previous screenshot, the user could just request for the Document file (the HTML file). Expire headers bring the solution !

Expire headers

Expire headers tells the user’s browser to use the cache filed without even checking if a new one exists.

Here is a screenshot of the same page but using Expire hearders instead of ETags :

Network stats with Expire headers

As you can see, there is only 1 transfer for the entire page ! So if you use Expire headers for all the files you serve, there is no need for ETags. Otherwise you will need both of them. More info here : Expire headers by type.

This great caching solution brings a problem: What if you modify your css or javascript ? The user’s browser won’t be informed and will keep on using the old cached files. This is where we will use PHP and create dynamic filenames.

Dynamic names

There is an old technique that doesn’t modify the name of the files directly but adds a query string version. It is used to turn http://example.com/css/theme.css into http://example.com/css/theme.css?v=1415493070. And when you modify the file, the algorithm increments the version number so that the user will get a new version.

This is actually a good technique however some HTTP Accelerator/Proxy servers, like Squid, won’t cache any files with a query string. And this is not what we want. Instead we will use the technique recommanded by HTML5 Boilerplate that consists in turning http://example.com/css/theme.css into http://example.com/css/theme.1415493070.css.

Of course, everytime you modify your theme.css, you won’t need to manually change its name.

So we will create a PHPixie helper for this “renaming modified files” task. Create a php file under project/classes/App/Helper/Helper.php (name it as you wish, I went for Helper) that extends PHPixie default Helper.

/classes/App/Helper/Helper.php

Those using composer, don’t forget to update your classes’ path.

This helper uses the PHP function filemtime to get the last modified time of the file.

Using the helper

The only thing left to do is call this helper in your main.php or in any other views :

/assets/views/main.php

If you wish to call this function in Controllers instead of Views, don’t create a Helper. Instead you should move the function autoversion($url) to your Controllers or even Controller\Page.php to set it for all your Controllers.

Routing the dynamic names

The final step is to tell Apache that when a user asks for theme.1415493070.css, he should receive theme.css.

Add the following to your .htaccess :

/web/.htaccess

 

Done !

Creating an admin backend

Posted by on 04.09.2014 in Tutorial
  • How to create a hidden admin backend
  • How to manage admin routes
  • How to manage an admin namespace

Required


Tutorial

Basically this tutorial covers the following steps :

  1. Setting up PHPixie
  2. Creating the database
  3. Creating the admin routes
  4. Creating the admin namespace
  5. Creating the admin controllers

 

The Setup

First download PHPixie and the module Authentication.
You can learn more about this module with this post.

Create a file under assets/config/ and call it auth.php.

assets/config/auth.php

The Database

Create the following with MySQL :

SQL

Then create a user with email admin@admin.com and password password, give him the role of admin and also create a non-admin role.

SQL

The Admin Routes

Go to your config file assets/config/routes.php and add the following before the default route.

assets/config/routes.php

So that every URL starting with http://example.com/admin will automatically target the namespace App\Admin.

The Admin Namespace

Now, we will need to limit the admin access to admins only.

Let’s go to classes/App/Page.php, the parent of all your controllers then modify the before function.

classes/App/Page.php

Note: The 404 redirection used is not proper to PHPixie and can create conflict with the flow of the framework.

Regarding the login process, you can learn more here or at the official PHPixie website.

The Admin Controllers

You can now create your own controllers under the folder classes/App/Admin/Controller/.

For example, a Dashboard under the Home controller :

classes/App/Admin/Controller/Home.php

As for your view, create them under the folder assets/views/admin/ – The subview in the example will call the file at assets/views/admin/home.php.

Remember to put the namespace App\Admin\Controller to all your admin controllers !

ORM Documentation

Posted by on 13.04.2014 in Documentation

More info on ORM Documentation for PHPixie

Update

  • July, 2014
    • [Add] Offset
  • May, 2014
    • [Add] Where in
  • April, 2014
    • [Add] Where like
    • [Add] Query result > Looping the results
    • [Add] Running queries > Multiple where
    • [Up] Additionnal description on Query result

Setting up ORM

For each table you will need to create a Model called after your table’s name. (You may exclude relation tables if they only have 2 foreign key columns with no additional data).

Here is an example with the User table

 

Running queries

Custom function

Using a function you created in the your model.

 

Multiple WHERE

Doing multiple WHERE (AND)

Doing multiple WHERE (OR)

 

Join query

Joining tables with has_one or belongs_to.

 

WHERE LIKE

Using WHERE column LIKE value.

 

WHERE IN

Using WHERE column IN value, …

 

OFFSET

Using OFFSET value

 

 

Query results

Looping the results

To get the result of your query, you usually do a find_all().

The problem of these lines is that you cannot do a second foreach on $users. You can only pass through a single time.

Instead, convert it to an array of objects.

Or you can do it the pure array way passing the parameter true.

 

Executed query on a single table

Query result on a single table

 

Executed query on multiple tables (JOIN)

Query result on a few tables with join statements (has_one and belongs_to relations)

Warning about prepare_relations
Executing prepare_relations() will create aliases for the JOIN query. This means you cannot prepare_relations() then find/find_all() because they will recreate the aliases (as they internally execute prepare_relations) resulting in a SQL error.

  • How to access php variables in a view

Required

  • Nothing

Tutorial

This will be a collection of existing methods to access PHP variables in your views.

The long way

PHPixie expects you to pass your variables this way :

MyController.php

MyView.php

How does it work ? With this code from

PHPixie/View.php

 

The global way

You may often want to pass the $_GLOBAL data (like all your $_GET and $_POST if your are doing forms). Here is a shortcut so you don’t need to call them in each one of your functions. Open Page.php and add this :

classes/App/Page.php

 

The semi-global way

You don’t need all the post and get data in all your Controllers ? Just declare them in your specific Controllers then !

classes/App/Controller/MyController.php

 

The hard way

Back to basics with the define() function ! You can declare it anywhere…

MyController.php

MyView.php

 

What represents $this in a view ?

It’s very simple $this represents the View class. It contains

Which you can access in your views doing

MyView.php

  • How to create a global notification system with noty.js

Required


Tutorial

We will add a global notification system using flashdata and noty.js. By global, this means that you can trigger your alert or information messages from anywhere in PHP.

 

Adding the assets

Open your view main.php, add a line and add the javascript file into /web/assets/js/.

/assets/view/main.php

 

Adding some markup

Always in the same view main.php, we will add 3 types of notification : error, information and success messages (you can add others from noty.js).

/assets/view/main.php

 

Tweaking Page.php

Now go to /classes/App/Page.php and add the following to the after() function :

classes/App/Page.php

Note that I’m using a ? : b. To learn more go to PHP.net

Since PHP 5.3, it is possible to leave out the middle part of the ternary operator. Expression expr1 ?: expr3 returns expr1 if expr1 evaluates to TRUE, and expr3 otherwise.

With this code, we create a message (error, information or success) based on a variable sent to the view (but if nothing is sent, we look for flashdata).

 

Using the notification

Now you can use in your controllers/functions either :

Or you can use a flashdata if you need to refresh the page :
  • How to send a simple ajax json response.

Required

  • Nothing

Tutorial

Based on the PHPixie’s wiki AJAX Views. Find more at http://phpixie.com/wiki/

The way that PHPixiev2 is made will generate a header error Cannot modify header information – headers already sent by if you do something like this :

This is because PHPixiev2 HTTP request works like this : $response->send_headers()->send_body();.

This is why, the clean way to echo a simple json_encode data for ajax purpose is to do :

 

  • How to use Mandrill API with PHPixie.
  • How to create an HTML template.
  • How to assign a view to a variable in PHPixie.

Required

  • Mandrill API Key

Tutorial

Let’s do this in less than 5 minutes !

Mandrill your website

First of all, create a Mandrill account and get your API Key at : http://mandrill.com/. Then use Composer and install Mandrill.

Don’t forget to upload the new vendor folder and all the composer files.

Now create a file under assets/config folder and call it general.php. We will put the Mandrill key inside.

assets/config/general.php

3 minutes left now, let’s create an email template !

Let’s do the email template

Let’s say that you have a website with users, you may want a “Forgotten password ?” feature, right ?
We will do something very simple with a link that contains a generated token for the user (so he can change his password).

assets/views/templates/email/forgotten_password.php

Write the minimal controller/method

Finally, with the last 2 minutes, we will write the controller/method to generate the view and send it with Mandrill :

Controller/Email.php

Note that to assign a rendered view to a variable, you need to do the equivalent of this line :

 

That’s it ! 5 minutes !
  • How to create custom config files and use them anywhere.

Required

  • Nothing

Tutorial

Create a file under assets/config folder and call it general.php.

assets/config/general.php

This is an example of what the general.php can contain.

Call it in one line

Just use this line in any Controller :

App/Controller/MyController.php

The pattern is simple filename.key.value. You can also use sub-arrays filename.key1.key2.value and so on.

  • How to throw a traditional exception.
  • How to create a custom exception class and throw it from anywhere.

Required

  • Nothing

Tutorial

Throwing an exception in one line

Next level…

You can throw your own Exception extending the Exception class. Why would you do that ? Well, for example it can be used to show different type of ERROR 503 pages.

You can check the previous post about custom 503/404 page at http://phpixie.jeromepasquier.com/custom-404-503-page/

Creating the Exception class

Create a folder called Exception then a file called CustomException.php (or whatever the name you want) and make it extend the Exception class.

App/Exception/CustomException.php

Yup that’s it !

Then in App/Pixie.php check for this new Exception.

App/Pixie.php

Learn more about HTTP Header 418 on Wikipedia : http://en.wikipedia.org/wiki/Hyper_Text_Coffee_Pot_Control_Protocol

Now you can call it !

Simply call this line anywhere in your code.

Custom 404 and 503 pages

Posted by on 08.03.2014 in Tutorial
  • How to manage basic 404 and 503 HTTP errors.
  • How to create a custom 404 and 503 error pages.

Required


Tutorial

First, we will see how to generate a traditional 404 and 503 error. Then we will see how to custom them.

 

Traditional HTTP Headers

Go to App/Pixie.php and change the handle_exception() method

App/Pixie.php

The code is quite explicit. We need to change the logic at the beginning of PHPixie processing that’s why we override handle_exception(). I recommend you to check how the parent class works, you can find it at vendor/phpixie/core/classes/PHPixie/Pixie.php. If we receive an Exception throw (type PageNotFound) then we will consider it a 404 error PAGE NOT FOUND. Any other errors will be considered as a 503 INTERNAL ERROR.

Don’t forget to keep the render_exception_page otherwise you won’t get the debug logs anymore

You can create your own \Exception type and catch it here. This is how the PageNotFound Exception is coded :

Nothing very difficult right ?

 

Custom HTTP Headers

We will now custom our header errors with a 404 page and a 503 page (special bonus for a maintenance page with an upcoming tutorial !).

Create a Controller that manages all the custom http headers :

App/Controller/Header.php

Then we need the corresponding views, create a folder header (under assets/views/) with a view for each page. Write whatever you want :

assets/views/header/404.php

I will go with a super awesome ERROR 404 with chocolates and bits and pixels YEAH!

Changing the handle_exception() method to consider our custom 404/503/…

Routing the custom HTTP headers

Finally, let’s add a route to the assets/config/routes.php. Without modifying any routes, you will have to access your 404 page using http://example.com/header/404 but what we want is http://example.com/404 which is more sexy.

assets/config/routes.php

Your visitors can enjoy a nice 404 PAGE NOT FOUND !