CakeDC Blog

TIPS, INSIGHTS AND THE LATEST FROM THE EXPERTS BEHIND CAKEPHP

Baking Smarter, Not Harder in 2021

After the year we had… our new motto should be work smarter, not harder, in 2021? Am I right? Luckily, CakePHP community and core members are extremely helpful and constantly working to make baking easier. Here are some things that will assist you with your CakePHP projects….

Plugins:

I recently wrote a blog featuring some of the best (voted by the community) CakePHP plugins - you can see it HERE. A full catalogue of CakePHP plugins is available at https://plugins.cakephp.org. It is no secret that plugins are essential for developers. CakeDC has a few of our own as well, you can get details at:  https://www.cakedc.com/plugins. The good news is, if you don’t see one, but have a great idea, you can build and release your own! To learn more about this process, Jose Gonzalez explains it in his CakeFest 2021 Talk.     Lots of other videos / talks / tutorials are located in the CakePHP Youtube channel as well.
 

Tools:

If you follow us on social media, we highlight a lot of tools released from the community.  One of the most popular is the debugging tool: https://book.cakephp.org/4/en/development/debugging.html A commonly used one is to help updating your composer.json while upgrading https://toolbox.dereuromark.de/utilities/upgrade   You can see more on THIS cakePHP tools list from Dereuromark!
 

Support:

I talk about support channels a lot… because well… what is open source without them? Every time I take a virtual stroll to the slack channels, I am amazed at the participation and interaction between community members. It’s like having your own development team available anytime you need them. Rest assured that if you have an issue that's causing a blocker, someone in the chat will (most likely) have a solution. A full list of support channels was listed in our last blog, but if you missed it, here you go: Discourse forum: https://discourse.cakephp.org Stack Overflow: https://stackoverflow.com/tags/cakephp IRC: https://kiwiirc.com/nextclient/irc.freenode.net#cakephp Slack: https://cakesf.herokuapp.com
 

The Book:

If you’re a veteran baker, you already know this. However, this wouldn't be a helpful blog without mentioning the all mighty book… The CakePHP bookThis is where you should start on your cake journey… read it… read it again. Then, reference back to it when you need it. There is an average of 46k users utilizing the book monthly (184k sessions). That should speak for itself.
 

Newsletter:

The CakePHP team releases a newsletter each month. This is a good resource if you’re looking to catch up on a month’s worth of news in one place.  Usually included is: releases, helpful tools, training/event dates, specials, surveys, and more.  You can see previous newsletters & subscribe HERE.   I will close this with a shameless plug: if you want to work a whole lot smarter this year, let someone else do the work for you. Check out all of the CakeDC services offered at cakedc.com/services.    Here’s to 2021 being a lot easier… more peaceful… and tasty!  

Saying Goodbye To 2020 Is A Piece of Cake

I never thought that I would be so excited to say… the year is coming to an end. What a year it has been. Let’s focus on some good things that happened for us this year.

CakePHP Community

Our team worked as closely as ever with the CakePHP community. We have hosted training sessions and multiple online meetups - for which we had consistent attendance and involvement. We have enjoyed getting to know each baker that attends and interacts with us. It was a great year for releases, too. If you follow the social media pages, you’re up to date with all of the new features and tools that are released in real time. Not to mention new and updated plugins. You can see all of the latest releases in the BAKERY.  

CakeFest

While we usually get to travel to some amazing city in the world and meet with the attendees in person, clearly that was not going to be an option this year. For the first time ever, the event was held virtually. Being so involved, and responsible for the success of the event, was stressful and frightening to say the least, but alas…it came together wonderfully.  We were able to have attendees that may not have been able to join us otherwise, and the participation was unprecedented. I am so thankful for the wonderful sponsors, speakers, attendees, and contributors that made the event possible.  In case you didn’t know, all of the CakeFest 2020 videos have been released. You can view them in the CakeFest archive, or on the CakePHP Youtube channel. Don’t forget to subscribe to the channel, and I will tell you why later.    Now… what can be expected in 2021? LOTS!

Increased Involvement

We want to expand the kitchen, if you will. We have an amazing group of core developers, and they would love to have more involvement from the community. If you’ve ever thought about contributing and getting involved, there are many options, you can check out details HERE.   

More documentation / blogs

Speaking of getting more people involved, this will include blogging. We have so many great plugins, but maybe not enough documentation to support the training on them. The core team is on board and we will all be working hard to provide more documentation for the framework. In fact, we even some some community members that have already volunteered to provide more blog contributions to the bakery. Maybe you’d like to as well?!  

Video Tutorials

One suggestion that we get consistently is that we need more video tutorials. We agree! We are going to be updating our YouTube channel and will hopefully be adding more video tutorials as soon as Q1. We will also make sure that training sessions / meetups will be available to subscribers for playback. We would love to hear your suggestions for content, you can email us at [email protected] and let us know what you’d like to see. 
 

Support

As always, CakePHP has many support channels, and this will not change in the new year. In fact, we plan to make it even easier to connect with other bakers.   Here are some current available support options: Discourse forum: https://discourse.cakephp.org Stack Overflow: https://stackoverflow.com/tags/cakephp IRC: https://kiwiirc.com/nextclient/irc.freenode.net#cakephp Slack: https://cakesf.herokuapp.com
  Want to have your opinion heard? The core team wants to know what you want for CakePHP 5. Please take a moment and fill out a quick SURVEY to let them know.    We can’t wait to bake with you in 2021. Wishing you all a happy holiday season and a very happy new year!  

Baking With Attributes

Tasting the cake with attributes

Attributes is a declarative way to pass information about the behaviors of various elements like classes, methods, properties, and even method parameters in your programs. In fact, attributes are used for adding metadata to existing code, and could be used as a way to reduce visual debt, and this way simplifies how code looks like.  

Defining an attribute

An attribute is simply an object whose class inherits from the Attribute class. However, attributes are not used in the same way as a typical object. They often add some additional semantics about the class or method, or to toggle behavior on or off. Some attributes specify functionality. For example, an attribute may contain a method that defines security behavior.  

Declaring Attributes

The attribute itself may be declared as a class. This is validated only when the attribute is fetched, and not immediately when the code is parsed. A PHP attribute is a class, declared with #[Attribute] attribute. In the following example we define an attribute class which allows us to specify what methods are allowed for controller actions.     Take note that in PHP 8 you can declare properties directly in class constructors, which is really handy for data classes.
 

Consuming reflection API to define meta behaviors

Just defined attributes have not added new code logic. To add new behavior we should implement it. Attributes could be fetched using the reflection API. PHP engine knows about attributes but does not instantiate it’s classes, so we have to do it ourselves. Reflection provides getAttributes() methods to fetch a list of associated attributes.   The following  example shows how we can add permissions checks for controller actions using attributes. In this example, the code is stored in beforeFilter of the controller class itself, but it could be an AppController or more generic solution.    

Where to use Attributes

Here are some areas where web frameworks could use attributes:
  •  Routes definition for the controller methods;
  • Validation rules as attributes for entity properties;
  • Smart object serialization, which defined as properties attributes
  • Security rules defined for classes and methods.
  • Static code analyzers.
  • IDE code hinting.
  The attributes are very handy and powerful, they could reduce visual debt and improve code quality. Hopefully this helps with your future projects!  

CakePHP Query Builder

CakePHP’s  database Query Builder provides a simple to use fluent interface for creating and operating database queries. It can be used to accomplish most database operations in your application, and works on all supported database systems.
Query builders allow us to create database queries that work with any supported database, without having to worry about differences between SQL implementations in the different database systems.


The CakePHP query builder uses PDO parameter binding to protect your application against SQL injection attacks. There is no need to clean strings being passed as bindings.
For creating a Query object in CakePHP, the easiest way is using find() from a Table object. In CakePHP, queries are lazily evaluated,  which means that they are not evaluated until any of the following actions happens: the query is iterated through a foreach, it’s called first(), all(), toList(), toArray(). 
You can check all the SQL queries that CakePHP is generating, you just need to enable the Database Logging. See here:  https://book.cakephp.org/4/en/orm/database-basics.html#query-logging
Let’s do a few samples using the Query Builder - this is the ER diagram of the database that we will be using for the queries. We have Orders, ProductsUsers and Items that will store the products sold in each order and the quantity sold. Let’s create some queries using the Query Builder SQL Functions: https://book.cakephp.org/4/en/orm/query-builder.html#using-sql-functions. SQL Functions as part of the Query Builder are abstractions of  some commonly used SQL functions,  and they allow the ORM to choose the specific implementation your application needs based on the Database that is being used. For example, CONCAT is implemented in a different way in MySQL and Postgres, using concat() function will work if you use MySQL or Postgres   Imagine we want to build a report of the products sold, including the following:

  1. Display the product in the following format “Products.name - Products.description”.
  2. Total of products sold.
  3. Total of products in stock..
  4. Total amount on sold products.
First, we need to build the Query object using find(), this needs to be done from the Table. $query = Table->find();. We want to get a report of the products sold and the current stock. Initially, we would need to build a subquery using ItemsTable where the information related to the products sold is present.  Don’t forget to use identifier() when referencing any column. This will tell us  the items sold per product. 

$itemsQuery = $this->Items->find() ->where(['Items.product_id' => $query->identifier('Products.id')]);

Now, let’s build each query needed for the information required:
  1. Let’s start displaying the  product in the following format: “Products.name - Products.description”. Using concat() we could get it: $query->select([             'display_name' => $query->func()->concat([                 $query->identifier('Products.name'), ' - ',  $query->identifier('Products.description')]),         ]);
  2. Total of products sold. Using sum() we could get it, we just need to sum Items.quantity per each product,  this  is why we use $itemsQuery and then we sum the quantity per each product. $query->select([
      'quantity_sold' => $itemsQuery->select(['sum' => $itemsQuery->func()->sum($query->identifier('Items.quantity'))]),
    ]);
     
  3. To get the income, we need to multiply the Quantity of items  *  Price  and sum all of them.    $query->select([
              'income' => $itemsQuery->select(['sum' => $itemsQuery->func()->sum($query->newExpr('Items.quantity * Items.unit_price'))
                ])]);
     
  4. Stock. to get the stock we need to take advantage of the quantity_sold we just got in #2, and subtract it from the real quantity Products.quantity. For getting this, we would need to create a subquery in the FROM clause using the previous queries, and then subtract in the target query something like quantity - quantity_sold. $products = $query->cleanCopy()->select([
                'id' => 'ProductDetails.id',
                'price' => 'ProductDetails.price',
                'quantity' => 'ProductDetails.quantity',
                'display_name' => 'ProductDetails.displaye_name',
                'quantity_sold' => 'ProductDetails.quantity_sold',
                'income' => 'ProductDetails.income',
                'stock' => $query->newExpr('ProductDetails.quantity - ProductDetails.quantity_sold'),
            ])->from([
              'ProductDetails' => $query->cleanCopy()->select([
                    'id' => 'Products.id',
                    'price' => 'Products.price',
                    'quantity' => 'Products.quantity',
                    'display_name' => $query->func()->concat([$query->identifier('Products.name'), ' -  ', $query->identifier('Products.description')]),
                  'quantity_sold' => $itemsQuery->select(['sum' => $itemsQuery->func()->sum($query->identifier('Items.quantity'))]),
                  'income' => $itemsQuery->cleanCopy()->select(['sum' => $itemsQuery->func()->sum($query->newExpr('Items.quantity * Items.unit_price'))]),           ])
        ]);
     
Notice that we are using cleanCopy(), this is useful when the same Query object is affected previously by a select(), from() or where clauses, if you run this same example without using cleanCopy() you will get unexpected results.  The SQL query generated is this: SELECT ProductDetails.id AS id, ProductDetails.price AS price, ProductDetails.quantity AS quantity, ProductDetails.display_name AS display_name, ProductDetails.quantity_sold AS quantity_sold, ProductDetails.income AS income, (ProductDetails.quantity - ProductDetails.quantity_sold) AS stock FROM (SELECT Products.id AS id, Products.price AS price, Products.quantity AS quantity, (CONCAT(Products.name, :param0, Products.description)) AS display_name, (SELECT (SUM(Items.quantity)) AS SUM FROM items Items WHERE Items.product_id = (Products.id)) AS quantity_sold, (SELECT (SUM(Items.quantity * Items.unit_price)) AS SUM FROM items Items WHERE Items.product_id = (Products.id)) AS income FROM products Products) ProductDetails
CakePHP QueryBuilder gives a ton of possibilities to create queries with clean and robust code. So go play with it and enjoy!  

Are you ready for PHP 8?

In just two days we will get a new PHP release, PHP 8. It’s been almost  5 years since PHP 7 was born and now we are about to enjoy the new major version, which will include some breaking changes and performance improvements.   It comes with a lot of new features, including:  

  • PHP JIT
  • Union types
  • Named arguments
  • Attributes
  • Match expression
  • Constructor property promotion
  • New static return type
  • New mixed type
  • Throw expression
  • Inheritance with private methods
  • Weak maps
  • Allowing ::class on objects
  • Non-capturing catches
  • Trailing comma in parameter lists
  • Create DateTime objects from interface
  • New str_contains() function
  • New str_starts_with() and str_ends_with() functions
  • New fdiv() function
  • New get_debug_type() function
  • New get_resource_id() function
  • Abstract methods in traits improvements
  • Object implementation of token_get_all() 
  • Variable syntax tweaks
  • Type annotations for internal functions externals
  • ext-json always available
  We will explain some of these features in future posts.   Remember that PHP 7.4 active support will remain until November 2021, with security fixes until November 2022. PHP 7.3 active support is almost over and the team will provide security fixes for 1 more year. Finally, PHP 7.2 is already out of active support, and almost out of security fixes (in 5 days). If you want to check PHP versions and support you can go HERE.   So, Are you ready for PHP 8?  

The Making of a Marketing Plan

Listen, although 2020 felt like it lasted 25 years, it’s still hard to believe that we are wrapping up this roller coaster of 12 months.  As companies prepare for 2021, crossing their fingers and wishing for a better Q1… it is important to start thinking about marketing strategies and plans for the next year. Without ideas and a solid goal for your company, it is very unlikely that things will change.   Reasons that making a marketing plan is important:  1. It organizes your goals and provides clear plans of actions to achieve them  2. It keeps everyone on track and on the same page  3. Promotes motivation and accountability
  I know making a marketing plan can sound time consuming, and a little complex, but it doesn’t have to be! I am going to walk you through the steps of making clear cut goals and plans for 2021 (with some actual examples!).  

1. Brainstorming

Our team is great at making notes of things that need attention, whether it's good or bad. We keep open lines of communication on things that are going well, or may need some extra work. It is important for everything to bring their ideas together, no matter how big or small.  I suggest keeping a notepad with things / ideas you have for your team moving forward, and organize them in a way to present to your marketing team.  

2. Team meeting

Now it is time for a group session to compare ideas, talk about what should be the priorities and get approval on anything needed. These meetings are super beneficial, because it is always refreshing to see if your team’s ideas mimic yours, or perhaps they even have some additional great ideas.   

3. Start building your plan

There are ample amounts of templates and checklists that you can find online to ensure that you’re including important information on your strategy plan. Some of the things I recommend including are:
Of course your main table of contents - easy to view for your team     Company mission - WHO ARE YOU?  
  Product Overview - what are you offering your clients?     Goals / Challenges - we all have them, don’t be shy  

Target market - Who are you working for?       Expansion Plan - how will you make it to the next level?   Upcoming Actions - Making a clear timeline for the next year. It is important to make the timeline obtainable... in other words, don’t make goals that are impossible to meet.   Other important topics include additional small actions, goal timeline, campaign calendars, advertising outlets, social media platforms (and the importance, utilization for each one).  

So making a powerpoint or pdf presentation for your team will allow all of the ideas and goals  to come together and be available in one place. I am a big checklist type of person, so in addition to my marketing plan, I always create a document.   

4. Create a spreadsheet

A spreadsheet doesn't have to be fancy, but it holds the team accountable, and we are able to make notes so that we can track the status of certain actions. This also helps me stay on track, and know what actions need to be executed next.    Something like this for internal works just fine:  
 

5. Budget & Execution 

It is extremely important that your team supports the marketing efforts. It is also important to know what your marketing budget will allow. Will you have additional funds for new goals? Will you need to reduce funds on other outlets to allow for new ideas? These are things that will need to be discussed with your financial department.   This is a good reason to create a marketing metrics / budget spreadsheet to track these items. I will share my examples on this in a future blog.    So, once your team is on the same page, and they have clear goals…. IT’S GO TIME. Start working on your plan of actions and preparing to let them fly. For us, some of our goals will take some prep work, so we are gearing up in Q4. 
  Hopefully, you have helpful ideas that you implement on your marketing plan… maybe it’s something I haven’t thought of (i’d love to hear yours! Email me - [email protected]). Either way, I wish everyone good luck on their strategies, and may all of your goals come true in 2021. If you’d like more insight on any of the ideas I have included, feel free to reach out, I’d be happy to chat!   

Baking With Traits

Traits are a mechanism for code reuse, the convention traits in CakePHP are suffixed with Trait so they can be discernible from classes or interfaces. Our book has a basic sample of Trait. For me, writing code with Traits it's not a regular daily job, but last week I found myself writing a Trait for handling the Theme of an Application.  We need to define the theme on AppView and AppController, and we don't want to repeat ourself:  Beyond re-use code, we can use Traits to separate our code by responsibility.  We like this approach so much that our Users Plugin utilizes it.:   Basically, instead of creating a regular controller with many methods, we create Traits and group the actions by domain business. Sometimes we need to override the functions, and we want add our custom logic after -before or replace the function on Traits: If you wanna bake Traits more complexly I recommend you check out the PHP manual… there,you can see how to fix conflicts, change the visibility of methods and so much more.
That's all bakers! I hope you’ve found this information to be helpful!  

Using CakePHP ORM in your app

CakePHP ORM in your app

We all know that CakePHP is a Full Stack framework, but you may not know that you can pick some of the components and use it in your app when you need. The ORM is not the only one available - you could also have filesystem, validation, utility, core, collection, database, cache, event, form, log, datasource, console and i18n. In this article, we are going to show how to use the ORM component in your slim framework app. You can find the component at: https://github.com/cakephp/?q=read&type=&language=  

Why should we use the componentes

You may be asking why to use as component instead of using the framework as it is, and one of the reasons would be that you already have an application, perhaps using slim framework, and now you need to retrieve data from database. This would be a good moment to use a lib to help you, and here is where cakephp/orm comes in handy. With the componentes you can now solve things with your knowledge in CakePHP, even when your application was not built with CakePHP.  

Setting up cakephp/orm in a slim application

The code used in this article can be found at: https://github.com/CakeDC/slim-cakephp4-packages We could use the package in any PHP application, but for this article we are going to use a slim application skeleton https://github.com/slimphp/Slim-Skeleton. In this app we’re going to change the routes /users and /users/[id] to fetch data from database instead of in-memory data.  

Install the package with composer

We are going to install the version 4.0 of the ORM package:   composer require cakephp/orm:~4.0  

Update config

The app uses the file app/settings.php to set up the main configs, so we need to add a config for database and set cakephp’s App.namespace config. First: add this line after the use declaration. Don’t worry about this config now. We’re setting this to avoid error with PHP 7.4.   Configure::write('App.namespace', 'App');   Then add your database config key inside settings array - in this case we’re using mysql database from a docker service:               'database' => [                 'className' => \Cake\Database\Connection::class,                 'driver' => \Cake\Database\Driver\Mysql::class,                 'database' => 'my_db',                 'username' => 'root',                 'password' => 'secret',                 'host' => 'mysql',             ]   See https://github.com/CakeDC/slim-cakephp4-packages/blob/main/app/settings.php  

Add TableLocator to app dependencies

The app uses the file app/dependencies.php to configure the container of dependencies, and this is a good place for us to define TableLocator as dependency since we normally would use it In my places. Let’s add this inside $containerBuilder->addDefinitions:   \Cake\ORM\Locator\TableLocator::class => function(ContainerInterface $c) {             $settings = $c->get('settings');             \Cake\Datasource\ConnectionManager::setConfig('default', $settings['database']);               return new \Cake\ORM\Locator\TableLocator();  }   See https://github.com/CakeDC/slim-cakephp4-packages/blob/main/app/dependencies.php     This service gets the settings we defined before,sets the configuration to CakePHP, and returns an instance of TableLocator. We could use this service in any route action with:    $locator  = $this->get(\Cake\ORM\Locator\TableLocator::class); $users = $locator->get('Users')->find()->all()->toArray();   But for this app it will make sense to use the TableLocator in a custom persistence class.  

Using the ORM to fetch data

Now, we are finally going to replace the current way of retrieving data to be able to use CakePHP OR. Since our idea is to have a minimum impact in the app, the best way for this app is to replace the current UserRepository. Keep in mind that you could use the following steps with any other class you have.   Create a new persistence class DatabaseUserRepository: Create the class at src/Infrastructure/Persistence/User/DatabaseUserRepository.php Define a constructor method with tableLocator parameter       public function __construct(\Cake\ORM\Locator\TableLocator $tableLocator)     {               $this->tableLocator = $tableLocator;     }          Now we can use the tableLocator to fetch data:         $this->tableLocator->get('Users')->find()->all();       $this->tableLocator->get('Users')->get(10);       ////   To make the app work correctly, we need  to add the required method findAll  and findUserOfId   See: https://github.com/CakeDC/slim-cakephp4-packages/blob/main/src/Infrastructure/Persistence/User/DatabaseUserRepository.php      Now that the repository persistence class was created, we need to connect using dependency injection. Update the UserRepository::class entry in repositories with:   UserRepository::class => \DI\autowire(\App\Infrastructure\Persistence\User\DatabaseUserRepository::class),   https://github.com/CakeDC/slim-cakephp4-packages/blob/main/app/repositories.php   That’s it! Now we can access /users and see the users stored in our database.   I hope you’ve found this information to be helpful! Let us know! For more information check out: https://github.com/cakephp/orm.

Playing with the new CakePHP Queue

One of the topics discussed in the community is the benefit of a unified, officially supported, CakePHP Queue plugin. Queues are used in most of the projects nowadays and are a central utility plugin. During the CakeFest 2020 event, there were also a couple direct references from speakers: (https://speakerdeck.com/josegonzalez/building-and-releasing-a-cakephp-plugin/?slide=15c) and this comment from Mark Story: https://cakesf.slack.com/archives/C172CS4TE/p1602257791377500.   This motivated me to take a deeper look at the cakephp/queue plugin and write this blog post.   Here at CakeDC we've been using queues for a looooong time. Initially in CakePHP 2, we've used plugins like CakeResque with redis or custom workers tied to Amazon SQS queues. Then in CakePHP 3 & 4 we've been using mostly https://github.com/josegonzalez/cakephp-queuesadilla with redis or mongodb backends. https://github.com/cakephp/queue   First thing would be setting up the plugin in your project, we are going to use the example project we used in CakeFest 2020: https://github.com/cakephp/cakefest2020/#using-docker   So after setting up the project and running it via docker compose, we can proceed to setup the plugin via composer. We will need to add it as a repository and set  

Install via composer

  After the first release it'll be much easier, but for now you'll need to add the package to your composer.json   "repositories": [         {             "type": "vcs",             "url": "https://github.com/cakephp/queue.git"         }     ]   Then do composer require cakephp/queue -W   And install some transport as stated in the official documentation https://book.cakephp.org/queue/1/en/index.html#installation composer require enqueue/redis:^0.9 composer require predis/predis:^1   Ensure your redis server is up and running, you can check the commands sent to your local redis server using redis-cli monitor   Now we are ready to configure the queue, we'll create 1 default queue adding this to the config/app.php file       'Queue' => [         'default' => [             'url' => 'redis:',         ],     ],   Add a Job using `bin/cake bake job Example` and add some code to the execute method       public function execute(Message $message): string     {         $data = $message->getArgument('data');           // do some long operation with data         Debugger::log($data);         sleep(2);           return Processor::ACK;     }   I've added a command utility to enqueue a test message bin/cake bake command addJob       public function execute(Arguments $args, ConsoleIo $io)     {         $callable = [ExampleJob::class, 'execute'];         $arguments = ['id' => 1, 'data' => ['some' => 'data']];           QueueManager::push($callable, $arguments);     }   And finally we can start our worker using bin/cake worker to pull jobs from Redis and process them using the ExampleJob::execute method   Here's all the example code created: https://github.com/cakephp/cakefest2020/tree/feature/cakephp-queue - for your reference.   Please note the plugin is still a work in progress and there is no stable release as of now.  It's looking great so far and we plan to include it in our next projects!  

Best CakePHP Plugins

Members of our team had the privilege of helping with CakeFest 2020 this year. One added virtual feature was the giveaways from CakePHP, these were done in the form of fastest-to-answer, trivia, or participation (random draw).  One of the giveaway games was to share your favorite CakePHP plugin but like, how do we only pick one, right? Anyway… There was a lot of participation in this giveaway! A few people even named our CakeDC Users plugin as their favorite *cue blushing face*. But in all seriousness, I thought it would be a good idea to share with you some of the plugins that were named most useful/helpful by CakeFest attendees this year….   Like I mentioned, the CakeDC users Plugin: https://github.com/CakeDC/users Queue Plugin: https://github.com/dereuromark/cakephp-queue Bake: https://github.com/cakephp/bake DataTables: https://github.com/fheider/cakephp-datatables CakePHP-tools: https://github.com/dereuromark/cakephp-tools Authentication: https://github.com/cakephp/authentication CakePHP-image: https://github.com/josbeir/cakephp-image Fixturize: https://github.com/lorenzo/cakephp-fixturize CakePHP File-Storage: https://github.com/burzum/cakephp-file-storage Crud: https://github.com/FriendsOfCake/crud IDE Helper: https://github.com/dereuromark/cakephp-ide-helper Asset-Compress: https://github.com/markstory/asset_compress CakePHP Debug Kit: https://github.com/cakephp/debug_kit Plum-Search: https://github.com/skie/plum_search CakePHP API: https://github.com/cakedc/cakephp-api/ Bootstrap UI: https://github.com/friendsofcake/bootstrap-ui Trash: https://github.com/usemuffin/trash   You can check out the full list of CakePHP Plugins at Plugins.CakePHP.org.  Have you been utilizing these tools? If not, it may be a good idea to start… while each of these serve their own purpose, using all of them can make your baking process a lot easier.    Perhaps your favorite didn’t make this list? Tell us about it… email HERE. Or, tweet us @CakeDC, @CakePHPThanks for baking!  

CakeFest 2020 recap

Taking a deep breath….. We have made it through another successful CakeFest event.    We didn’t know exactly what to expect with a fully virtual event, as it opens the door for a list of things that can (and most likely will) go wrong. Would the speakers show up? Would the internet connections keep things from running smoothly? Would attendees enjoy the information?   The answer to all of those questions is yes.    The lineup this year was amazing, and we had speakers from 6 different countries! With the ever changing way of life, our team wanted to have a diverse group of speakers, with some talking about some pretty serious subjects - like Dr. Jennifer Akullian and the mental health issues faced in the tech world. Jen allowed for questions and how-to-handle scenarios, and worked through some tough issues with attendees. Workshops from Mark Story, Jorge Gonzalez, Mark Scherer and Jose Lorenzo provided incomparable information while building projects in real time. All of the talks provided useful information that we hope all attendees will take with them as they bake in the future.    Now, does all of this bragging mean we didn’t have any issues? No. As I said in our opening, I think our group is pretty awesome and perfect, but the fact of the matter is, no one is. When bringing people together from all over the world, it is hard to test and check every connection multiple times. We had our fair share of internet lag, connection problems and audio issues. You know what we did? We worked together, fixed it, switched around the schedule and made it happen.   Virtual CakeFest 2020 was a great success, and exceeded our expectations. We were able to gather bakers from all over the world, in real time, and host a live event! I couldn’t believe how interactive the audience was, and everyone is still baking together in our #cakefest chat channel. I hope everyone is as impressed with the turn out as our team is. I know what you’re thinking… when will the recordings be released. We are working on uploading, editing and releasing the videos ASAP. While we tried to find the best universal timezone, we understand that other obligations kept some from attending, and we want to share these videos with you quickly, so know that we are working on it.    To our attendees: THANK YOU. Thank you for joining, supporting our framework and keeping CakePHP alive.   

I would like to thank all of our speakers:

  Remy Bertot  Junichi Okuyama Mark Story Jorge Gonzalez Jose Lorenzo Mark Scherer Jose Gonzalez Cal Evans Ed Barnard Jennifer Akullian Mariano Iglesias Chris Nizzardini Juan Pablo Ramirez
 

A HUGE THANK YOU TO OUR SPONSORS:

   Cake Development Corporation
  Passbolt 
  Marks Software
  RingCentral  


  Here’s to planning next year’s event to be even bigger and better!  

How to take a rest in five minutes

There are a lot of toys these days. Let me show you one very simple and powerful brick for your next revolutionary invention. Let's assume that you're either:

  • A curious person, and you like to play with things you don't know, just for the case
  • A frontend developer with no PHP coding experience, and your javascript components could use some dynamic backend json resource. Maybe you want to do this without playing with all mocking options or Node.js modules out there...and you don't want to set up MySQL database, user, grant permissions and all that stuff
  • building dynamic user interface, and your code needs to be aware of continuously changing structure of databases using unpredictable table names
  • A creator of a wireless network of IoT devices or swarm of flying educational robots. Or, looking for some stable and performant data backend running on your central Raspberry Pi Zero W with tmpfs mounts and ridiculously huge memory card, while sniffing around for bluetooth signatures
  • aware of services like ngrok and wanting to consume payloads of some IFTTT webhooks locally. Or, allowing a friend with Postman to access and/or feed up your database created (or temporarily exposed) just for that reason.
  • Having a rich html application and flirting with the idea of full blown CakePHP backend running in kiosk mode of the DraftCode application right on your iOS device
  • able to pack a PHP application as a single file Phar archive. For example: to simplify all sorts of domain logic/responsibility distribution across bazillions of machines spawned on demand and utilizing jq in your provisioning scripts
  • praying for headless access to any database that your CakePHP application is able connect to, bypassing implemented validation, callbacks, events, and even sneaking through your authentication/authorization backdoor if you want to
  • going to try following example right away, or at least very soon
If your machine meets the CakePHP Requirements, and you have composer in your $PATH then we are good to go for a CakePHP application using SQLite database accessible through REST. This would have obvious api goodies like CRUD, CORS, HATEOAS, versioning, list, describe, relations, sorting and pagination included by default.

Clock is ticking, time to rest with some book(s)

I don't know how much time of the rest limit we lost on the preface (quick learners are quick readers), but don't worry, unless you are on the slow internet connection and packagist is taking a break - we are almost done. We have a clear picture of what we're going to create, so the rest is a piece of cake.
  • create a CakePHP 4.x project named rest with CakeDC/Api plugin unlocked and loaded:
composer create-project \ --prefer-dist --no-interaction \ cakephp/app:~4.0 rest cd $_ composer config \ minimum-stability dev composer require \ cakedc/cakephp-api:~8.0
  • Unlock and load! Auth bypass, "allow all" switch (don't try this at home)
cp vendor/cakedc/cakephp-api/config/api_permissions.php.default \ ./config/api_permissions.php bin/cake plugin load CakeDC/Api
  • manually (meh, we should be resting now) configure Database.default connection in the file config/app_local.php
'database' => TMP . 'rest.sqlite', 'driver' => 'Cake\Database\Driver\Sqlite',
  • create example table books in the database and start local server
bin/cake bake migration create_books \ title:string:unique \ description:text \ price:integer:index \ available:boolean:index \ created \ modified bin/cake migrations migrate bin/cake server Open http://localhost:8765/api/books in your browser to see the (empty) list of your books, then pick some RESTful Route and take a rest from the back end, even without backend coding, scratching who knows where, etc. You maybe have some SQLite databases laying around, and that would be also worth a try. I forgot to remind you to stop that 300s timer, sorry. You will get lost in time as well, once you'll realize what all is possible with the CakeDC/Api plugin using little to no configuration, and what dimensions are opening to you. If you combine its powerful multilayer services approach with solid implementation of your custom ORM classes embraced by CakePHP core and conventions, the results are amazing. Oh, and a quick note for CakePHP 3.x developers - we like you, but please take your time to upgrade your toolset. Feel free to ask us for help, or use following warranty-limited commands: composer create-project \ --prefer-dist --no-interaction \ cakephp/app:^3.9 rest composer require \ cakedc/cakephp-api:~7.0 bin/cake plugin load -b -r CakeDC/Api

What's next

CakeFest 2020 of course. I hope you all are as excited as we are, together in these hard times. Be safe and take care, folks! And rest too, even if it's a quick one :-)

CakeFest Insider

In case we haven’t reminded you enough lately, CakeFest 2020 is less than a month away. While we have recently hosted a few virtual meetups, a fully virtual conference is uncharted territory for our team. I like to look on the bright side of things, so I will say how excited I am that bakers from all over the world will be able to join in and participate this year. Obviously, with international travel, this hasn’t always been the case for individuals. So my last CakeFest blog, I went into details of what to expect, and how the conference will (hopefully) run - smoothly. However, we’ve had a lot of emails and interest in hearing about what topics will be covered. Our lineup is excellent this year - so we wanted to share some things to look forward to:  

SPONSORS

First, we have to give a shout out to this year’s sponsors Cake Development Corporation  Passbolt Mark’s Software  RingCentral Companies that support Open Source are essential for our communities to move forward and grow!   

SCHEDULE

Day 1 will feature our popular workshops. These sessions are different than normal conference talks because they are basically training sessions to help grow your recipe book. You can see examples of previous years HERE. There will be basic workshops, as well as advanced during the full day session. We have condensed this year’s duration, so what is normally 2 days of workshops will be done in 2 hour sessions by each baker.  Mark Story, Jorge Gonzalez, and Jose Lorenzo are back. This year, we’ve also recruited another core member, Mark Scherer… you may be familiar with Mark from hosting many of our virtual meetups.  Topics that our core members MIGHT include are (these are being discussed): CakePHP 4.x, as well as project examples -  a repost builder, a headless micro cms, a media server to upload/download cache files from S3. The speaker’s will build through a project with you, answering questions as they progress.  Have an idea you’d like the workshops to include? Email us! [email protected].
  Now, day 2. This year, we decided to go ahead and try a few new things. Of course being 100% digital, condensing times, and some topics and speakers that may be unexpected. I personally invited some speakers that I thought could bring something fresh to the tech conference table.  One of these being OSMI (Open Source Mental Illness). I wanted to bring mental health importance to light, and this group is doing amazing things for the development world. Mental health doesn’t have to be a taboo subject. Dr. Jennifer Akullian will be talking about mental health, stress, and burnout in the tech industry. In addition to an overview of the research, distinctive considerations of the industry we work in will be discussed, as well as how to improve the management of common stressors in technology during an incomparable time in the world. We will also hear how some people got their start, like Michael Hoffman, and learn how to build solid architecture with CakePHP Plugins thanks to Ed Barnard. Ever wondered how to release your own plugin? Jose Gonzalez will shed some light. We are also delighted to have one of our involved Japanese community bakers, Junichi Okuyama, joining us as a speaker this year talking about helpful tips that he has learned for baking with CakePHP. Our keynote will be given by our diamond sponsor representative from Passbolt, Remy Bertot.  Other talks will include: well known podcast host Cal Evans talking about all of the cool things that can be done with PHP's built in DateTime math, Mariano Iglesias,  core members Mark Story, Chris Nizzardini and Mark Scherer. Popular contributors Juan Pablo Ramirez and Nicolas Masson will join us and share more details about CakePHP fixture factories.   You can see the full schedule HERE, and plan your attendance accordingly. 
 

SLACK CHATS 

We will also have slack chat rooms for attendees. This will give everyone the opportunity to interact with other watchers as well as speakers. Questions are welcomed before, during, and after the event. We will have team members monitoring the chat and trying to get all questions answered as soon as possible.   Slack channel tag: #cakefest  So basically, have a coffee and a chat with other attendees and presenters.    Have you purchased your ticket yet? WHAT ARE YOU WAITING FOR?    

Upgrading to CakePHP 4

As you know, CakePHP announced the version 4.x last December.I recommend that you consider upgrading your applications to the next version, to keep up to date and get all the benefits. Now, let's see how to bake!  

Step 1: Upgrade PHP

First things first, if you are not running on PHP 7.2 or higher, you will need to upgrade PHP before updating CakePHP. CakePHP 4.0 requires a minimum of PHP 7.2.  

Step 2: Upgrade Templates and Resources

There is an upgrade CLI tool for rename and moving the templates and resources:   Templates and Resources must have been moved and renamed, check the result below: * This project doesn't have Resources files   Now, let's create a new constant for Resources on /config/paths.php: Finally, update the paths on config/app.php:  

Step 3: Upgrade CakePHP

The next step is optional (and the Migration Guide included this) - run the rector command to automatically fix many deprecated method calls: The rector applied on codebase some return type declarations: https://github.com/rafaelqueiroz/cakephp-upgrade-sample/commit/d7e5c2ecc5dc28045700a270721f07098a8e189c?branch=d7e5c2ecc5dc28045700a270721f07098a8e189c&diff=split Pay attention: It is important to apply rector before you upgrade your dependencies.   Upgrade CakePHP and PHPUnit: PHPUnit can be upgraded easily. Most of the time, the --update-with-dependencies doesn’t work with me for CakePHP: The root of the issue is the packages using Caret Version Range, so let’s update debug_kit, migrations and bake using editor:   Here we go:   Now, let see how the project looks: Here, we have few deprecations and warnings. Do you remember I mentioned the rector is optional? So, the question is the rector and it's not always able to handle these issues.   I will use the PHPStan to fix this - we will install with composer: Now, we can run the phpstan analyse and fix the issues:   It's up to you how much effort you will put in with PHPStan issues. I recommend fixing everything. For this post, I did fix only what was needed to run the project after the update, you can check the fixes on this commit.   After the last fixes, the project is running well:  That’s all? No. But we upgraded CakePHP? Yes. Real applications probably use many plugins, and if these plugins don't have a version for CakePHP 4, you will need to update. Depending on the size and level of complexity of the project, the upgrade could be hard, but never impossible.    If you do not feel confident or your company would like to outsource support for this, don't hesitate to contact us at Cake Development Corporation. Our team is offering a full upgrade from CakePHP 2/3 to CakePHP 4. This will be a migration of your current application code to make it compatible with CakePHP 4 features, plugins, security settings, etc. We will be doing these migration services for a special rate - something we have never done before! Learn more about our Upgrade Services You can check the codebase of the examples on this repository. The branch upgrade has all steps by commit.  With every release CakePHP gets better, and version 4.x is no exception. There are many benefits that come with upgrading, and it makes baking a lot easier.

Using Postgres as default database- hi...

SQL language for different databases has some differences, which could cause problems after migrations between these databases. Here, we collected some hints, problems could appear during migration from MySQL to PostgreSQL. We focus on the CakePHP model layer and query generation layer.  

Tables join in where expression

Often we want to join two tables using a condition like $query->where([‘Author.id = Article.author_id’]) which works fine till we dont need field alias quotes. In the case of migration to postgres, we might want to enable autoQuotes. In this case, we can use $query->newExpr()->equalFields(‘Author.idArticle.author_id’).   

Case sensitivity in like expressions

By default mysql does case insensitive search. Switching to postgres, you can note that some functionality works differently. Hopefully you have tests, which covers your code, and this will be detected during migration. Postgres uses custom syntax for such queries named ILIKE.The case of old style conditions where method arrays straight forward,  you’d just go with ILIKE instead of LIKE. But what if we want to use ILIKE in builder methods... Here is that example:     return $query->where(         function (QueryExpression $exp) use ($field, $value): QueryExpression {             return $exp->add(new \Cake\Database\Expression\Comparison($field, $value, 'string', 'ILIKE'));         });   

Type casing

As postgres is much more strict with types, type casing is not a rare operation and may be needed. Here is an example of how to perform it using FunctionExpression$expr = (new FunctionExpression('CAST'))->setConjunction(' AS ')->add([$id, 'varchar' => 'literal']); which generates expression like :id AS varchar there :id is the placeholder for variable $id. This trick, used with literal, allows you to cast to any postgres type.  

 Quotes of tables and fields

Sometimes it is critical to inform CakePHP that the field should be quoted. One recommendation is to avoid using plain strings in case of table joins, or using IS NULL as string. So if array syntax is used, all CakePHP conventions must be followed. However,  sometimes we should help the ORM and obviously wrap a field name with IdentifiedExpression. Let's take a look back to the previous example, but now we want to type cast not value, but a field. The only solution to quote field name correctly is using this code:     $id = new IdentifierExpression($this->aliasField($field));     $expr = (new FunctionExpression('CAST'))->setConjunction(' AS ')->add([$id, 'varchar' => 'literal']);   

Building complex arithmetic expressions

In case we want to generate expressions in query fields, and we don’t want to overcomplicate logic, we could use these next tricks. Here, I have created ListExpression, which could be used as a collection of expressions. Each of these are corrected, and generates a query with correct handling of each element. See: https://gist.github.com/skie/f6e4f1a1b61e0f902a507f7907c3bbf2 So, say we want to generate expressions like this: “Events”.”time_to” - “Events”.”time_from”... With ListExpression, it can be done quite easy:  $diff = new ListExpression([new IdentifierExpression('Events.time_to'), '-', new IdentifierExpression('Events.time_from')]);   Hopefully these tricks will be as useful for your baking as they have been for mine! 

CakePHP Common Errors: Saving HasMany ...

The Cake Development Corporation team performs many code reviews. In fact, that is our starting point with every new client, as we offer free quick reviews. This is a good way to see where code stands, and how much work will need to be done to get it functioning properly.  One of the common errors we have found while doing Code Reviews of existing applications or just working with inherited code, it’s the way HasMany relations data is saved.  We have noticed that to save HasMany relations, some developers save the target relation, and then when the ID is retrieved after saving, they save one per one each item of the ‘many’ relation. There is no need to do this, as CakePHP can do all this in one single ‘save’! You won’t have any issue related to inconsistent data, because everything will be stored in one single transaction and your code will look much more clean. Let’s see a quick and easy to follow example - We will have the following relations: ‘Users’ and one User could have many ‘Addresses’.  We wish to save one user and this user will have two addresses.  First, you need to build the form in the proper way, the request data should follow the structure of your entities. The key in the form is the fieldName for the hasMany inputs. They must follow this format: {entityname}.{position}.{property}, for example: adddress.0.street_1, adddress.0.street_2, etc for the first item so store, for the second one: : adddress.1.street_1, adddress.1.street_2, and so on. More examples can be found here:  https://book.cakephp.org/4/en/views/helpers/form.html#creating-inputs-for-associated-data.
<?= $this->Form->create($user) ?> <fieldset>    <legend><?= __('Add User') ?></legend>    <?php        echo $this->Form->control('first_name');        echo $this->Form->control('last_name');        echo $this->Form->control('phone');    ?>    <legend><?= __('Address 1') ?></legend>    <?php    echo $this->Form->control('addresses.0.street_1');    echo $this->Form->control('addresses.0.street_2');    echo $this->Form->control('addresses.0.zip');    echo $this->Form->control('addresses.0.city');    echo $this->Form->control('addresses.0.state');    ?>    <legend><?= __('Address 2') ?></legend>    <?php    echo $this->Form->control('addresses.1.street_1');    echo $this->Form->control('addresses.1.street_2');    echo $this->Form->control('addresses.1.zip');    echo $this->Form->control('addresses.1.city');    echo $this->Form->control('addresses.1.state');    ?> </fieldset> <?= $this->Form->button(__('Submit')) ?> <?= $this->Form->end() ?>
Now that we have the form, we need to convert the request data. The Table class provides an easy and efficient way to convert one or many entities from request data. It’s needed to define which associations should be marshalled, using associated
public function add() {    $user = $this->Users->newEmptyEntity();    if ($this->request->is('post')) {        $user = $this->Users->patchEntity($user, $this->request->getData(), ['associated' => ['Addresses']]);        if ($this->Users->save($user)) {            $this->Flash->success(__('The user has been saved.'));              return $this->redirect(['action' => 'index']);        }        $this->Flash->error(__('The user could not be saved. Please, try again.'));    }    $this->set(compact('user')); } In this example we are saving one user and two addresses for the given user.  Associated data is validated by default, If you wish to bypass data validation, pass the validate => false option, for example: $this->Users->patchEntity($user, $this->request->getData(), ['associated' => ['Addresses' => [‘validate’ => false]]]).    We are all about working smarter and in less time, so I hope this information will be useful! Take a look here for more information: https://book.cakephp.org/4/en/orm/saving-data.html#converting-request-data-into-entities  We will be posting more Common Errors while using CakePHP.  Keep checking back!

Virtual CakeFest 2020

There we were… just 8 months ago, bright eyed and planning our annual CakeFest event for 2020. The community picked Los Angeles for a host city, and who doesn’t love LA? Our team was excited! Now, fast forward, and we are planning our virtual event. After sitting in on a few well executed virtual events this year, I was pleasantly surprised and impressed. There are still ways to keep these conferences interactive, but theres no denying that it is hard to beat the face to face communication within our CakePHP community, like we have experienced in the past.  Wondering what our (and many others) event will look like this year? Let’s see….  

Virtual

Duh. We will be hosting for attendees all over the world. This is probably the biggest pro about doing digital conferences. Attendees are able to join in, no matter where they live. With international travel, there are many things at play, schedule, finances, family, work. And it is not always an option to attend… The fact that ANYONE can tune in from ANYWHERE is so refreshing. We usually host a 4 day event, but this year we have condensed all of the fun into 2 days, to make things easier on those who don’t want to miss anything. I have had many people reach out to me saying that this will be the first CakeFest that they get to attend live (because we do always post the event after the fact or stream).  Basically, come as you are, dress comfy, and grab the coffee. You get to watch and learn from the comfort of… anywhere you want.
 

Speakers

The same thing goes for speakers - except that they will actually have to wear pants because they will be seen on camera. Our speakers will not have to worry about travel or accommodations, and can fit us in their busy schedules. We have some pretty great talks lined up this year, from building plugins, to mental health in tech, theres something that all attendees can benefit from.  As always, we will have our workshops as well, one FULL day of basic to advanced CakePHP workshops, which is the highlight of the event for most developers. The schedule is posted on our site, but there could be unexpected changes or additions moving forward.  Times are ever changing, am I right? We will allow for quick breaks throughout the events to allow potty time, refills, walking the dog etc.   

Interactive

We will have the opportunity for Q&A during talks, as well as a “convos with speakers” chat available for attendees to interact with the spealers during the event. On RingCentral, there is a fully interactive chat rolling through the presentations. The speakers are on a pretty strict time schedule, but will get to any questions they can. For this reason, we are creating chat rooms for post talk Q&A as well.  Basically you can have a chat with any available speaker for more insight on their presentations, to ask them questions, or just say hello!  This access will be sent to attendees via email before the live event. As I mentioned, our schedule is posted, and we are even taking questions ahead of the event. If there’s something you’d like to request the speaker includes, or get ahead of the question game, you can send us an email HERE.  

Giveaways

Need I say more? This year we have decided to give away some pretty cool digital prizes during the event. This may be in the form of trivia, or a game of “who can tweet us the fastest”. Either way, everyone attending will have the chance to win! If you don’t follow us on social media, you may want to start, because there MAY or may not be some pre event giveaways as well.   

Tickets

Tickets are available now. They are limited, so make sure you purchase & register ASAP. Get them here: CakeFest.orgWe hope to “see” you at CakeFest 2020! October 8-9.   

Why Use CakePHP

CakePHP  is a web development framework running on PHP. CakePHP provides tools to help build websites and web apps faster, stable and very easy to maintain. We will outline some of the interesting features of the CakePHP framework below:

Authorization

The authorization layer is in charge of determining if a user is able to access a feature or not. Authorization in CakePHP may be as complex as you want. It is powerful because you can define permissions per role, ownership, or anything else by just writing a policy.  In CakePHP 4, the Authorization layer is part of another package, which means that it can be used in a non-CakePHP app.

MVC Support

The layers in CakePHP are very explicit. Firstly, you will see that the application has specific folders for each layer (Model, Controller, Template). Secondly, you are encouraged to not access layers incorrectly, because the right way is simple enough. After using multiple frameworks out of there, I can say that CakePHP implements MVC and it implements it well.

Bake

Bake is not something new in CakePHP 4. It has been included with Cake since version 0.1.0 and even now when it is released as a plugin, it is a required tool for any developer. Bake makes generating an application, controllers, models and everything else easier... just running a command and within minutes. Other frameworks may have some tools, but in my opinion, there is nothing like bake.

Database Migration

Database migrations with CakePHP are simple, quick and safe. Those are probably the only three things you look for when versioning your database. MigrateShell can be used to generate migrations and you are able to alter database structure in any way, as well as running queries/commands. The CakePHP team is also responsible for Phinx plugin development.

Multi Language Support

This is another old feature that has been in CakePHP for years and has been recently improved in CakePHP 4. I must say that we have not found any other framework with the same set of features for internationalization and localization. You only need to use the translation function for any strings [__()] and define a way to set the language in your app. After doing that, just extract PO files using the shell and start translating your strings.

Powerful ORM

ORM in CakePHP 4 is able to do anything you can imagine. Simple and complex queries have an easy way to be executed using ORM functions. Joins, grouping, subqueries can be done in just minutes. Even after working in complex reporting for several clients, we have not found something that cannot be done through CakePHP ORM.

PHP Standards 

Going back to previous CakePHP versions (1.x and <2.x) we found that they implemented their own standard, which was good if you only worked with CakePHP... but it made integrating external libraries more difficult. In CakePHP 4, as well as 3.x, it is not a problem anymore because the wonderful CakePHP team is aware of the latest standards for the language and they are implemented inside the core... as well as the libraries released around it. It allows you to use any PHP library or package inside your Cake application.  I could go on all day about features that I like about the CakePHP framework, but there's more blogs to write in the future. I hope this gives you some incentive to use it.  

Managing A Company During A Global Pan...

A worldwide pandemic is not something a company, a manager, or a team ever plans for. This time 6 months ago we were bringing in more clients than anticipated, and planning for an international conference. Fast forward to now, just like most companies we have been hit, our conference has gone virtual, and many employees are still worried about what is to come.  Here are 5 things I have learned during these uncertain times:  

1. Don’t panic. 

Easier said than done, right? Being responsible for a team of great people and their financial, as well as professional, well being can be trying at times. I have learned it is best to stay calm, push forward and still do the best we can, even when our best isn’t always enough. Luckily, I am not a worrier by nature, and I hope that I can be a solid backbone for my team and clients, while letting them know that they (and our company) are my top priority … now more than ever.   

2. Be transparent

It is best to have sure answers and knowledge of what is expected, and to be open and honest about this with the team. If we are going to be working longer hours one week, maybe shorter the next, I want to be upfront so that no one is caught off guard. If policies or procedures are changing, they are notified immediately   Same thing goes for our clients, we have always prided ourselves on being honest and transparent about the behind the scene scenarios. It may not always be good news that’s delivered, but it will be honest. I have set goals to make my expectations clear, and reasonable.   

3. Be available:

Someone like myself, I am always going in a million directions. I have made it a point to make myself available for help, support, or whatever it is that someone may need. This goes for  clients, team members, even friends.  A pandemic like this really makes you step back and think about what is important, and things that you may not have made priorities in the past that needed to change. Our team is used to working remotely, but we communicate daily, and we always have open lines of communication (sometimes in the middle of the night as we all work in different time zones.  

4. Be Understanding

If 2020 has taught us anything, it’s to expect the unexpected. It is vital that each individual understands that not everyone is the same. We do not handle stress the same, we go through trials and tribulations differently, so it is important to be empathetic. We need to provide tools for success... and sometimes that means paid time off, new communication platforms, team building exercises, or just listening and being compassionate. I think a mistake a lot of people made early on was expecting everyone to adjust to the new way of life, with no clear direction. This resulted in a lot of confusion, and negativity, instead of learning together and changing the course of action. 
 

5. Surround yourself with a great team. 

Luckily for me, our team is fully functional without me, maybe that should scare me a little, huh? We have structure, we built up trust with each other, and everyone works towards the same goal - being successful, delivering to our clients, and growing together. While it may be my job to keep everyone moving forward and be motivating, it’s no secret that they motivate me, too. Despite working in different countries, our team has built great relationships with each other, and everyone is ready to step in and help their colleagues whenever necessary. 
 

Final thoughts

Has 2020 been different than I imagined? Absolutely. We do not know the answers to every question. We also do not know where this year may take our team, the company, or the world! One thing I do know is we will adapt, adjust and keep pushing forward. We will keep providing the best service to our clients as we always have, and we will not panic…. Not yet at least. 
 

We Bake with CakePHP