CakeDC Blog

TIPS, INSIGHTS AND THE LATEST FROM THE EXPERTS BEHIND CAKEPHP

How not to be a good CakePHP developer in 10 questions

I have been writing code for almost 20 years. It hasn't always been PHP, the first 6 or 7 years I was very involved with the Java world.

While I partially agree with people thinking you can write bad code with PHP (more than other programming languages), I personally think that you can write bad code in any language because bad practices are common for all of them. For instance, you can call functions or initialize variables inside a loop, you can hit database many times, or you can repeat yourself no matter the language you use.

That said, I want to list the most common questions that good developers should never ask themselves.

 

1.  Are you serious? Is it possible to add code to tables / entities?

If you want to be a bad CakePHP developer, this is your golden rule. Almost every code we receive for review follow this one. Controllers with thousands of lines and models with just baked code.  That’s wrong because all the logic related to your tables should never be in your controllers (or helpers / views).

 




 

2.  I love using SQL queries in my code, is it really so bad?

The short answer is YES. It’s bad, really bad. It is the greatest source of issues and unpredictable behaviors. It is hard to test but of course if you are asking this question you will probably ask the next one.

 

 

3. Tests? Baked tests are enough, aren’t they?

Ehm.. no. You won’t be a bad developer if you don’t have 100% coverage. Even more, I don’t like to talk about what coverage is good because it exclusively depends on the project itself. I would say that you should feel good if your core features are fully covered.

 

4.  Why should I put the code in one place only if you can copy and paste it everywhere?

Even most modern IDEs identify this as a bad practice now, but this is something we see in almost every code we get for review. People prefer to copy and paste the same function in multiple classes instead of creating a Component or Behavior or even a library and use it everywhere.

 

 

5.  Plugins? What is a plugin?

CakePHP has a very large set of available plugins, or you can always start your own plugin and publish it so other people can use it. Plugins are one of the most important features in CakePHP since you can encapsulate a feature or a set of features to use them in multiple projects. Just be careful and don’t overplugin.

 

6.  How the hell would somebody hash a password?

Well, even when you think it's a joke, no, it's not. Some people think hashing a password is not required. CakePHP provides several options for password hashing to secure your application.

 

 

7.  Do you document your code? I don’t think it is useful.

Having the availability of documentation aids in understanding the intended use, as well as the expected functionality and result of the code's execution. It is pretty easy if you just document your code while you are doing it instead of waiting to have 20 classes to document.

 

 

8.  Should I declare variables to execute find methods / DB / Service requests or should I put them inside a for/while loop to "save" memory?

Please no, doing external service requests (DB / File / Web Service) from inside a loop affects application performance very badly. You should always try to put the result in a variable and then use it inside the loop.

 

9.  Who needs coding standards?

Coding standards help make code more readable and maintainable. For CakePHP applications, the Cake Conventions and Coding Standards should be applied.

 

 

10.  Is it better to make all calculations inside for/while loops level in code instead of calculating at the DB/query level?

Data iteration at the DB level offers way better performance than iteration done at the application level.


 

To summarize,  for sure there are lots of things to look at, but from my perspective these are the 10 basic questions that can define you as a good (or bad) developer.

I hope you've never had these questions before but if you do, don’t worry about it, don’t tell anybody, just follow these recommendations to improve yourself!

 

Latest articles

CakePHP 4 - First Look

Last december, the CakePHP team announced the immediate availability of 4.0.0. This release begins a new chapter for CakePHP, as 4.0 is now API stable. With this release, Cake 3.x moves into maintenance mode, while 2.x moves into security release mode. The promise of the version is: cleaner, faster and still tasty as usual. I had the opportunity to bake a new application from scratch and I will give my feedback about my process.  

Skeleton Design

The new version refreshes the skeleton design of the application. Now we have 2 new folders on root:
  • Templates

The templates folder has presentational files placed here: elements, error pages, layouts, and view template files. Pay attention for subfolders: 
  • Core templates are lowercase: cell, element, email, layout
  • App templates still uppercase: Error, Pages
  • Resources

The resources folder has subfolders for various types of resource files.  The locales* sub folder stores string files for internationalization.   If you are familiar with i18n, you will see the difference:
  • src/Locale/pt_BR/default.po (3.x)
  • resources/locales/pt_BR/default.po (4.x)
  Another important change was the .ctp files. They are moved for .php. CakePHP template files have a default extension of .php now. We have a new config/app_local.php file, which contains the configuration data that varies between environments and should be managed by configuration management, or your deployment tooling.  

PHP Strict Type Mode

In PHP the declare (strict_types = 1); directive enables strict mode. In strict mode, only a variable of exact type of the “type declaration” will be accepted, or a TypeError will be thrown. The only exception to this rule is that an integer may be given to a function expecting a float. This is a feature from PHP 7 - which we strongly recommended. All codebase from the skeleton and files generated by bake will include the function.  

Entities

The preferred way of getting new entities is using the newEmptyEntity() method: $product = $this->Products->newEmptyEntity();  

Authentication

After 10 years baking, that's a really big change for me. I’m not usually use plugins for authentication, I really like the Auth Component. I think many bakers would agree, as I remember on the first international meetup, the co-host shared the same opinion.   The Auth Component is deprecated, so it's better move on and save the good memories. The new way for implementing Authentication is more verbose. It requires a few steps, I don’t will detail that,  because you can easily check on book:
  • Install Authentication Plugin
  • Load the Plugin
  • Apply the Middleware
  • Load the Component
  My first look is like I said,  too verbose, for me anyway. We need to write a lot of code. Also it is not included on the skeleton of CakePHP applications, you need include by your own. https://book.cakephp.org/authentication/2/en/index.html  

HTTPS Enforcer Middleware

Contrary to the Authentication, I was really surprised how easy it was to force my Application to use HTTPS. If you are familiar with CakePHP, you will use the Security Component for that: class AppController extends Controller {      public function initialize()    {        parent::initialize();        $this->loadComponent('Security', [            'blackHoleCallback' => 'forceSSL',        ]);    }      public function beforeFilter(Event $event)    {        if (!Configure::read('debug')) {            $this->Security->requireSecure();        }    }      public function forceSSL()    {        return $this->redirect(            'https://' .            env('SERVER_NAME') .            Router::url($this->request->getRequestTarget())        );    }   }
  The implementation on version 4 is less verbose and easy, kudos for the new version:    public function middleware(MiddlewareQueue $middlewareQueue)    {        $middlewareQueue            ->add(new HttpsEnforcerMiddleware([                'redirect' => true,                'statusCode' => 302,                'disableOnDebug' => true,            ]));          return $middlewareQueue;    }   What I know is a drop, what I don’t know is an ocean. The new version is here to stay, and this article it's a just one overview of basic usage of the new version. * Version 4.1.0 is released already with more improvements and features.  

Links 

[1] Book https://book.cakephp.org/4/en/contents.html [2] Migration Guide https://book.cakephp.org/4/en/appendices/migration-guides.html  

CakeDC API plugin - Authentication and Authorization

This article covers new changes for CakePHP 4 version of plugin. So it covers versions starting from 8.x (8.0) and later.  

Permissions system. RBAC

By default, the plugin uses CakeDC Users and CakeDC Auth plugins for authentication. For RBAC it uses the same style as defined in the Auth plugin RBAC system with minor changes required for the API plugin. First, let's consider the case when we want public api without any authorization. In this case the most simple way would be is to define in config/api_permissions.php next rule   return [     'CakeDC/Auth.api_permissions' => [         [             'role' => '*',             'service' => '*',             'action' => '*',             'method' => '*',             'bypassAuth' => true,         ],      ], ];   Now, consider the case we want to use users plugin authentication. Since Api is supposed to be used from another domain, we should allow all requests with OPTIONS type. To do this we should add this rule as first on in config/api_permissions.php       [         'role' => '*',         'service' => '*',         'action' => '*',         'method' => 'OPTIONS',         'bypassAuth' => true,     ],    Here, method define OPTIONS and bypassAuth means that such actions should work for any users, including not authenticated. Now we should allow Auth service methods       [         'role' => '*',         'service' => '*',         'action' => ['login', 'jwt_login', 'register', 'jwt_refresh',],         'method' => ['POST'],         'bypassAuth' => true,     ],    All other services/actions should be declared in api_permissions file to define what user roles are allowed to access them. Imagine we want to allow the admin role to access the add/edit/delete posts and make index and view public. We can do it based on method or based on action names.       [         'role' => 'admin',         'service' => 'posts',         'action' => '*',         'method' => ['POST', 'PUT', 'DELETE'],     ],      [         'role' => 'admin',         'service' => 'posts',         'action' => ['index', 'view'],         'method' => '*',         'bypassAuth' => true,     ],   

 Routers and Middlewares

Starting from the 8.x version, API Plugin uses router middlewares. This gives great abilities to configure the plugin. So now it is possible to have separate authentication and authorization configuration for website and for api. Also, It is possible to have more then one api prefix, and as result provide more then single api for website with different configuration. Let’s take a look on the default configuration for middlewares   'Middleware' => [     'authentication' => [         'class' => AuthenticationMiddleware::class,         'request' => ApiInitializer::class,         'method' => 'getAuthenticationService',     ],     'bodyParser' => [         'class' => BodyParserMiddleware::class,     ],     'apiParser' => [         'class' => ParseApiRequestMiddleware::class,     ],     'apiAuthorize' => [         'class' => AuthorizationMiddleware::class,         'request' => ApiInitializer::class,         'params' => [             'unauthorizedHandler' => 'CakeDC/Api.ApiException',         ],     ],     'apiAuthorizeRequest' => [         'class' => RequestAuthorizationMiddleware::class,     ],     'apiProcessor' => [         'class' => ProcessApiRequestMiddleware::class,     ], ],   First we see the order of middlewares that proceed api request. It passes through AuthenticationMiddleware, AuthorizationMiddleware, and RequestAuthorizationMiddleware to perform generic auth tasks. It passes through BodyParserMiddleware to unpack the json request. And finally ParseApiRequestMiddleware does initial service analysis and ProcessApiRequestMiddleware performs the request. Also we can note CakeDC\Api\ApiInitializer class used to define Authentication and Authorization configuration. It can be redefined in the application layer to provide needed Identifiers and  Authenticators.  

 Jwt authentication - Refreshing tokens

New plugin feature is embedded jwt_login action which allows the user to get access_token and refresh_token included into the login response. Tokens should be passed in the Authorization header with bearer prefix. Access token is supposed to be used as default token and refresh token needed to get a new access token when it's expired. So for refreshing provided additional jwt_refresh action which should be used in this case.  

 Configuration

Configuration should be defined on application level in config/api.php. Need to note that it is important to enable this file to load by the Api plugin. It could be done in config/bootstrap_app.php using global configuration: Configure::write('Api.config', ['api']);       'Api' => [          ...                  'Jwt' => [             'enabled' => true,             'AccessToken' => [                 'lifetime' => 600,                 'secret' => 'accesssecret',             ],             'RefreshToken' => [                 'lifetime' => 2 * WEEK,                 'secret' => 'refreshsecret',             ],         ],    Hopefully, this was helpful. Our team is always working on adding new features and plugins. You can check out more available plugins HERE.

CakePHP Meetup: Unit Test Fixtures, Queue Plugin, PPM Bridge

Developers are used to living in a virtual world, so adjusting has been easier than expected. Recently, we’ve been holding virtual meetups, and we are so happy with the feedback. Digital training sessions allow bakers from all over the world to come together and enjoy. Our plan is to host one each month, and coordinate time zones so that everyone gets a chance to attend. Our latest one was based around a good time for our Japanese community.  If you missed the meetup, no problem. We always post the recording for playback, and I’ll even give you a quick rundown of the topics covered. Let’s jump in:

CakePHP Fixture Factory Plugin

by Juan Pablo Ramirez CakePHP Fixture Factory Plugin https://github.com/pakacuda/cakephp-fixture-factories  helps to improve the way fixtures are generated, when having a big database writing fixtures can get so complicated. This plugin provides Fixture Factories in replacement of the fixtures found out of the box in CakePHP.
Generating fixtures can be done in a few code lines reducing the effort of writing and maintaining tests. There are some other plugins to manage fixtures: 

CakePHP Queue Plugin

By Mark Scherer @dereuromark CakePHP Queue Plugin https://github.com/dereuromark/cakephp-queue is a simple Queue solution, it can be used for small applications and it’s a good one to get started with Job Queues, having something easy to maintain at the beginning is a good starting point.
Queues are a good option for functionalities like: image processing, email sending, PDF generation; to improve the response-time for heavy-processing tasks. For more robust solutions can be used:
  • CakePHP Queuesadilla  https://github.com/josegonzalez/cakephp-queuesadilla This plugin is a simple wrapper around the Queuesadilla queuing library, providing tighter integration with the CakePHP framework. We have used this plugin in CakeDC in several projects, we also had to build  a Mongo Engine for a specific client.

CakePHP PHP PM Bridge

By Jorge Gonzalez @steinkel CakePHP Bridge https://github.com/CakeDC/cakephp-phppm  to use with PHP-PM project.
PPM is a process manager, supercharger and load balancer for modern PHP applications. PHP PM It's based on ReactPHP, the approach of this is to kill the expensive bootstrap of PHP (declaring symbols, loading/parsing files) and the bootstrap of feature-rich frameworks.
It’s a good option If you want to significantly improve the responsiveness of an application that could have spikes. PM works as PHP FPM, it’s a replacement for it.  Below some benchmark:  50 Concurrent threads in 10 seconds
  • FPM 83 transactions per second, Failed 0,  Concurrency 6.58.
  • PPM 90.30 transactions per second, Failed 0, Concurrency 3.86.
200 Concurrent threads in 10 seconds
  • FPM 116,49 transactions per second, Failed 142,  Concurrency 116.64.
  • PPM 207.35 transactions per second, Failed 0, Concurrency 85.59.
1000 Concurrent threads in 10 seconds
  • FPM 109,88 transactions per second, Failed 1759, Concurrency 187.49.
  • PPM 214.91 transactions per second, Failed 0,  Concurrency 302.39.
PPM is able to handle a lot of concurrency connections coming in spike to the server  in a better way than PHP FPM.
For watching the Meetup visit the following link https://www.youtube.com/watch?v=POI0IwyqULo Stay up to date on all virtual meetups here  https://cakephp.org/pages/meetups      

We Bake with CakePHP