CakeDC Blog

TIPS, INSIGHTS AND THE LATEST FROM THE EXPERTS BEHIND CAKEPHP

Using the CakeDC Tags plugin for CakePHP

This is an introduction to using the CakeDC Tags plugin for CakePHP. I'll take you through a new project creation, and the addition of the Tags plugin to your project for use with tagging a Blog model on your project. You should be able to take the skills learnt here to any other project, and start taking advantage of the Tags plugin for tagging your models appropriately.

Lets get started by baking a new project:

cake bake project blog1

Follow the prompts to complete the baking operation.

You will now have a "blog1" directory available. Change into that directory:

cd blog1

ensure that the `tmp` directory is writable:

chmod -R 777 tmp

Open up the `config/database.php.default` file in your favourite editor. Immediately choose to "Save as..." and save the file in the same location omitting the ".default" part of the filename. So save the file as `config/database.php`.

Configure the options at the bottom to match the database credentials for your application. Mine are as follows:

<?php
class DATABASE_CONFIG {
   var $default = array(
      'driver' => 'mysql',
      'persistent' => false,
      'host' => 'localhost',
      'login' => 'dev',
      'password' => 'dev',
      'database' => 'blog1',
      'prefix' => '',
   );
}

For the moment, I have remove the 'test' datasource, as we won't use that right now.

Go ahead and create your MySQL database, and a simple table to hold blog items:

CREATE DATABASE `blog1`;
USE `blog1`;

CREATE TABLE `blogs` (
   `id` CHAR(36) NOT NULL PRIMARY KEY,
   `title` VARCHAR(255) NOT NULL,
   `body` TEXT,
   `created` DATETIME,
   `modified` DATETIME
);

Now lets bake the controller, model and views for this blogs table, in order to be able to add and edit content. Once this is complete, we'll begin integrating the tags plugin into the application.

First bake the model:

cake bake model blog

Next bake the controller. The following bakes all the "public" actions for this controller:

cake bake controller blog public

And finally, the views:

cake bake view all

Browse around your application at the address: /blogs to begin with to ensure that your app is functioning correctly. You should be able to add, edit, delete and view blog entries.

Time to get cracking on the Tags plugin. Our objective here is to tag each blog entry with an arbitrary tag at add / edit time to allow us to easily categorise content we are posting.

In order to download and install the Tags plugin, I'll be using git. You can however download an archive from the github website, and extract that archive into your `APP/plugins` directory. In either case, the result will be a `tags` directory in your `APP/plugins` directory, containing the contents of the CakeDC tags plugin.

From your `APP` directory (in this example, the APP directory is `blog1`), clone the tags repository:

git clone git://github.com/CakeDC/tags.git plugins/tags

The first thing that we need to do now that the Tags plugin has been added to our project, is to create the tables required to store the tag information. These are available in schema's and migrations within the Tags plugin, so you don't need to handle the SQL yourself, just use the cake console to create the tables for you:

If you prefer using the builtin CakePHP schema mechanism, or you are not sure what the "migrations" plugin is, you can create the database tables like this:

cake schema create schema -plugin tags -name tags

If however, you are familiar with using the migrations plugin, or you want to use the migrations plugin for this project, add the migration plugin to your project, and then run the migrations:

git clone git://github.com/CakeDC/migrations.git plugins/migrations

cake migration -plugin tags all

Either method is fine.

Next up, we need to add the `Taggable` behavior from the `Tags` plugin to our model to enable all the awesome functionality. Add the following variable to your `Blog` model in `APP/models/blog.php`:

public $actsAs = array(
   'Tags.Taggable'
);

Finally, we need to add a new input for the tags on our add and edit screens, to allow users to customise the tags they want for the blog posts. Simply add a new input called 'tags' to your forms, such as the following:

echo $this->Form->input('tags', array('type' => 'text'));

Note that this needs to be done for both your add and edit views.

You can also make this be of type `textarea`, if you need gigantic amounts of tags. `text` is fine though, to allow a good number of tags, and to minimise the input space.

This is all you need to do to enable your content to be tagged! Looking back at all the instructions so far, the bulk of the content has been on how to create a new project, bake the model, views and controller, and the addition of plugins. In terms of code addition, we've only added a behavior to the Blog model, and a new input to the add and edit views.

To test your tagging, use a comma to separate your tags when using the tags input. Using a comma allows you to enable users to add multiple-word tags.

What now!? You can tag stuff, thats pretty cool. You probably want to look up blog posts based on tags now. Thats already provided for you in the Tags Controller quick comes with the Tags plugin. Browse to `/tags` to see the tags controller index action from the tags plugin render all the tags that you have added to your blog so far.

There is a whole lot more that you can do with tagging in terms of both operation and the visual representation of the tags themselves. Stay tuned for more blog articles explaining our plugins and other interesting PHP and CakePHP code from myself and the rest of the CakeDC team.

UPDATE: An excellent guide on how to style the tags with CSS has been written by @WyriHaximus, check it out here.

Latest articles

CakePHP Upgrade to 4 - Piece by Piece

Let's imagine you have a huge application in CakePHP 2.x (or 1.x) and you're planning to upgrade to the latest CakePHP 4.x. After doing some estimations, you realize the upgrade process is out of your scope, because you don't have the budget or developer availability to do it in 1 shot. At this point, some companies would abort the upgrade and keep working on 2.x for "some more time" until "this last release is delivered" or until "budget is available next fall", digging deeper and deeper into the rabbit hole…   There's an alternative you could follow if this is your case: proceed with the upgrade of a smaller portion of your application and let the 2 versions coexist for some time.   Warning: This is NOT for every project or company. Please carefully think about this decision as it has overhead you'll need to handle.   So, if your application has a portion that could be extracted, with a small set of dependencies from other areas of your application, or if you are creating a new feature with a limited set of dependencies with the rest of your application, this approach would be good for you.   In order to allow both applications to coexist, we are going to keep the CakePHP 1.x application as the main one, and use CakePHP 4.x as a subfolder inside of the first one. It's important to note that in order to share sessions between both applications you'll need to use a storage you can actually share, like database or cache based sessions (redis, etc). Then, you can use a configuration like this one (see below) to add a new upstream to handle your new application. Note: the upstream could be located in another server of your network, using a different PHP version etc.   We've used nginx as an example, but you can use the same approach in other web servers like Apache.   In our example we're going to use all paths starting with /api  to be managed by our new CakePHP 4.x application. upstream cake4 {      # Note this could be any server/port in your network where the cake4 application is installed          server 127.0.0.1:9090; }   # This is our CakePHP 2.x server server {     server_name example.com;       root   /var/virtual/example.com/app/webroot;     index index.php;       # All requests /api are forwarded to our CakePHP 4.x application location /api {         proxy_pass http://cake4;             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;         proxy_set_header Host $host;             proxy_http_version 1.1;         proxy_set_header Upgrade $http_upgrade;             proxy_set_header Connection "Upgrade";     }       location / {             try_files $uri $uri/ /index.php?$args;     }       location ~ \.php$ {           try_files $uri =404;           include fastcgi_params;                fastcgi_pass unix:/run/php/php7.4-fpm.sock;           fastcgi_index index.php;             fastcgi_intercept_errors on;         fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;     } }   # This is our CakePHP 4.x server server {     listen 9090;     server_name example.com;       root   /var/virtual/cake4-example.com/webroot;     index index.php;       location / {         try_files $uri $uri/ /index.php?$args;     }       location ~ \.php$ {         try_files $uri =404;             include fastcgi_params;         fastcgi_pass unix:/run/php/php7.4-fpm.sock;             fastcgi_index index.php;         fastcgi_intercept_errors on;             fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;     } }   As you can see, we have 3 blocks defined in our configuration file:

  • upstream cake4 {...} to forward requests to the CakePHP 4.x application
  • server {... 2.x ...} using a location /api to forward all these calls to the CakePHP 4.x server
  • server {... 4.x ...} using a specific port (9090) to handle requests in CakePHP 4.x
  Using this approach, you can break your application into 2 parts, and start moving features by path to CakePHP 4. You'll need to handle the changes in 2 projects for a while, and pay this overhead,  but this could be better to maintain than a CakePHP 2.x application sitting on an old PHP version. Happy baking!  

Dependency Injection with CakePHP

Dependency Injection is some of the bigger buzzwords in PHP frameworks.  Historically, CakePHP application logic didn’t support that, until the version 4.2 was released last December. You can do that on your own and have a few plugins for that. This is a new chapter of the framework, let's see how to bake it.  

Use Case

First, let’s talk about a classic Use case on real applications. Our application will include an address form, such as the shipping address for an online order, or provide information about User, Company, etc. Autocomplete can help users supply the details.   We will use the Geocoding API from Google Maps Platform, making a HTTP request for API with json output format and address parameter: https://maps.googleapis.com/maps/api/geocode/json?address=89104&key=****** And here we go, we will get this result:  

Baking a Address Service

After seeing the Use case, all we need on our backend is to make a HTTP request for API and return the JSON result for the frontend to populate related fields.   1. First, let’s exposing our application for accept “.json” requests:   2. Now, we can bake a Address Controller and let’s request an empty result: $ ./bin/cake bake controller Address --actions index   Now our app requests /address.json will return an empty JSON.   3. Let’s bake (manually) the Address Service:   Basically I’m using Cake\Http\Client to make the API request. Also I read Geocode.key from Cake\Core\Configure, we don't want to expose our key on public requests (add the key on config/boostrap.php).   4. Let’s rewrite our Controller:   5. Finally, let’s add our Service on Application.php:   That’s all bakers! Now our endpoint /address.json will support query parameters and return the result of the API request.  

The cost of shiny

I’m here selling an idea and I don't start with the cons. Unfortunately, the Dependency Injection container is an experimental feature that is not API stable yet.  The support is a bit limited, CakePHP will inject services into: constructors of Controllers and Commands and Controller actions. The core team hopefully stabilizes the feature on version 4.3, or at most 4.4. They need your help testing and finding cases, and feedback always is welcome.   I hope this post can be useful for you and your projects.  See you next time!  

Planning For Your Upgrade

Having a successful upgrade implies not only upgrading the code itself, but also identifying the different tasks that will be part of the Upgrade Plan. Making a good plan for an upgrade requires identifying the current status of the application. A good plan is based upon clear, well-defined, and easily understood objectives.   After years of experience with CakeDC making upgrades, migrating applications from CakePHP 1 to CakePHP 4 in all possible combinations, we have noticed there are a set of elements or characteristics that are useful to evaluate and identify before starting the upgrade. Having a clear understanding of these elements will be helpful to define the different tasks that will be included in the Upgrade Plan, and reduce any risk while upgrading and delivering.   Imagine that you want to run a marathon - but before starting any of the thousands of plans you can find on the internet about “How to run a Marathon”, you must know where you are. You could ask yourself:  How many miles per week are you currently running? What is the base training needed to start this program? What is the distance of your longest run in the past 3 weeks? How many days per week do you have available to exercise?, etc. This will help you to choose the plan that better fits you. It’s important to identify where you are, where you want to get and how to get where you want.    Wondering how  to evaluate where you are for the Upgrade? Evaluate the status of your application. You could consider the following points as reference:

  • What is your current CakePHP version? 
  • Identify the weaknesses and the strength of the current code by making a code review.
  • Identify the versions of the packages, plugins, libraries that your application is using. 
  • If you are using CakePHP Third Party plugins, figure out if those plugins have already been upgraded.
  • Identify any third party integration and how the upgrade could affect it. 
  • What is the unit test coverage, if any? 
  • Is there any existing documentation?
  • Is there any custom change in the CakePHP core? (I hope there is not!)
  The complexity, time, cost, and resources required to upgrade your application will depend on the status of your application. Once you know where you are, it’s the time to plan how to get where you want.  Let’s talk about this in a future article. In case you are looking for some guidance on preparing your Upgrade Plan, don’t hesitate to contact us, we could help you to identify your current status, define the plan and execute the whole plan for you. We can also work together with your team on the upgrade, helping them understand the upgraded codebase so you can maintain the project with your own team as you did before.  

We Bake with CakePHP