CakeDC Blog

TIPS, INSIGHTS AND THE LATEST FROM THE EXPERTS BEHIND CAKEPHP

CakeFest Is Going Digital!

What a strange unprecedented time we are living in, right? Thanks, COVID-19. CakeFest, just like many other conferences and events, has been up in the air. Our team spent weeks discussing the possibility of moving forward as planned, having backup plans, or ways out of contracts should the emergency continue. After negotiations with pending sponsors, venues, vendors, etc., we toyed with the idea of going virtual and following suit of many others. After discussions with the core team, it was decided that this was the way to go. 

 

This virus infused world is uncharted territory for billions of people, but one thing remains the same among us all…. the safety and health of our clients, families, and teams is the number one concern and priority. I’m sure everyone has encountered those who don’t understand these types of decisions, but allow me to put some numbers into perspective:

Currently, there are 1,696,588 cases of COVID-19 worldwide, and 105,952 deaths have been reported  (as of April 12, 2020 via World Health Organization). According to hopkinsmedicine.org: “The virus can spread between people interacting in close proximity—for example, speaking, coughing, or sneezing—even if those people are not exhibiting symptoms. In light of this evidence, CDC recommends wearing cloth face coverings in public settings where other social distancing measures are difficult to maintain (e.g., grocery stores and pharmacies) especially in areas of significant community-based transmission.” 

 

So what I am reading is that someone who has it, may not even know they are carrying the virus, and can spread the germ by just being in the same area as a peer. This is even more frightening due to the fact that there’s no research to this new virus, therefore no cure or vaccine to combat its effects on those infected. 

 

With the statistics and facts about this virus, we made the difficult decision to go digital for CakeFest 2020. We understand that our intended dates in October are still far away, but without knowing how regulations and orders will change from government officials, it is hard to plan such an important event. Hopefully after learning more about how we came to this decision, you will understand and support us. We were extremely excited to bring the Cake to Los Angeles, but not at the cost of anyone’s health. We also hope to still deliver the knowledge, information, and possibly some ElePHPants to our virtual attendees this year (while also keeping you safe). The good news is, we can host in LA next year! And look at it this way, you can watch and learn in your pajamas! 

 

So what will CakeFest look like this year? We are still in the planning phases, and allowing for sponsors. After a lot of research we hope to find the best platform for our needs, and the best speakers to share the knowledge. Speaking of which, if you have tips or suggestions for hosting a virtual conference, we’d love to hear from you! You can email us.  Tickets will be sold (for less cost, there's a silver lining) for full access to all videos - before and after the event. We will conduct the conference as normal, but the difference is, we won’t be face to face

 

To keep up with the planning process or any changes, make sure you follow us on Twitter, or Facebook. You can always stay up to date at CakeFest.org, too. 

 

Latest articles

PHP Quality Assurance Tools with CakePHP

In Software Development, we are always looking for resources to improve the products we deliver. In this article we show some awesome php qa tools to help us improve our CakePHP software quality and development process. Let's dive in. Note: The snippets provided in this article can be found at https://github.com/CakeDC/phpqa-app-example
 

Coding Standards

Choosing a coding standard for your project will help the developers team speak the same language by defining a set of rules on how to name variables, methods, class and etc. The coding standard usage can make the integration of community libs and plugins easier. Checking and fixing coding standards are easily done with the awesome tool PHP_CodeSniffer, this tool has two main scripts:
  • phpcs check for coding standard violations
  • phpcbf autofix coding standard violations, keep in mind that not all errors will be autofixed, but will help you a lot.
     
CakePHP offers a customized coding standards at https://github.com/cakephp/cakephp-codesniffer and you should be using it.
  Let’s install the tool and the coding standard: composer require --dev cakephp/cakephp-codesniffer:~4.1.0
Create the file phpcs.xml <?xml version="1.0"?> <ruleset name="App">    <config name="installed_paths" value="../../cakephp/cakephp-codesniffer"/>    <rule ref="CakePHP"/> </ruleset>
Update “scripts” block in composer.json  with: "scripts": {         "cs-check": "phpcs -p ./src ./tests",         "cs-fix": "phpcbf -p ./src ./tests",
  Now we can run composer cs-check and composer cs-fix. In a sample app I got this output saying some errors can be autofixed with composer cs-fix


Static Analysis

How many times have you deployed a project on a production server and found a silly error like calling an undefined method? I hope not often. To avoid this type of issue, a static analysis tool is useful. I recommend you to use PHPStan and PSalm, these tools will help you find errors without having to run the application.

PHStan

PHPStan will rely on phpdoc, so that’s one more reason to use a coding standard tool like PHP_CodeSniffer. Also I recommend that you use the plugin: cakephp-ide-helper, to update annotations (phpdoc) in your app classes. In some cases we need to help PHPStan understand our code better, and for this reason we created a custom extension: https://github.com/cakedc/cakephp-phpstan. Let’s install PHPStan using composer: composer require --dev phpstan/phpstan phpstan/extension-installer cakedc/cakephp-phpstan:^1.0
  We also need to create two config files Includes:     - vendor/cakedc/cakephp-phpstan/extension.neon     - phpstan-baseline.neon parameters:     level: 6     checkMissingIterableValueType: false     checkGenericClassInNonGenericObjectType: false     autoload_files:         - tests/bootstrap.php     ignoreErrors: services: parameters:     ignoreErrors:
  And add two scripts into “scripts” block from composer.json "stan": "phpstan analyse src/",         "stan-rebuild-baseline": "phpstan analyse --configuration phpstan.neon --error-format baselineNeon src/ > phpstan-baseline.neon",
Now we can run composer stan and  composer stan-rebuild-baseline the second one will populate phpstan-baseline.neon to ignore all errors returned in composer stan so only use when all the errors shown should be ignored.  

Psalm 

Psalm is another awesome static analysis tool, it provides a way to check for errors in your code, and can fix some of them, too. In my experience psalm and phpstan work perfect, so you don’t need to pick one or the other, you can use both. Let’s install psalm: composer require --dev  "psalm/phar:~3.11.2"
We also need to create two config files <?xml version="1.0"?> <psalm     allowCoercionFromStringToClassConst="true"     allowStringToStandInForClass="true"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xmlns="https://getpsalm.org/schema/config"     xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"     errorBaseline="psalm-baseline.xml" >
   <projectFiles>         <directory name="src" />     </projectFiles>     <issueHandlers>         <LessSpecificReturnType errorLevel="info" />         <RedundantConditionGivenDocblockType errorLevel="info" />         <TypeCoercion errorLevel="info" />         <DocblockTypeContradiction errorLevel="info" />     </issueHandlers> </psalm>
  <?xml version="1.0" encoding="UTF-8"?> <files psalm-version="3.11.2@d470903722cfcbc1cd04744c5491d3e6d13ec3d9"> </files>
  And add two scripts into “scripts” block from composer.json "psalm": "psalm.phar --show-info=false src/ ",         "psalm-rebuild-baseline": "psalm.phar --show-info=false  --set-baseline=psalm-baseline.xml  src/"

Now we can run composer psalm and  composer psalm-rebuild-baseline the second one will populate psalm-baseline.xml to ignore all errors returned in composer stan, so only use this when all the errors shown should be ignored. When we run composer psalm it may inform you that some errors can be autofixed and which arguments you should use to fix. Normally it will be something like vendor/bin/psalm.phar --alter --issues=MissingReturnType,MissingClosureReturnType --dry-run
Psalm will only change the file If you remove the --dry-run part.  

Testing

Testing is extremely important for any application development. There are many types of software for testing, in this article we are focusing on unit tests. Unit tests help us check if one specific piece of code is working as expected, you can think like ‘Is method ‘A’ returning the correct value when argument has value ‘Z’?’. In CakePHP we have built-in support to PHPUnit, CakePHP integration offers additional features to make it easier to run units tests like custom asserts and methods for integration tests, and fixtures logic for models. We can bake unit tests using the bake plugin. To improve your unit tests try the cakedc/cakephp-db-test with this one you can use database fixtures instead of files. Learn more at: https://www.cakedc.com/rafael_queiroz/2020/04/27/unit-testing-with-cakedc-db-test PHPUnit probably already is installed in your app but if not I recommend you to compare your project files with: https://github.com/cakephp/app. For more information check out: https://book.cakephp.org/4/en/development/testing.html   Hope you enjoyed this article and will start using these awesome tools to make your projects better than ever. Good Baking.  

Working with CakePHP Authorization

As you may know, there are 2 new plugins "recently" (not so recently) added to deal with the concepts of Authentication and Authorization in your CakePHP applications. Over the years, both Authentication and Authorization were managed in the Controller layer, via AuthComponent.  These 2 things usually grow in complexity as your project grows too, making the AuthComponent a complex class dealing with many features at the same time.
One of the original ideas behind these new plugins was to refactor AuthComponent and create specific layers to handle:

  • Authentication: who are you?
  • Authorization: are you allowed?
We are going to explore the Authorization concepts in this article using a specific example: Let's imagine we have some kind of game application where Users are going to manage Tournaments. The Users will be able to create new Tournaments, and join the Tournaments through a TournamentMemberships many to many association. Other users won't have access to the Tournaments unless they are invited to play. Players of a Tournament can invite other Users to play. So, a quick list of the use cases we are going to cover below are:
  • /tournaments/add  any user can create a new Tournament
  • /tournaments/index  browse all joined tournaments
  • /tournaments/invite  only current Members can invite others, and only if the Tournament has not started yet
We are assuming Authorization step is done in our application and we have a logged in user available in our request. At this point we'll also assume you've installed cakephp/authentication and cakephp/authorization and loaded both plugins. Authorization does not impose restrictions  on when the authorization checks will be done, let's quickly examine the workflow and related classes for Authorization:
  • AuthorizationMiddleware is attached to your Application, and will ensure the Authorization will be checked somewhere while processing the request.
     The unauthorizedHandler config will allow you to define what to do if the request was not authorized for some reason.
  • At some point in your code, you'll need to call AuthorizationComponent, either to
    • skipAuthorization when you don't require any specific condition to authorize the operation. Example: // ... somewhere in your beforeFilter...     if ($user->is_superadmin) {         $this->Authentication->skipAuthorization();     } // ...
    • authorize($resource, $action) when you need to check if a given user is allowed to do some action on a given resource. Note the resource must be an Object.


How Authorization checks are done?

  1. We start by checking the resource, it's an Object so we use a Resolver to map every resource with a given Policy. There are some common defaults, for example to map ORM classes.
  2. Once we get to a Policy class, we check the matching method, for example if the action is "invite" we would check the method canInvite(IdentityInterface $user, Tournament $tournament)
Configuration: After the Authentication middleware, in your src/Application.php class, add the Authorization Middleware            $authorizationService = new AuthorizationService(new OrmResolver());             ...             ->add(new AuthorizationMiddleware($authorizationService, [                 'unauthorizedHandler' => [                     'className' => 'Authorization.Redirect',                     'url' => '/users/login',                     'queryParam' => 'redirectUrl',                 ],             ]));   Note the $authorizationService is configured with one resolver to match the CakePHP typical ORM classes, like Entities or Queries. https://book.cakephp.org/authorization/2/en/policy-resolvers.html#using-ormresolver   Once the middleware is added, you'll need to ensure the Authorization is checked, or you'll get an  error?: "The request to / did not apply any authorization checks" . The first step would be to skip authorization for all the controllers and actions, for example in beforeFilter callback that all Users are allowed to access. About the previous Tournaments specific cases, we'll need to create a new Policy class including all the possible actions to be done, for example:
 
  • /tournaments/add
We need to create a new Policy for the Tournament Entity file src/Policy/TournamentPolicy.php to define policies related to specific tournaments class TournamentPolicy {     public function canAdd(IdentityInterface $user, Tournament $tournament)     {         // all users can create tournaments         return true;     } } file src/Controller/TournamentsController.php // ...     public function add()     {         $tournament = $this->Tournaments->newEmptyEntity();         $this->Authorization->authorize($tournament);         if ($this->request->is('post')) { // ... The call to $this->Authorization->authorize($tournament); will map the Tournament entity to the TournamentPolicy, by default the action is taken from the controller action, in this case "add" so we will need to define a canAdd() method. We allowed all Users to create Tournaments.  
  • /tournaments/index
We'll need to create a new policy for the TournamentsTable, and additionally a scope method to filter the Tournaments based on the current User membership. file src/Policy/TournamentsTablePolicy.php to define policies for the TournamentsTable class TournamentsTablePolicy {     public function canIndex(IdentityInterface $user, Query $query)     {         // all users can browse tournaments         return true;     }     public function scopeIndex(IdentityInterface $user, Query $query)     {         // scope to filter tournaments for a logged in user         return $query->matching('TournamentMemberships', function (Query $q) use ($user) {             return $q->where(['TournamentMemberships.user_id' => $user->get('id')]);         });     } } file src/Controller/TournamentsController.php     public function index()     {         $query = $this->Tournaments->find();         $this->Authorization->authorize($query);         $tournaments = $this->paginate($this->Authorization->applyScope($query));           $this->set(compact('tournaments'));     }
 
  • /tournaments/invite
file src/Policy/TournamentPolicy.php to define policies related to specific tournaments // ...     public function canInvite(IdentityInterface $user, Tournament $tournament)     {         return TableRegistry::getTableLocator()->get('TournamentMemberships')             ->exists([                 'user_id' => $user->get('id'),                 'tournament_id' => $tournament->get('id'),             ]);     } // ... file src/Controller/TournamentsController.php // ...     public function invite($tournamentId, $userId)     {         $tournament = $this->Tournaments->get($tournamentId);         $this->Authorization->authorize($tournament); // ...   In this case, we need to check if the logged in User is already a member of the TournamentMemberships group, if so, we are allowed to invite another user. As you can see, Authorization plugin will provide a flexible way to manage your application permissions.   In the previous examples we've covered typical application use cases to handle permissions per resource and action. New classes and interfaces, like policies, resolvers and mappers will allow you to configure the Authorization and ensure all the resources in your application will provide the required permissions. If you're looking for RBAC based on your controller actions, take a look at https://github.com/CakeDC/auth/blob/master/Docs/Documentation/Authorization.md For additional tools and plugins, check https://github.com/FriendsOfCake/awesome-cakephp#authentication-and-authorization  

Benefits of S.E.O

As a marketer that works with web developers daily, I know that content may not be top priority on their long list of to-do’s. However, for the success of a company, it is essential. If your team doesn’t have a designated marketing person or team, and you’re not a seasoned content creator, I have 3 letters for you to learn: S.E.O.   So what is SEO? It stands for search engine optimization. Basically this represents guidelines for gaining traffic to your website (or one you’ve been hired to create), and doing it organically. What is organic traffic? This is the results people see without being targeted, no paid ads, no cold calling - just desired results because your company offers something that they are interested in.    Today’s market is extremely competitive, so it is important to take every step in making sure that your webpage stands out and is easy to find. Think about how you find information daily… how to make fried chicken? Where to get your car fixed? Or even when a new movie is being released? You search for it, online, right? 9 times out of 10, you’re probably going to run a search for it on a site like Google, right? Then, most likely, you’re going to click on one of the first couple results that pop up on your screen, because they include keywords relevant to the search that you performed. This is an example of SEO. You search for a term that is relevant or appears on a company’s website, and Google recognizes that term/phrase and yields the webpage to you as a result. Thus, increasing traffic for the website, and a lot of times, without any cost to them.    Utilizing this idea, or service, is essential for any marketing department. Actually, according to a recent survey done by HubSpot, about 64% of marketers actively invest time in search engine optimization. So if you're not, you're falling behind.     Now that you have a basic understanding of what SEO is, we can talk about some of the benefits.   

1. Better PR

  The better your SEO is, the more people that will see your company name pop up on their search engine results. While most companies, like CakeDC, offer specific services (and input specific keywords into ads), we have very detailed SEO streaming from our website so that we do not miss a potential client. It is the goal to be in the top 3 results of a search engine like Google.   Even if someone is searching for something your company doesn’t offer, they may see you, remember you, and use you in the future. win-win. Start building your reputation! For example if you wanted to search for CakePHP web development, you may see:    

2. Increased Traffic 

  This is a no brainer. The more keywords that trigger your webpage at the top of consumer results, the more people that will click. This generates better quality leads, in my opinion. Things like cold calling, or cold emailing, while still effective, have become outdated. Inbound marketing compared to these avenues has produced better return, without becoming annoying to your potential leads. When you aim your focus on specific consumers looking for services that are related to your business, you can build better relationships.   

3. FREE

  Perhaps the best benefit of SEO? The cost… or lack of cost. SEO gets clicks, and sales (we hope!) for the wonderful price of $0 per month. How? Well, Google’s organic rankings come from their algorithm, which determines which webpage’s information relates closely to the “searcher’s” inquiry. This can result from keywords coming from your web pages that may not be imputed on any sort of ads you may be running (we will talk about paid ads in a future blog).    This doesn’t mean that getting a perfect SEO score (yes, you can test it) comes for free. It is important to have good content, detailed content, in all areas on your webpage. Make sure each page describes services you provide, or products that you sell, in great detail. Have pages for each option, and make it accessible like this:       It’s time to beat out the competition, are you ready? I first recommend seeing where you stand. There are a few tools you can use to test your SEO score. One example is: Woorank. I like this site because it gives you your score, shows the good, the bad, and the ugly. The tool also shows you what you can and should do to improve your SEO. You can try most tools for free, or get extra optimization help by paying a premium.    Once you run a report, it’s time to get to work. Fix the issues, and constantly monitor your information. I do think it’s important to mention - don’t expect results to happen overnight, it can take up to 6 months for SEO strategies to yield return. If you’re like me, and impatient, just chill. Put the work in, and get the reward.  

We Bake with CakePHP