CakeDC Blog

TIPS, INSIGHTS AND THE LATEST FROM THE EXPERTS BEHIND CAKEPHP

Introduction to CakeDC Api plugin

 

The CakeDC API plugin was created with the goal to prepare abstract solutions that solve generic tasks -in case of creating a rest API. It provides such features like automatic rest API generation based on db schema, support nested routes. It also allows the use of different formats like json or xml, and easily adds their own custom format. It helps to solve generic tasks appearing in development of any API, like pagination, data validation, adding common data to response, or building metadata, about data objects.

Dependencies

The CakeDC API plugin hardly depends on the CakeDC Users Plugin. For authentication it is highly recommended to use CakePHP Authentication plugin configured as middleware.

Installation

You can install this plugin into your CakePHP application using composer. The recommended way to install composer packages is: composer require cakedc/cakephp-api  

 Load the Plugin

Ensure  The CakeDC API Plugin is loaded in your src/Aplication.php in bootstrap method. php     $this->addPlugin(\CakeDC\Users\Plugin::class);     $this->addPlugin(\CakeDC\Api\Plugin::class, ['bootstrap' => true, 'routes' => true]);

Configuration

Minimal configuration to allow non authorized requests require you to copy file: ./vendor/cakedc/cakephp-api/config/api_permissions.php.default to ./config/api_permissions.php

Examples

Lets bake table blogs with two fields id and name. After that, the next requests would be possible to perform to api. Requests would be performed using curl. Request: curl http://localhost:8765/api/blogs Response: {     "status": "success",     "data": [         {             "id": 1,             "name": "blog001"         }     ],     "pagination": {         "page": 1,         "limit": 20,         "pages": 1,         "count": 1     },     "links": [         {             "name": "self",             "href": "http:\/\/localhost:8765\/api\/blogs",             "rel": "\/api\/blogs",             "method": "GET"         },         {             "name": "blogs:add",             "href": "http:\/\/localhost:8765\/api\/blogs",             "rel": "\/api\/blogs",             "method": "POST"         }     ] } Request: curl -d "name=blog001" -H "Content-Type: application/x-www-form-urlencoded" -X POST http://localhost:8765/api/blogs Response: {     "status": "success",     "data": {         "name": "blog001",         "id": 1     },     "links": [] } Request: curl -d "name=blog002" -H "Content-Type: application/x-www-form-urlencoded" -X PUT http://localhost:8765/api/blogs/1 Response: {     "status": "success",     "data": {         "id": 1,         "name": "blog002"     },     "links": [] } Request: curl -X DELETE http://localhost:8765/api/blogs/1 Response: {     "status": "success",     "data": true,     "links": [] } For more complex features about plugin initialization and configuration based on routes middlewares, we plan to create an additional article.

Services and Actions

In the REST recommendations documents names defined as a noun. Here, services come into play. It describes business entities. From other side actions define the verbs that describe the operations that should be performed on the actions. Common and difference between controller classes and services. The common part is the service is the managing the choosing action to execute. The primary difference is that service could be nested, if this is defined by request url. Common and difference between controller actions and service actions. The common part is the action defined logic of the request. The primary is that each service’s action is defined as a separate class. This means that generic actions could be defined as common class and reused in many services. From the other side, an action class is able to extend if the system has slightly different actions. This way it is possible to build actions hierarchy. Both service and actions define an event during this execution flow.  Main service events: * Service.beforeDispatch * Service.beforeProcess * Service.afterDispatch Main action events: * Action.beforeProcess * Action.onAuth * Action.beforeValidate * Action.beforeValidateStopped * Action.validationFailed * Action.beforeExecute * Action.beforeExecuteStopped * Action.afterProcess Crud actions define events that depend on the type of action, and more details could be checked in documentation. * Action.Crud.onPatchEntity * Action.Crud.onFindEntities * Action.Crud.afterFindEntities  * Action.Crud.onFindEntity

Nested services

Consider we have request with method POST /blogs/1/posts with data like {"title": "...", "body": "..."} As it is possible to see there is nothing in the given data about the blog_id to which the newly created post should belong to. In the case of controllers we should define custom logic to parse a route, and to consume the blog_id from url. For nested service all checks and records updates are automatically executed. This will happen for any crud operations, when detected by the route parent service. So for example: GET /blogs/1/posts, will return only posts for the blog with id 1. Logical checks are also performed, so for request: DELETE /blogs/1/posts/2, a user gets an error if the post with id 2 belongs to the blog with id 2.

Action inheritance

As each action can be defined as a separate class, it is possible to use class inheritance to define common logic. For example:  Add and Edit actions.

Extending services and actions with shared functionality

The alternative way for defining common logic actions is using action extensions. Action extension is a more powerful feature and could be used for global tasks like search or pagination. It is also possible to create service level extensions. Those extensions work on the top level of the execution process, and could be used for things like adding cors feature, or to append some counter into response.

Add service actions from service::initialize

This is a recommended way to register non crud actions. The mapAction uses the Router class syntax for parsing routes. So on any special use cases well described in cakephp core.     public function initialize()     {         parent::initialize();         $this->mapAction('view_edit', ViewEditAction::class, [             'method' => ['GET'],             'path' => 'view_edit/:id'         ]);     }

Configure actions using action class map.

Each action class uses $_actionsClassMap for defining a map between crud (and non crud) actions on the name of the action class. Non crud actions should be additionally mapped, which is described in the previous step. use App\Service\Protocols\IndexAction; class ProtocolsService extends AppFallbackService {     /**      * Actions classes map.      *      * @var array      */     protected $_actionsClassMap = [         'index' => IndexAction::class,     ];

Configure service and action in config file

Service options are defined in the config/api.php in Api.Service section. Let's consider configuration options for ArticlesService. Configuration are hierarchical in the next sense: 
  • define default options for any service within the application in the Api.Service.default.options section.
  • define options for any service within the application in Api.Service.articles.options section.
All defined options are overridden from up to down in described order. This allows common service settings, and the ability to overwrite them in bottom level.
  •  Api.Service.classMap - defines name map, that allows defining services action classes with custom location logic.
    Any action, that could be loaded as default action defined in fallback class, or specific action class could be configured using configuration file.
    Let's consider how one can configure options for IndexAction of ArticlesService.
    Configuration are hierarchical in the next sense: 
  • one can define default options for any action for all services in the application in the Api.Service.default.Action.default section.
  • one can define default options for index action for all services in the application in the Api.Service.default.Action.index section.
  • one can define options for any action in the specific (articles) service in the Api.Service.articles.Action.default section.
  • one can define options for index action in the specific (articles) service in the  Api.Service.articles.Action.index section.

Crud and non crud methods. Mapping non-crud actions.

Crud services mapped automatically in two levels routing by FallbackService.

Index and view. Formatting output

The CakeDC Api Plugin is flexible and provides multiple ways to prepare result data for the response objects. There is a list of main options.

Use Entity serialization

The most trivial way to convert data is using entity serialization. When converting an entity to a JSON, the virtual and hidden field lists are applied.  Entities are recursively converted to JSON as well.  This means that if you eager, and loading entities and their associations, CakePHP will correctly handle converting the associated data into the correct format. Additional fields could be defined using Entity::$_virtual and hidden using Entity::$$_hidden.

Build object manually from Action::execute

In this case users manually perform mapping of requests received from model layer to output array. public function process() {     $entity = $this->getTable()->get($this->getId());     return [         'id' => $entity->id,         'name' => $entity->name,     ]; }

Use Query::formatResults in model layer

The request could be formatted in model layer using: Query::formatResults. So in this case, the process action just calls for a needed finder from the model layer and returns the result. public function findApiFormat(Query $query, array $options) {     return $query         ->select(['id', 'body', 'created', 'modified', 'author_id'])         ->formatResults(function ($results) use ($options) {             return $results->map(function ($row) use ($options) {                 $row['author'] = $this->Authors->getFormatted($row['author_id']);                 unset($row['author_id']);                   return $row;             });         });

Use Action extensions to format output

In index action defined callback Action.Crud.afterFindEntities, which called after data fetched,  could be used to extend or overload results coming from the database. Callbacks are catch-in-action extensions and could be applied to multiple endpoints. For view action defined Action.Crud.afterFindEntity, which called after single record fetched.

Use Action extensions to append additional data to output

Sometimes there is some additional information needed to be presented in some group of endpoints. In this case it is possible to implement an action extension to append additional data. For example, pagination provides information about number of pages, records count, and current page number. Another example for additional data is some execution statistics about the query. Here you see main parts of appending such data from extension. class PaginateExtension extends Extension implements EventListenerInterface {     public function implementedEvents(): array     {         return [             'Action.Crud.afterFindEntities' => 'afterFind',         ];     } ...     public function afterFind(EventInterface $event): void     {         ...         $pagination = [             'page' => $this->_page($action),             'limit' => $limit,             'pages' => ceil($count / $limit),             'count' => $count,         ];         $result->appendPayload('pagination', $pagination);     }     The renderer class describes how to handle payload data. For example in JSend renderer, all payload records appended to the root of the resulting json object.

Rendering output. Renderers.

Renderers perform final mapping of response records to output format.  Such formats like xml, json, or file are provided by  The CakeDC API plugin. JSend is the json extension with some additional agreements about returning results.    

Remote Work, Actually Works!

As a fully remote company, the Cake Development Corporation team is used to working from home. We communicate with our team daily, keep on top of tasks, hold each other accountable and support one another. Heck, a lot of us even do it with kids in the household, too! I consider us extremely lucky to be able to work while juggling an at home life at the same time.  It has worked for CakeDC over the past decade, and in my opinion, can work for most companies.   As of last month, an estimated 4.7 million people were working remotely, which grew 44% over the last 5 years. This is just in the United States. Remote work is becoming the norm.  Obviously for the next few weeks, this number will be drastically increased, but perhaps this will educate companies on the advantages of a WFH culture. Advantages to employers, besides the operations cost (other than payroll, of course), which can decrease by close to 90%, includes increased productivity. Decreased overhead results in higher salaries, which results in more quality candidates and employees.  I understand the concern of the ability to micro-manage (UGH) being unavailable, but according to statistics, 85% of businesses that work remotely confirmed that productivity increased in their companies. When there is more flexibility, there will be higher employee morale.  With the current situation arising from COVID-19, a lot of businesses are forced to transition employees to WFH in order to stay afloat. This not only keeps employees and clients safe, but family members too.  I have put together some stats and resources that may help CEO’s and employees transition a little bit easier.  

Communication:

It is absolutely essential to keep open communication among a team when everyone is working remotely. Our team uses RocketChat* ( I will include some links in the resource section at the end of this blog), and it has proved to be effective. A chat allows for quicker response time, as well as allowing individuals to set their status (like busy, away, at lunch, sick, etc.). This is a good way to get quick answers, as users can be alerted when they have been messaged or tagged in a company chat. Most of our team work in different timezones, so this is a good way to “stay in the know” about everything happening day to day. We separate chats according to their department. For example: marketing, development, general, etc. We also have the option to private message with co-workers when needed.  Other ideas, if not daily chat interaction, include scheduled meetings. For most of our team meetings, we use Zoom. This tool allows for audio only, as well as video chats.  

Accountability & Time Management:

It is important that tasks are managed and followed through. We use programs like Redmine* to track hours and work, in addition to weekly, or monthly conference calls for each department.  If you or your team are new to remote work, it may be in your best interest to assign a project manager, someone who will assign work, track hours, and ensure that work needed is being completed in a timely manner. Without each person being held accountable, the ship will sink, fast. For personal accountability, there are many free apps and tools available. One example is Trello*. This is a scheduling board so that tasks are not forgotten and you can plan your work week and stay organized. Once tasks placed on your “schedule board” are completed, you can make note of it and stay focused on each one according to their priority. You can also keep track of documents and reports. The boards look like this:    

Resources:

Documents & Recording - We <3 Google Docs - we are able to share and edit internally, we couldn’t function without it.  Docusign is a good tool for contracts / documents needing signatures Invision Freehand - this is a tool where you can create presentations, and allows comments and feedback between designers. Good for freelance designers!    Organization/Tasks -  Trello - for individual time management scheduling.  Redmine - for project assigning, time recording, HR management,    Communication -  RocketChat - allows for multiple internal chats all rolled into one link (allows for individual logins) Zoom - good for meetings. Allows audio and video chats for teams or reps and clients.  Slack - also a great option for expanded chats. Each person has a “screen name” and can be personally messaged, or public groups can be created (we use this as well). Slack also allows video calls with their paid subscription.  Google Hangouts WhatsApp - if your team is diverse, like ours, WhatsApp is a must. We are able to text each other, regardless of location - no fees, no service problems (if you have wifi of course).  World Time Buddy - this is a tool that I am not familiar with, but being the designated “scheduler of meetings”, I think I would find it useful. If your team works within different timezones, this allows you to add the location of your teammates, compare times, and find ideal times for meetings.    Community - In the development world, community support sites are absolutely one of the most important tools. This allows for individuals - inside or outside of your company - to communicate and help each other out. Most developers are aware and utilize these, but if not, may I suggest: Discourse - chat support  GitHub - our favorite team collaboration tool. GitHub allows for hosting, editing and managing products. We use it for building software and allow for community interaction. It also integrates with a lot of other tools, which is a plus!  

Take Away:

These resources are just a drop in the bucket compared to what is available to remote workers. I think this is a reflection of how WFH is becoming more accepted and more normal in the corporate world. I’d love to hear some of your favorites: amanda.goff@cakedc.com.  Let’s take away some positivity to the current quarantined times, and encourage more companies to follow suit. In today’s world, flexibility goes a long way and this type of transition can be mutually beneficial for employers and employees. I mean look at us, we are PRETTY normal… right?  Speaking of being in quarantine - stay healthy, stay inside, and wash your hands!  

Two Factor Authentication & CakeDC Use...

Why 2FA?

Nowadays we have noticed that many of the websites or applications that we access offer the option to activate an extra layer of security called Two Factor Authentication, better known as 2FA. Most of our lives happen on our mobile devices and laptops, so it’s not a secret that cyber-thieves would like to gain access to our personal and financial data. This is why adding an extra layer for protecting logins is worth it.  2FA  is an extra layer of security to make sure that someone that is trying to gain access to an account is who they say they are. The first layer is generally a combination of a username and password, and the second layer could ask for a code that is sent to your phone, a fingerprint scan or the name of your best friend. Currently 2FA has become a security standard in the digital world.

How does it work?

First the user will enter his username and password, then instead of getting in immediately into the system, he will be required to provide  additional information. Which could be one of the following options or factors:
  • Something you know : This could be a password, a personal identification number (PIN), answers to a secret question or a specific keystroke pattern.
  • Something you have: This is something the user owns, a physical device, like a mobile phone, an id card, an usb stick, a token, etc.
  • Something you are: This could be face or voice recognition, retina scan,  fingerprint, DNA, handwriting.

CakeDC Users Plugin and 2FA

There are various ways to implement Time-based One-Time Password (TOTP), Short Message Service (SMS), Electronic Mail (Email),  Universal Second Factor (U2F). CakeDC Users Plugin provides the ability to enable in your site TOTP or U2F. 
 

TOTP Google Authenticator

Enabling 2FA Google Authenticator in CakeDC Users Plugin is quite easy, it just takes a few minutes. In case you have not installed CakeDC Users Plugin in your application, follow the installation steps described here. Once you have installed the plugin and your basic login is working, you just need to do the following:
  1. Run the next command: composer require robthree/twofactorauth
  2. In Application::pluginBootstrap() add the following: Configure::write('OneTimePasswordAuthenticator.login', true);
  Once you have 2FA enabled in your site, when you try to login will happen next 
  1. Type your username and password.   
  2. You proceed to the next step where you are asked for the authentication code
    • First time you will be shown a QR code that you need to scan from your authenticator application.   
    • Next time you will only get the input to type your authentication code  
  3. You open the authenticator application to get a secondary code called a one-time password (OTP)—usually six characters in length. There are many options in the market for the authenticator application, some of the most used are: Google Authenticator, Duo Mobile, FreeOTP etc.
  4. You type the 6-digit code into the website, and you’re in!
 

FIDO U2F

If you want something more solid and reliable, then you could use U2F (Universal 2nd Factor) standard created by the FIDO Alliance. With this kind of authentication you use a physical security key, and insert that into your PC, touch the key’s button, and you’re “automatically” logged in.  U2F standard was implemented in CakeDC Users Plugin by using  the YubiKey, the most famous and common example of U2F. To enable 2FA via Yubico follow the next steps:
  1. Run the next command: composer require yubico/u2flib-server:^1.0
  2. In Application::pluginBootstrap() add the following: Configure::write(‘U2f.enabled’, true);
     
Yubico is a hardware based 2FA, it’s a small device with one end that slots into a standard Type-A USB port. You just need to Insert your YubiKey and touch it! You won’t need to manually enter the code. Take into account that you will need to use https to be able to use 2FA features in your applicatins.

So, what to choose for two-factor authentication? There is no universal answer, it will depend on the level of security you are expecting, but start protecting your account by enabling 2FA! In this article you could noticed how easy is to enable 2FA in any CakePHP application by using CakeDC Users Plugin.
  References: https://github.com/CakeDC/users https://en.wikipedia.org/wiki/Multi-factor_authentication https://en.wikipedia.org/wiki/One-time_password https://en.wikipedia.org/wiki/FIDO_Alliance https://en.wikipedia.org/wiki/Universal_2nd_Factor  

Things about CakePHP that you probably...

CakePHP is often more than just a framework to many in the community, but there are some great features and treasures that many may not know about - so join us with your piece of cake and let’s check these out!

Cake Bake

Cake Bake is an incredibly helpful tool for any developer starting up a new application, or adding new functionality to an existing one.

Using your existing database schema (that follows the CakePHP conventions), running the cake bake command will quickly generate a fully working application skeleton with all your database fields and associations. It will even generate sane validation rules and pretty view files for you.  This allows you to concentrate on the features of your application that actually matter, rather than the generic admin CRUD interfaces. Have some kind of structure or class in your application that you regularly need to create? Maybe a specifically formatted view, or adaptor class? Cake Bake allows you to easily extend it and create your own bakeable templates. Find out more about Cake Bake in the CakePHP Cookbook (i.e. the framework docs)

CakePHP standalone packages

CakePHP’s core is built using standalone packages - this means that you aren’t bound to the framework.

The ORM, database, console, log to just name a few are available to use in your own PHP projects - even if you aren’t using CakePHP. Have you checked these out

Interactive console (REPL)

Not many developers are aware that CakePHP ships with an interactive console tool (Or REPL - Read Eval Print Loop).

You can start the console with bin/cake console. This console tool allows you to quickly and easily explore CakePHP and your application. Use it to quickly check if a finder method is working as expected, or to experiment with a specific query. Anything that you can code, you can run in the interactive console, much quicker and easier than coding a class.

Chronos

Chronos is a standalone DateTime library originally based off of Carbon.

The biggest difference between Chronos and Carbon is that Chronos extends DateTimeImmutable instead of DateTime. Chronos is immutable by default. Carbon is not. 

CakePHP Core team

The core team is built up of community members - just like yourself - who contribute their time to improving the framework.

All of their time is volunteered - so if you see them in the support channels, be sure to say hi! How did they get onto the core team you ask? They showed commitment to improving the core and the community.

There are some plugins that are just around to make your life a little easier

While most plugins were developed to add to the functionality of your CakePHP application without too much extra effort, there are some plugins that have been written to actually just make your life easier.

One such plugin is the CakePHP IDE helper, written by dereuromark. This plugin improves your IDE compatibility and uses annotations to make the IDE understand the "magic" of CakePHP - so you can click through the class methods and object chains as well as spot obvious issues and mistakes easier. For a curated list of CakePHP Plugins, grouped by topic, check https://github.com/FriendsOfCake/awesome-cakephp.   What’s your favourite part of the CakePHP framework or community? Let us know!

How not to be a good CakePHP developer...

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!  

10 Features Of A User Friendly Website

Let’s talk about appealing web presence. There are a lot of factors to consider when determining if a site is “user friendly”, and I’m going to give you some tips to make sure yours makes a good impression.   Here are some of the top must-haves for a good web page:  

1. Layout and design

This is extremely important as it is the first thing a visitor will see. If your layout is scattered, or pages are hard to find, they will be running to the red x. In this case, less is more. I am a firm believer in simple clean layouts - I mean it works for Google, right?  Make sure your pages are seen and easy to access. Make sure your design is aesthetically pleasing, and that is easier than it sounds.  This brings me to the next point.  

2. Good, easy to read content

Not only is accessibility important, but the content that the visitor is reading is a direct reflection on your brand. Users are generally on a website for a very specific reason, and if they have landed on yours, then you need to make sure they know that they are in the right place. It is important to immediately list who you are and what you do. It’s okay to have detailed pages to navigate to, but always make sure your homepage illustrates the services that you provide. Don’t lose a good lead due to bad content, that’s just embarrassing.  Speaking of good leads, a lot of people search for services on the go which means…
 

3. Be mobile compatible 

More than ever, consumers are using mobile devices to browse the web. You can even order groceries for pickup using your phone. It is absolutely essential that your website is mobile friendly - if you want added success. If you aren’t sure how your site appears to mobile users, it’s an easy investigation. If searching for your site via mobile device isn’t enough, Google actually offers tools to do it for you. A good developer and design team can assist in making sure that your website is mobile compatible, but there are also some third party providers that you can rely on after your initial site build, if mobile wasn’t included. Basically… just make sure it happens.
 

4. Have ways to be contacted

If someone is on your site, and can’t find an answer to their questions, do you want them to leave? The answer is no, obviously. It is important to have multiple ways to reach some sort of customer service. I personally like a number, chat, and email option, but I guess that is being demanding.
 

5. Browser compatibility

A lot of times, as we are editing or designing sites, our team will compare screen grabs and the site looks totally different on each one. This is a top priority and it gets fixed ASAP. I really don’t understand why this happens, but it must be combated nonetheless. Mostly, it has to do with sizes, layout, background images, etc. It is just important to make sure that your site looks the same no matter who is looking at it and no matter which browser they choose to do so with. These issues are easy to fix, but sometimes tedious. ALWAYS check each popular browser before deploying.   

6. Speed

I’m impatient, and I don’t care to admit it. I would say most people have a short attention span. If I land on a website and I get the spinning wheel, I will give it a chance. If every page has slow loading speed, I am probably going to move on. It’s easy to tell if it’s a webpage causing the issues, so it’s always better to troubleshoot this ahead of time. Once again, there are a lot of free tools you can use to test your speeds. A good free one to try is: wpengine.com - and they will even provide issues & fixes for your slow page. 
 

7. Hosting

Good speed and function is a result of a good hosting service, too. This is something that may not even cross your mind as you are building your brand and your website, but it is so important. The hosting provider you choose can make or break your impression. Pick wisely, and do your research. There is no reason to risk security or your site breaking every time there is an update. You’ll thank me later for this one
 

8. Security

I mean this goes without explanation, right? Especially for e-commerce sites - online shopping - anything that requires customer information. Nothing will ruin a reputation faster than a compromised system. PLEASE make sure all backend security options are locked tight.
 

9. Be Transparent - and bug free

There are going to be errors. No one is perfect - no website is perfect. I always appreciate when a site provides on-screen error descriptions so that I know where I (or the page) has gone wrong. It opens up the trust door with your visitor, and makes them more likely to stick around or retry the action. This also requires the developer to stay in tune with these errors and provide fixes. We want a robust site, right?  An important thing to remember is always check the status of your webpage, and fix issues fast. Many development companies that offer these services, are avialable to help round the clock. For example, CakeDC offers project management services (see here), which allows client to rely on us for development services long term on the existing projects. 
 

10. Be ever changing

It is important for a business, entrepreneur or developer to adapt. This is especially true for long lasting websites. Say a page has been around for 15 years - things have changed - new features are available… keep up with the times. It is a competitive market that one must always stay in front of. Don’t be afraid of change. 
  Now go… go out there and make your website great again.   

15 Years of CakePHP

This April we will be celebrating 15 years of CakePHP! I can’t help but feel honored to have been a part of this framework, made lasting connections, and help build up the community. As one of the founders of the CakePHP project, I want to express how excited I am about the positive progress that has taken place over the years. We started out with just a few core members, which got us pretty far. Looking back, it’s crazy to see how much our community has grown, and with all of the input, this project has become one of the longest developed PHP framework available today! Our community has always centered on going the extra mile in order to acquire the best results in every aspect. This is not to say that some ups and downs have not hit us along the way in the last 14 years. Indeed, there have been bumps in the road, and some discussions regarding the route the project should take moving forward. Heck, there have even been some individuals who have opted to depart from the team. Other team members have decided to place their feelings down and their dedication in front at all times to work past disagreements in order for CakePHP to continue to evolve in the positive ways it has. Each year, people with diverse visions are joining our core team, and the future for CakePHP is promising. The team is working harder than ever before to keep CakePHP in its reigning position, and promoting it in the open source world for it to continue to impress. Our goals are clear - and if we have anything to say about it, CakePHP is not going anywhere, anytime soon. Our team is certainly stronger and more determined to continue giving the project their all. There are so many things that make the open-source community amazing - I mean think about it: people from different backgrounds, who speak different languages, and who have different beliefs come together and work jointly to attain a common goal. It’s pretty cool. I have worked with open-source software for more than 25-years. Even so, I am still amazed daily on what can be accomplished by such a diverse group of individuals. Actually, I think the rest of the world could take some notes from the open-source community and the benefits that come from people working together. The friends that I have made in the open-source community throughout the years are way too many to name one by one, but I am grateful. This goes on to reflect my awesome experience with it, one that will always be present on my mind. I want to finally express to the CakePHP core team, the CakePHP community, and everyone I have had the pleasure and honor of working with at CakeDC, that I am extremely thankful for absolutely everything. Here is to 15 more years of CakePHP.

How To Get More Involved In Your Commu...

Ever wondered where you can find out more about a specific topic related to PHP, or find out new and exciting things happening in the PHP world? We’ve put together a list of useful links that will help you on your PHP journey!

 

Learn More 

Cakephp Training

The team at CakeDC sponsors monthly training - focusing on the following topics.
  • Standard CakePHP 4 Training Course
These interactive and live sessions offer you the opportunity to get involved, ask questions and learn more from the experts behind the framework.  

CakePHP Tutorials

The CakePHP cookbook (i.e the documentation) includes several tutorials to help you along. These are a great way to learn more about typical CakePHP applications and to come to grasps with how CakePHP is put together.  

CakeFest - The annual CakePHP Conference

CakeFest, run over 4 full days, features 2 full workshop days led by the top CakePHP developers. The last two days showcase some of the top CakePHP speakers from around the world - join CakeFest to experience a jam-packed opportunity to increase your knowledge base and grow your community network.  

Stack Overflow

While not a traditional platform with courses or guided tutorials, Stackoverflow offers something better - real life issues that others are facing, and how they have found a solve for them! You can really learn a lot by watching others.  

PHP: The Right Way.

As a PHP developer, it can sometimes be difficult to find information that is both updated and helpful to your specific problem. PHP: The Right Way is a an easy-to-read platform that you can use as a reference for popular and up-to-date coding standards, links to tutorials as well as best practices. From the best practices through to resources, community groups and more, PHP The Right Way should be on your frequently visited list.   

Read More 

Blogs

There are many CakePHP related blogs out there - here are just a handful of the ones we find awesome!  https://www.dereuromark.de/tag/cakephp/  http://mark-story.com/  http://josediazgonzalez.com/  http://www.cakedc.com/articles  

PHP Architect

PHP[architect] is a digital magazine solely focused on the world of PHP. From in-depth technical articles through to hosting training and organizing conferences, this is a great resource to grow your PHP knowledge base from.  

Listen More

Voices of the ElePHPant

Voice of the ElePHPant is a regular podcast interviewing PHP community members on a wide variety of topics. Cal Evans digs deep into what is keeping community members busy.
 

Phpugly

Another podcast focused on the PHP Community - hosted By @shocm, @realrideout, and @johncongdon.  

Discover More

Awesome CakePHP

Run by the Friends of Cake, the awesome CakePHP list is a curated list of  plugins, resources and other interesting CakePHP links.   

Awesome PHP

There are many PHP lists of curated PHP libraries and resources - here are just a few that we think you would find interesting. https://github.com/ziadoz/awesome-php https://php.libhunt.com/  

PHP league

A group of developers joined forces to create the league of extraordinary Packages - where they build solid, well tested PHP packages using modern coding standards.  

Packagist 

Packagist helps you to find packages and lets Composer know where to get the code from. Check out download stats or publish your own package.    Do you have more to add to this list? 

CakeDC/Users 9.x Easy migration from A...

In a previous article, we talked about the version 9.x of the CakeDC/Users plugin which is compatible with CakePHP 4 and compatible with the cakephp/authentication and cakephp/authorization plugins, we recommend you check it out. In this article we will demonstrate how to migrate your code from AuthComponent. Before we continue, it is important to remember some things:

  • Authentication and Authorization are performed at the middleware layer
  • Authorization is configured to work with Rbac (config/permissions.php)
  • The migration guide `8.x-9.0` is available for additional information
  • 9.x version is for CakePHP 4

Replacing AuthComponent::allow, also known as public actions

For many applications it is normal to have public actions that do not require a user login, previously this was possible with AuthComponent::allow, now the authorization check step is done in the Middleware layer and is part of RBAC by default. You will need to move this permissions to your config/permissions.php, but don’t worry because this migration is very simple. For example, to enable the `index` and `view` actions you needed to have this code in your `ArticlesController`. /** * @inheritDoc */ public function initialize() { parent::initialize(); $this->Auth->allow(['index', ‘view’]); } In this new version we don't need to call Auth->allow, but instead we just have to include a permission of type 'bypassAuth' in config/permissions.php [ 'controller' => ‘Articles’, 'action' => [‘index’,’view’], 'bypassAuth' => true, ],   Check a sample permissions file at: https://github.com/CakeDC/users-example/blob/9.next-basic-with-custom-username/config/permissions.php Don’t forget to remove this snippet from your controller: $this->Auth->allow(['index']);  

Replacing AuthComponent::user

Your application probably uses the AuthComponent::user method in at least one place, in fact it should be the method that you use the most from this component. The good news is that the migration here is the easiest, because instead of using this method, we will obtain the user data from a request attribute. If you had something like this: //Get all user data $user = $this->Auth->user(); //Get the user id $userId = $this->Auth->user('id');   Now you can get the user (identity) data this way: $user = $this->getRequest()->getAttribute('identity'); $userId = $user['id'] ?? null; //OR $userId = $this->getRequest()->getAttribute('identity')['id'] ?? null;  

Be careful with direct access from session data

Avoid the direct access of user data from session, it will only return the user data after authenticator has persisted, and this may not happen when you try to read from session.  

Additional information

In the previous version we used the `Auth` configuration to customize the Auth component, now we have specific configurations to be used in the authentication and authorization process related to the new plugins. For example `Auth.Authenticators` and `Auth.Identifiers` provides information needed to setup authentication to work with Form, Token, Cookie (Remember Me) and Social (when enabled).  

Form Authentication with email

One of the most common needs for user login is the ability to change the fields used for login via the form. The default behavior allows login by username or email, but let's assume you want to restrict login only by email, you can do it by including the following in your config/users.php file: 'Auth.Identifiers.Password.fields.username' => 'email' You can get a sample app at https://github.com/CakeDC/users-example/tree/9.next-basic-with-custom-username  

That’s all for today

In the plugin's documentation you can find more information about the available configurations and please be sure to check the migration guide if you have not https://github.com/CakeDC/users/blob/9.next/Docs/Documentation/Migration/8.x-9.0.md. The Auth component's migration shouldn't be very complicated, as our idea for the plugin was to offer you a set of default configurations to make it easier to use. If you have a config/users.php file it is recommended to compare it with the new users.php file from plugin. That’s all for today, are you using the new version? Have suggestions for new features? Tell us what you think.

Why Choosing The Right Development Tea...

 Listen, we get it… it is the age of do-it-yourself everything, but one thing that I will remain firm on is the fact that a good web presence (and web application/website) is absolutely essential for any business. The fast track to a good application starts with choosing the right development team. Whether you decide as a business owner to have an internal development team, or outsource the work, it is a very important action for success.   Having a user friendly site will do just that, get you friends. Or in this case, “traffic” to your webpage. What can a development company or team do that those “quick and easy build a site” tools can’t? A lot. But firstly, they can build custom features and integrations. If someone visits your site, it is likely they will stick around if there are things to do/see/read, thus decreasing your “bounce rate” - which is a nice way to say clicking the little red x or back button.    Another benefit to choosing the right development team is having someone on hand to work on debugging, error fixing, and training for maintainers you may have on your team. For example, with CakeDC, we offer consulting, project management and training. This means your project manager can be with you for the long term (always available to fix those ERROR codes or upgrade), or train your tech team to manage the application themselves. Development is a long term commitment.  Our team keeps clients accompanied during all stages of development, from the initial call and vision building, to implementation and delivery… and even offer after build management in case there is a future need. It is important to make sure your site/application is always running smoothly and dedicate time to enhancing it. Nothing is more frustrating to a potential client or consumer than trying to run an action and getting broken links or useless site features. A good developer will ensure security is enabled as well (number one priority). The more features you have, and the easier they are to use, means the more conversions and leads you can get and the easier they are to obtain.   Hiring a team does not always mean things will be perfect, there are so many options available: commercial teams, freelancers, internal tech departments… so it is important to do your research before making the plunge. When speaking to a lot of our potential clients, a common complaint I get is that developers are not accessible (or at least not quickly). Many times, I hear the same story… a company hires a freelance developer working on their own time, the freelancer builds the initial project, then disappears and the company is left with a site full of errors. Our team focuses a lot on communication with clients, and we make ourselves reachable at any time. We even have developers in different timezones to suit the needs of clients, and we keep them in the loop every step of the way. CakeDC has a project management system that is accessible to every client so that they are able to track work and time being used. Not to mention, we chat via email, skype, slack, phone… you name it.    Plus, our team works together, that way the work promised gets delivered.     Basically, what I am trying to say is to choose a development team, and choose wisely. The team should start with asking your needs and wants, and your vision for the project. An experienced development team can bring that project to life. The decision you make now, can save time, money, and many meltdowns in the future. Don’t say I didn’t warn you (just kidding…kinda).   

Users plugin 9.x for CakePHP4

CakePHP 4 is out for some time (4.0.2 at the time of writing this post) and some of you already asked "Is there a cakedc/users version for cake4?" a couple times... The answer is YES!. We had a meeting after we realized AuthComponent was going to be deprecated, the authentication/authorization layer was leaning towards
Middlewares and getting a new Plugin home ourside of the core.
We decided to embrace the new middlewares and provide native compatibility from version 9.x of the plugin. Before we explain how is it going to work, and proceed to setup a project from scratch a couple answers to potential questions: * Are you going to maintain cakedc/users 8.x for CakePHP 3.x?
  * Yes, as long as you use it, we'll keep it maintained. Version 8.x will be a LTS version. We'll consider backporting some features from 9.x but the
  main objective of 8.x is to provide stability over time to existing CakePHP 3 projects.
* I'm planning to migrate my project from CakePHP 3 to CakePHP 4, what's the migration path for cakedc/users?
  * Keep the version 8.x of the plugin for some time. Complete your upgrade and then decide if you want to migrate to cakedc/users 9.x.
  We wrote a migration guide here when you decide it's time to move forward.
* AuthComponent is going to explode in CakePHP 4.x ?
  * No, it's deprecated, but deprecated also means it's completely functional. Just keep it until you decide to upgrade it.
 
This blog post is the first of a series of articles about cakedc/users 9.x where we'll explain how to use the plugin from scratch, it's benefits and
also the way the new authentication & authorization layers work for a CakePHP 4.x application. We've kept our main objectives for this plugin: provide a quick, easy, flexible users management plugin to help you build awesome products on top of CakePHP 4. So let's create a new project * Ensure you have a working develop environment, download a development vagrant machine or pick some other's environment. composer create-project cakephp/app:^4 users9 Now we have a new CakePHP 4 project skeleton created under folder users9.
Test it using bin/cake server then go to http://localhost:8765 and check it's all green.   all green checks for cakephp 4   * Install the plugin using
composer require cakedc/users:^9 * Now configure your application to use the plugin in your src/Application.php bootstrap() method, add
$this->addPlugin(\CakeDC\Users\Plugin::class); * Create the required tables in your configured Datasource using Migrations:
bin/cake migrations migrate -p CakeDC/Users This will create an empty `users` table and `social_accounts` to hold your authenticatio data. * Now create a superadmin user
bin/cake users addSuperuser It will create a superadmin user and a random password, copy the user and password to a safe place. Now start the standalone server using bin/cake server again, and go to the home page http://localhost:8765... you'll see the login form.   login form cakephp 4 and cakedc/users
If you use the superadmin credentials previously generated, you'll be able to login and continue to the home page. Total setup process, possibly less than 5 minutes if your network allows it... How is it actually working? * Once the plugin is added to you Application class through the Plugin class, we implement the  `AuthenticationService` and `AuthorizationService` provider interfaces, and use
the `middleware()` plugin callback to inject the configured middlewares into the Application middleware queue, see the `MiddlewareQueueLoader`.
We do it to keep the loading and configuration of the middlewares in one place, and decide the middlewares needed based on your configuration, for example if you are using
social login with Facebook, we configure which middlewares you need loaded and the correct order.
Check LINK for customization options of the plugin. We'll deal with customization in other articles of this series. * CakePHP core Authentication and Authorization middlewares are also loaded, with the provided configuration. Check file vendor/cakedc/users/config/users.php for the
default configuratio used. You'll see there we're using by default Session, Form, Token, Cookie and Social. Depending on your configuration we'll check if you're authenticated in the following order:
  * Your identity already in the session
  * You've posted login form and your credentials are in the request data
  * There is a token present we can retrieve, usually for API stateless token based auth
  * There is a remember me cookie present
  * Your identity is available after social login, and we can use it to login into the app
 
If all these methods fail, you're redirected to the login page, `/login` by default (configurable, of course).   * But that's the first step, once we can identify who are you, the next step (Authorization) is to determine if you're allowed to access the page you're trying to open. The plugin default configuration has 2
Authorization methods, superuser and rbac.
  * If you're user is a superuser, you are granted
  * If there is a rule in the rbac configuration to match your role and the current page, you are granted
 
If none of the above, you are not authorized, and redirected to the home page. One of the important concepts about the new authentication layer in CakePHP is: "Authentication happens before you hit AppController".
So when you get to your Controller, CakePHP alreay knows you're an existing user and you have permission to access the page. All the abstraction and complexity
of maintaining the authentication is now extracted and managed OUTSIDE of your controllers, reducing their complexity. Give it a try in your next project! Let us know how it goes and share you experiences with us, we'll be happy to help in the community channels.  

CakeFest 2019 Recap

Here we are, a couple weeks out of CakeFest 2019. What an experience in Japan!  We didn’t really know what to expect when we decided to finally make the trip to host in Tokyo. We were given great welcoming from the PHP community, and each person we met left us with wonderful memories. Another welcoming surprise was the low price of food, and delicious ramen. Our team definitely utilized all of the free time we had.            Let’s talk about the event, and the workshops. Jorge Gonzalez, Jose Rodriquez, and Mark Story definitely delivered in the knowledge department. The participation was fantastic, although the class size was smaller than in other years. We’ve had a lot of requests for their slides, so those are included in the link below ⬇️ One thing that was different this year, is that we had different venues for the workshops and conference. This makes it difficult for the team, with transferring our equipment in such a busy city (shout out to the quick responding taxi services).  We did try the metro when we had less baggage, and got up close and personal with the locals. Speaking of venues, we cannot thank DMM.com and SmartNews enough. We are still dreaming of an office like DMM’s with live plants growing up the walls and a complete installed watering system.  These venues were overly accommodating, making this one of the best conferences we’ve had.          If you are a PHPer or specifically working with CakePHP, the speakers topics were overflowing with useful information. Like Yuki Kanazawa’s tips for a smooth upgrade to CakePHP 3, or Tadahisa Motooka’s ideas about database replication. Kazuki Higashiguchi helped talk us through painful testing of code, and Sho Ito walked us through an initial OSS with CakePHP. We had such a great lineup this year, and we cannot wait to have some speakers return. Other great talks included David Yell, Daniel Voyce, Jose Gonzalez, and Wim Godden, and superstar core members Mark Story and Jose Rodriguez.  We even had to be confronted with details about life after CakePHP (GASP!) from Andrej Griniuk.    Unfortunately, no event can be executed without some roadblocks, and we aren’t exempt. We had a couple late cancellations (understandable) from speakers, but definitely made up the time with chats and lightning talks. There was so much information exerted during the short 2 days, that we all probably needed and extra day to take notes. Luckily, we did that for you. All of the slides included during CakeFest are available at the link below as well.    So, would we come back and host in Japan again? YES! We hope to do so sooner rather than later. Are there some things we will change on our end? Yes, again.  We hoped for higher numbers for workshops, as the information given is invaluable. We hope that in the future, all conference attendees will take advantage of those sessions as well. You can stay up to date with all things CakeFest at CakeFest.org - we are actually working on adding a history feature to reference past events.      We could not have done all of this without the amazing sponsors we had this year:    Cake Development Corporation  Shizen Energy  BASE  Lancers  DMM JetBrains Connehito  Marks Software SmartNews  ESM   Follow our speakers on Twitter:   Yuki Kanazawa - @yakitori009  Mark Story - @mark_story Jose Rodriguez - @jose_zap Jorge Gonzalez - @steinkelz Tadahisa Motooka - @t_motooka Kazuki Higashiguchi -  @hgsgtk Sho Ito - @itosho David Yell - @Yelldavid Daniel Voyce - @voycey_web Jose Gonzalez - @savant Wim Godden - @wimgtr Andrej Griniuk - @andrej_gr   CLICK HERE to view the CakeFest 2019 workshop and speaker slides.   Now, we want to hear from you! If you attended, what did you think about CakeFest Japan? What did you enjoy the most/least? If you did not attend: what has held you back from joining us? Let us know - email: community@cakephp.org.

How To: CakePHP, CakeDC Users and Amaz...

Long time ago, in 2010, CakeDC Users plugin for CakePHP was released for CakePHP 1.3. Almost nine years has passed and the initial code has changed dramatically, offering new and exciting features. In 2011 the team released the first version to be compatible with the new CakePHP 2.0. At this moment we focused in keeping the same features and only adding support for the new version of the framework. When CakePHP 3.0 arrived in 2015 we decided to refactor Users plugin completely, making it easier to use but also adding terrific features out of the box like:

  • Social login with most popular providers
  • RBAC permissions
  • Superuser
  • And much more..
It continued evolving and today we will show how to use the latest provider we have added to the social login feature in the plugin, Amazon Cognito. Let’s talk first about it. We'll use Amazon Cognito basically as an Oauth 2.0 Server. It'll let you manage your user groups and users. It provides a simple interface to sign up, sign-in and also use many social providers like Facebook, Google and Amazon. It also allows using SAML 2.0 providers and they promise it may scale to millions of users. You can also fully customize form and buttons. Best of all, it is free for the first 50,000 logins. Let's start configuring Amazon Cognito in AWS Panel. We must first create a user pool. You could have different user pools and each of them having an exclusive set of features.     Now we need to customize our new pool adding a pool name, etc. We can use default settings for testing purposes. If you want to customize fields you should then go through steps.     Once we check everything is okay we can click on Create Pool.     Now, it's time to setup App Clients. If you are familiar with OAuth and another services it is like creating a Facebook or Twitter App.     And then click on Add an app client.  Just add a name and save.   Remember to write down your client ID and client secret because they will be needed later to configure Users plugin. The next step is to setup app client settings. We need to configure:
  • Callback url: set it to /auth/cognito if you want to use plugin defaults.
  • The flow to Authorization code grant and the scopes you must select at least email and openid. You can select profile in case you want to get all the user information from cognito.
      Finally we need to configure a domain name for the user pool. Use a custom domain or a subdomain from Cognito.     Now that we are ready with Cognito setup, let’s easily create a new CakePHP app, to connect with Amazon Cognito. First, we need a new CakePHP app: composer create-project --prefer-dist cakephp/app users-app Remember to create a new empty database. Now we can go to users-app folder and run: composer require cakedc/users After CakeDC Users plugin is installed, we need to install Oauth 2 Cognito provider package: composer require cakedc/oauth2-cognito CakeDC Users plugin configuration is pretty easy: $this->addPlugin('CakeDC/Users'); public function pluginBootstrap() { parent::pluginBootstrap(); Configure::load('users'); } return [ 'Users.Social.login' =--> true, 'OAuth.providers.cognito.options.clientId' => 'CLIENT_ID', 'OAuth.providers.cognito.options.clientSecret' => 'CLIENT_SECRET', 'OAuth.providers.cognito.options.cognitoDomain' => 'DOMAIN', 'OAuth.providers.cognito.options.region' => 'REGION', ];
  • Load the Users Plugin bin/cake plugin load CakeDC/Users
  • If you prefer to do this manually, add this line at the end of your src/Application.php bootstrap() method
  • Add the following line into AppController::initialize() method $this->loadComponent('CakeDC/Users.UsersAuth');
  • Add the following code to your src/Application.php pluginBootstrap() method to ensure we override the plugin defaults
  • Add the file config/users.php with your specific configuration, including
In case you used a custom domain for you user pool, you can replace cognitoDomain option by using hostedDomain option (including protocol): 'OAuth.providers.cognito.options.hostedDomain' => 'YOUR DOMAIN', Scope option defaults to email openid . If you selected another scopes, you may want to add them as well: 'OAuth.providers.cognito.options.scope' => 'email openid profile', Finally we just need to go to /login.     and click on Sign in with Cognito. If everything is setup correctly you should see the following screen:   You can previously create a user in AWS panel or just click signup on that screen. After login you will be redirected to homepage in CakePHP App. As you can see, the setup for both Cognito and App are simple if you use default settings. However after testing defaults, you can start customizing forms, fields, adding third party apps. You have no limits.  

Last words

We create and maintain many open source plugins as well as contribute to the CakePHP Community as part of our open source work in CakeDC. While developing this provider, we've also published a generic Oauth2 Amazon Cognito repository. Reference  

Boost CakePHP using RoadRunner Plugin

https://github.com/CakeDC/cakephp-roadrunner was just released! Some time ago we developed a bridge for the PHP Process Manager, and now we've integrated with another alternative, a fast, go based, PHP application server (see https://github.com/spiral/roadrunner) Using this approach, and configuring nginx + roadrunner + cakephp, we're getting ~1500 requests per second for a typical index operation (including database access), and over 2200 (!) requests per second using a cached resultset. Here's what you need to do:

  • composer require cakedc/cakephp-roadrunner
  • Download roadrunner binary and place the file in your filesystem, for example under /usr/local/bin/rr
  • Create a RoadRunner worker file, or use the example worker provided
cp vendor/cakedc/cakephp-roadrunner/worker/cakephp-worker.php . cp vendor/cakedc/cakephp-roadrunner/worker/.rr.json . Note the configuration is stored in .rr.json file, check all possible keys here https://github.com/spiral/roadrunner/wiki/Configuration
  • Start the server, either using your own configuration or the sample configuration provided in the plugin
/usr/local/bin/rr serve   Check plugin details here > https://github.com/CakeDC/cakephp-roadrunner

Last words

Please let us know if you use it, we are always improving our plugins - And happy to get issues and pull requests for our open source plugins. As part of our open source work in CakeDC, we maintain many open source plugins as well as contribute to the CakePHP Community.

Integrating Users and ACL plugins in C...

In previous posts, we saw how CakeDC Users plugin can help you to build an application that manages everything related to users: registration, social login, permissions, etc. Recently it has been noted by the team that there are some use cases where a deeper control of permissions is needed - more than is offered in RBAC. Today we’ll go into this using the ACL approach. ACL or Access Control List, refers to the application using a detailed list of objects to decide who can access what. It can be as detailed as particular users and rows through to specifying which action can be performed (i.e user XX has permissions to edit articles but does not have permissions to delete articles). One of the big features of ACL is that both the accessed objects; and objects who ask for access, can be organized in trees. There’s a good explanation of how ACL works in the CakePHP 2.x version of the Book. ACL does not form part of CakePHP core V 3.0 and can be accessed through the use of the cakephp/acl plugin. Let’s just refresh the key concepts of ACL:

  • ACL: Access Control List (the whole paradigm)
  • ACO: Access Control Object (a thing that is wanted), e.g. an action in a controller: creating an article
  • ARO: Access Request Object (a thing that wants to use stuff), e.g. a user or a group of users
  • Permission: relation between an ACO and an ARO
For the purpose of this article - we shall use this use case: You are using CakeDC/users plugin and now want to implement ACL in your application.

Installation

Starting with a brand new CakePHP app: composer selfupdate && composer create-project --prefer-dist cakephp/app acl_app_demo && cd acl_app_demo We are going to use CakeDC/users and cakephp/acl plugins. In a single step we can install them with composer: composer require cakedc/users cakephp/acl Create a DB and set its name and credentials in the config/app.php file of the just created app (in the Datasources/default section). This command can help you out if you are using MySQL: mysql -u root -p -e "create user acl_demo; create database acl_demo; grant all privileges on acl_demo.* to acl_demo;" Plugins will be loaded always with the app. Let’s set them on the bootstrap file: bin/cake plugin load -br CakeDC/Users
bin/cake plugin load -b Acl Now let’s insert a line in bootstrap.php before Users plugin loading, so cakedc/users will read the configuration from the config/users.php file of our app. Configure::write('Users.config', ['users']); This file does not exist yet. The plugin provides a default file which is very good to start with. Just copy it to your app running: cp -i vendor/cakedc/users/config/users.php config/ Also, let’s copy the permissions file the same way to avoid warnings in our log files: cp -i vendor/cakedc/users/config/permissions.php config/ We need to change cakedc/users config: remove RBAC, add ACL. In cakephp/acl there’s ActionsAuthorize & CrudAuthorize. We’ll start just using ActionsAuthorize. We will tell ActionsAuthorize that actions will be under the 'controllers/' node and that the users entity will be MyUsers (an override of the Users entity from the plugin). Edit the Auth/authorize section of config/users.php so that it sets: 'authorize' => [ 'CakeDC/Auth.Superuser', 'Acl.Actions' => [ 'actionPath' => 'controllers/', 'userModel' => 'MyUsers', ], ], Add calls to load components both from Acl & Users plugin in the initialize() method in AppController: class AppController extends Controller { public function initialize() { parent::initialize(); // (...) $this->loadComponent('Acl', [ 'className' => 'Acl.Acl' ]); $this->loadComponent('CakeDC/Users.UsersAuth'); // (...) } // (...) }

Database tables

Some tables are required in the database to let the plugins work. Those are created automatically just by running their own migrations: bin/cake migrations migrate -p CakeDC/Users
bin/cake migrations migrate -p Acl One table from the Acl plugin needs to be fixed because Users migration creates users.id as UUID (CHAR(36)) and Acl migrations creates AROs foreing keys as int(11). Types must match. Let’s fix it adapting the aros table field: ALTER TABLE aros CHANGE foreign_key foreign_key CHAR(36) NULL DEFAULT NULL; Now, it’s time to set our own tables as needed for our app. Let’s suppose we are developing a CMS app as specified in the CMS Tutorial from the CakePHP book. Based on the tutorial, we can create a simplified articles table: CREATE TABLE articles ( id INT AUTO_INCREMENT PRIMARY KEY, user_id CHAR(36) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL, title VARCHAR(255) NOT NULL, body TEXT, published BOOLEAN DEFAULT FALSE, created DATETIME, modified DATETIME, FOREIGN KEY user_key (user_id) REFERENCES users(id) ); Note: Specify CHARACTER SET and COLLATE for user_id only if the table CHARACTER SET and COLLATE of the table differ from users.id (than may happen running migrations). They must match. Roles will be dynamic: admin will be allowed to manage them. That means that they has to be stored in a table. CREATE TABLE roles ( id CHAR(36) NOT NULL PRIMARY KEY, name VARCHAR(100) NOT NULL, created DATETIME, modified DATETIME ); Association between users and roles bill be belongsTo, so we’ll need a foreign key in the users table instead of a role varchar field: ALTER TABLE users ADD role_id CHAR(36) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER role, ADD INDEX role_id (role_id), ADD FOREIGN KEY (role_id) REFERENCES roles(id); ALTER TABLE users DROP role;

Baking

Time to think about what will be ACOs and AROs. In most cases, Users will be the only AROs. To do that, we need to link the Users entity and table to the ACL plugin. In this case that we are using CakeDC/users plugin, we first need to extend the plugin as it is explained in the docs. We will also add the behavior and parentNode() as shown in the cakephp/acl readme file, so at the end we’ll need to create those files: src/Model/Entity/MyUser.php: <?php namespace App\Model\Entity; use CakeDC\Users\Model\Entity\User; /** * Application specific User Entity with non plugin conform field(s) */ class MyUser extends User { public function parentNode() { return ['Roles' => ['id' => $this->role_id]]; } } src/Model/Table/MyUsersTable.php: <?php namespace App\Model\Table; use CakeDC\Users\Model\Table\UsersTable; class MyUsersTable extends UsersTable { public function initialize(array $config) { parent::initialize($config); $this->addBehavior('Acl.Acl', ['requester']); $this->belongsTo('Roles'); $this->hasMany('Articles'); } } Run bin/cake bake controller MyUsers (beware of case) Then, edit the top of src/Controller/MyUsersController.php as: <?php namespace App\Controller; use App\Controller\AppController; use CakeDC\Users\Controller\Traits\LinkSocialTrait; use CakeDC\Users\Controller\Traits\LoginTrait; use CakeDC\Users\Controller\Traits\ProfileTrait; use CakeDC\Users\Controller\Traits\ReCaptchaTrait; use CakeDC\Users\Controller\Traits\RegisterTrait; use CakeDC\Users\Controller\Traits\SimpleCrudTrait; use CakeDC\Users\Controller\Traits\SocialTrait; class MyUsersController extends AppController { use LinkSocialTrait; use LoginTrait; use ProfileTrait; use ReCaptchaTrait; use RegisterTrait; use SimpleCrudTrait; use SocialTrait; // CRUD methods ... To generate the template files for MyUsers we can run: bin/cake bake template MyUsers Next, just let Cake bake all objects for articles and roles: bin/cake bake all Articles
bin/cake bake all Roles Add behavior to their tables. ArticlesTable will act as controlled because it will represent ACOs: class ArticlesTable extends Table { public function initialize(array $config) { parent::initialize($config); // (...) $this->addBehavior('Acl.Acl', ['controlled']); // (...) The case of RolesTable will be similar but it will act as requester, as it will represent AROs: class RolesTable extends Table { public function initialize(array $config) { parent::initialize($config); // (...) $this->addBehavior('Acl.Acl', ['requester']); // (...) Create the parentNode() method in both entities: Article and Role. public function parentNode() { return null; }

Testing

Ok, time to test the whole system! At this point, the app should be ready to use. At least, for an administrator. Let’s quickly create one: it is as easy as running bin/cake users add_superuser. New credentials will appear on screen. When accessing our app in the URL that we installed it, a login form will appear. Log as the just created admin. First, let’s create some roles. Go to /roles in your app’s URL. Then, click on "New Role". Create the roles:
  • Author
  • Editor
  • Reader
Then, we can create two users an author and a reader. Head to /my-users and add them. Remember to select the Active checkbox and the proper role in the dropdown menu. Because MyUsers has the AclBehavior, AROs has been automatically created while creating users, along with the created roles. Check it out with bin/cake acl view aro Aro tree: --------------------------------------------------------------- [1] Roles.24c5646d-133d-496d-846b-af951ddc60f3 [4] MyUsers.7c1ba036-f04b-4f7b-bc91-b468aa0b7c55 [2] Roles.5b221256-0ca8-4021-b262-c6d279f192ad [3] Roles.25908824-15e7-4693-b340-238973f77b59 [5] MyUsers.f512fcbe-af31-49ab-a5f6-94d25189dc78 --------------------------------------------------------------- Imagine that we decided that authors will be able to write new articles and readers will be able to view them. First, let’s create the root node for all controllers: bin/cake acl create aco root controllers Then, let’s inform ACL that there are such things as articles: bin/cake acl create aco controllers Articles Now, we will tell that there are 5 actions related to Articles: bin/cake acl create aco Articles index bin/cake acl create aco Articles view bin/cake acl create aco Articles add bin/cake acl create aco Articles edit bin/cake acl create aco Articles delete We can see the first branch of the ACOs tree here: bin/cake acl view aco Aco tree: --------------------------------------------------------------- [1] controllers [2] Articles [3] index [4] view [5] add [6] edit [7] delete --------------------------------------------------------------- ACL knows that articles can be added, so let’s tell who can do that. We can check which aro.id belongs to role Author with: mysql> select id from roles where name like 'Author'; +--------------------------------------+ | id | +--------------------------------------+ | 24c5646d-133d-496d-846b-af951ddc60f3 | +--------------------------------------+ 1 row in set (0.00 sec) And the same with the Reader role:: mysql> select id from roles where name like 'Reader'; +--------------------------------------+ | id | +--------------------------------------+ | 25908824-15e7-4693-b340-238973f77b59 | +--------------------------------------+ 1 row in set (0.00 sec) So, if we look up this id in the bin/cake acl view aro output, it turns out that aro.id 1 is Author and that aro.id 3 is Reader. If we want to let authors (ARO 1) add articles (ACO 5), we must grant permission to Articles/add to editors by running: bin/cake acl grant 1 5 And we'll grant readers (ARO 3) view articles (ACO 4) with: bin/cake acl grant 3 4 Don't forget to grant access to Articles/index for all roles, or nobody would access /articles: bin/cake acl grant 1 3 bin/cake acl grant 2 3 bin/cake acl grant 3 3 Note: Obviously, it would be easier to set a "super role" which includes the 3 roles and grant access to index to it, but we don't want to add too many steps in this tutorial. You can try it for yourself. Then, aros_acos table becomes: mysql> select * from aros_acos; +----+--------+--------+---------+-------+---------+---------+ | id | aro_id | aco_id | _create | _read | _update | _delete | +----+--------+--------+---------+-------+---------+---------+ | 1 | 1 | 5 | 1 | 1 | 1 | 1 | | 2 | 3 | 4 | 1 | 1 | 1 | 1 | | 3 | 1 | 3 | 1 | 1 | 1 | 1 | | 4 | 2 | 3 | 1 | 1 | 1 | 1 | | 5 | 3 | 3 | 1 | 1 | 1 | 1 | +----+--------+--------+---------+-------+---------+---------+ 5 rows in set (0.00 sec) Let’s create a new article as the first user. To do that:
  • Log out (we are still logged in as superadmin) going to /logout
  • Log in as the first created user
  • Go to /articles
  • Create an article
Right now, author can add an article but not view it, since we only set the add permission. Check it out clicking in View next to the article. Log in as a reader to check how the reader can really view the article. Obviously, more than a couple of permissions have to be grant in a big app. This tutorial served just as an example to start.

Last words

That's all for now related to the use of ACL in a webapp made with CakePHP. A lot more can be done with ACL. Next step would be to use CrudAuthorize to specify which CRUD permissions are granted for any ARO to any ACO. Keep visiting the blog for new articles! This tutorial has been tested with:
  • CakePHP 3.5.10
  • CakeDC/users 6.0.0
  • cakephp/acl 0.2.6
An example app with the steps followed in this tutorial is available in this GitHub repo. Please let us know if you use it, we are always improving on them - And happy to get issues and pull requests for our open source plugins. As part of our open source work in CakeDC, we maintain many open source plugins as well as contribute to the CakePHP Community. Reference

Using a vagrant box as quick environme...

We've decided to create a simple vagrant box with all the required packages to improve the environment setup step in our free Getting Started with CakePHP training session. We used other tools in the past, but we hope vagrant will help users to install a common environment before the session to get the most of it.

Requirements

Setup

  • Create a new folder where the code will be located
  • Create a new file called Vagrantfile with the following contents
# -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.configure("2") do |config| config.vm.box = "cakedc/cakephp-training" config.vm.network :forwarded_port, guest: 8765, host: 8765 config.vm.provider "virtualbox" do |vb| vb.memory = "1024" vb.customize ['modifyvm', :id, '--cableconnected1', 'on'] end end
  • Run vagrant up
  • Wait (download could take several minutes depending on your internet connection)
  • Run vagrant ssh
Now you have ssh access to a training ubuntu (16.04) based virtual machine, with all the requirements to run your training CakePHP application.
  • Setup a new CakePHP project
cd /vagrant composer create-project cakephp/app
  • Start the local server
cd /vagrant/app php bin/cake.php server --host 0.0.0.0
  • From your host machine, open a browser and navigate to http://localhost:8765
  • You should be able to see the CakePHP welcome page
  We think this VM will enable faster environment setups, and an easier entry point to the training session. Please let us know if you find issues with this process.

Boosting your API with CakePHP API and...

A couple days ago AlexMax commented in CakePHP's IRC channel about the https://github.com/php-pm/php-pm project and it rang a bell for us. We did a couple tests internally and found this could be a great companion to our API plugin, so we wrote a new Bridge for CakePHP and ran some benchmarks.

The Cast

We put all together and created a sample application (1 posts table with 30 records) to do some benchmarks.

Benchmark configuration

We are not aiming to provide detailed or production figures, just a reference of the results obtained for your comparison. Results are generated from a development box, using PHP 7.1.12-3+ubuntu16.04.1+deb.sury.org+1 with xdebug enabled on ubuntu xenial, 8x Intel(R) Core(TM) i7-4771 CPU @ 3.50GHz We baked the application using the latest CakePHP 3.5.10, and set application debug to false, and log output to syslog. As we are interested in boosting API response times the most, we tested the following scenarios
  • A) CakePHP json output, served from nginx+phpfpm
  • B) CakePHP + API Plugin Middleware integration json output, served from nginx+phpfpm
  • C) CakePHP + API Plugin Middleware integration json output, served from php-pm
Benchmark figures were obtained using ab -n 5000 -c 100 URL

Results

Scenario requests/second avg time
A) CakePHP json output, served from nginx+phpfpm using php7.1 372.97 [#/sec] (mean) 268.120 [ms] (mean)
B) CakePHP + API Plugin Middleware integration json output, served from nginx+phpfpm using php7.1 399.79 [#/sec] (mean) 250.133 [ms] (mean)
C) CakePHP + API Plugin Middleware integration json output, served from php-pm using php7.1 911.95 [#/sec] (mean) 109.656 [ms] (mean)
D) CakePHP + API Plugin Middleware integration json output, served from php-pm using php7.2 1811.66 [#/sec] (mean) 55.198 [ms] (mean)
  These results for a NOT OPTIMIZED CakePHP application are promising, and the improvement using PHP-PM is huge in this case. There are some important considerations though:
  • PHP-FPM is mature and stable, PHP-PM is still in early development, although there is a 1.0 version released already.
  • Processes need monitoring, specially regarding memory leaks, we would need to manage a restart policy and be able to hot-restart individual workers
  • System integration, init scripts are not provided, even if this is something easy to manage nowadays via systemd or monit, would be good to have for production
  • Application bootstrapping should not be affected by the request. If your application bootstrapping depends on the request params, or logged in user, you'll need to refactor your code
  • Session handling was not tested, issues are reported for PHP-PM for other frameworks. We were aiming to stateless API's so we don't know if this would be an issue for a regular application
Performance is always a concern for the API developer, applying proven paradigms like the event driven development (https://reactphp.org/) to your existing code would be the way to go and ensure backend frameworks like CakePHP will perform as required when dealing with the peaks we all love and hate. Edit: We've added a php7.2 based benchmark, with a huge performance improvement.

Giving back to the community

This Plugin's development has been sponsored by the Cake Development Corporation. Contact us if you are interested in:      

Why an independent code review is impo...

Passbolt recently contacted us about doing a code review so we thought now would be a great time to share more about our code review process with you. While in-house and peer reviews are important to maximise code quality, it is still incredibly important to get an independent third party to review your code - that is where CakeDC can step in. Passbolt is free, open-source, self hosted password manager for teams which makes collaboration and sharing company account credentials within a team much easier. It's based on open security standards and uses OpenPGP to authenticate users and verify secrets server side. Passbolt consists of server side web app built in CakePHP providing web interface and API, and Chrome extension for client side. The overall aspects that are reviewed in our code review include a review of quality, implementation, security, performance, documentation and test coverage. When looking into quality, the team reviews aspects concerning the code following CakePHP conventions, coding standards and coding quality. Overall, passbolt’s code review revealed that CakePHP conventions and coding standards are largely followed, no concerns were detected. Implementation outlines key issues with framework use and approach. It includes reviewing the code for framework usage, separation of concerns as well as code reuse and modularity. Key recommendations are outlined at this point and guidance is given into how to solve any issues. For the Passbolt review, bigger or concerning issues were uncovered, but improvements were recommended and outlined within the closing documentation. The security portion of the code review deals with how secure the code is in terms of CakePHP usage. No security flaws were found in the passbolt code review. Our in depth code review focuses on performance, specifically investigating any bottlenecks in the code base and database as well as indexes optimization. For the full passbolt code review results, check out the Code review results. Passbolt has also posted about their review, check out their post here. If you or your company has a CakePHP application and you aren’t sure if its running at the optimum, then get in touch - Code reviews can offer insights and learning into how to improve your application.

Errors to fix today on your site

Running a website can lead to massive success for you business, however, without the proper maintenance, you can be losing out. Some errors your site can be suffering from may be minor, such as spelling mistakes, however, there may be errors that can have significant impacts such as pending security updates. Let's take a quick look at some that you should fix today! Basic HTTP errors If there are HTTP errors lurking on your site, your visitors are probably getting frustrated. Make sure to constantly review your website for these errors. Some of the more common ones include 401, 404 and 500 errors. Spelling errors, basic content duplication and broken links These are all easy and minor errors to fix, however they can lead to your visitors losing trust in your company or brand. Invalid HTML Your website’s HTML needs to follow the published HTML standards and if not, will lead to invalid HTML. Having invalid HTML leads to a multitude of things including impacted/lower SEO rankings, reduced accessibility for visitors using screen readers and other assistive technologies and browser compatibility. Pending security updates and version updates Having pending updates can open you up to malicious activity such as website defacing or stealing of confidential information. If you have an update pending, quickly update today! Incorrectly inserted analytics tags Be sure to double check that your analytics tags have been added to your code correctly. You may be missing out on valuable information that will help you improve your website. Not sure what you are doing wrong? Google offers guidelines and tutorials to get any issues sorted out quickly. Lastly, be sure to ask yourself - Have you tested? Testing is another key part to the success of your new site’s launch. Be sure to not miss this step. Not sure how to properly test your site? Here’s a great checklist to check out. From how to test elements such as HTML, CSS, security and performance through to SEO and accessibility, this checklist will guide you along best practices when it comes to testing. Another important tool to make use of is the W3 Markup validator.  

We Bake with CakePHP