Symfony

Symfony cache: Redis vs Memcache vs APC/APCu

TLDR: Go with Redis!

REDIS VS MEMCACHE VS APCU
Redis and memcache are more or less interchangeable. Redis is considered the newer/faster option but real world performance hasn’t always reflected that sentiment. I naturally would try Redis first and see if it’s super fast, no weird issues. If Redis isn’t totally smooth, go straight to memcache. (Or for a totally hassle-free option, just go memcache first.) And then if you want to venture further, go with APCu. APCu is faster than both Redis/memcache but can be unstable or total memory-hog.
https://wpjohnny.com/redis-vs-memcache-vs-apcu-object-cache-comparisons/
Existing Symfony Bundles:

Articles:

  • Caching in Microservices – A Highly Effective way to Maximize Performance

    Below are the 4 things to consider when deciding to use the cache.

    1. What to cache.
    2. When to cache.
    3. Where to cache.
    4. How long to cache.
  • Why Redis beats Memcached for caching

    Memcached or Redis? These renowned cache engines share a number of similarities, but they also have important differences. Redis, the newer and more versatile of the two, is almost always the superior choice.

  • Memcached vs Redis, Which One to Pick?

    The performance and memory usage of Redis compared to memcached is relatively similar. Unless you already have a large investment in memcached, going forward redis is the obvious solution.Not only Redis is better option, it enables whole new types of use cases and usage patterns.

APC (Alternative PHP Cache) is opcode cache and data store and it is discontinued in favour of APCu (APC User Cache: “userland” data caching) which is only data store.
Since Zend Opcache (is only opcode caching) was included in core PHP >5.5 we can set it up altogether with Redis.. APCu is faster than both Redis/memcache but can be unstable or total memory-hog.

We have to differentiate two things:

  • The OPCode cache (formerly APC, xcache, etc…) : only serves the purpose of storing compiled version of PHP code into memory, and make it run faster – this has nothing to do with the later
  • The applicative cache : purely business stuff that Symfony will store into a raw storage in order to avoid to do some business computations too often and be faster

OPCode cache and applicative cache are really very different things, you should in order to understand ignore the word “cache” in the “OPCode cache” term, and replace it with “compiled PHP binary” which makes much more sense.

Considering the APCu (formerly APC user cache) user cache, it’s a storage for applicative cache, you can tell Symfony to use it the same way as Redis. Main problem with APCu is that it will store cache in the PHP shared memory, which means that you need to have *a lot* of dedicated RAM to the PHP processes to storeSymfony data into it. Plus, if you multiple PHP frontends, each frontend will carry its own shared memory, data in those frontends may differs: this means that you can have a cache desync between PHP frontends; That’s why we often prefer to use a Memcache, or Redis or Mongodb.
https://www.drupal.org/u/pounard

 

Redis use case:

Redis is a NoSQL key-value data store.

Pub/Sub: You can keep track of subscribers and what information they are interested in. You can use SUBSCRIBE, UNSUBSCRIBE, and PUBLISH.

Queues: You can use normal queue data structure, Redis has blocking queue commands as well.

Real time analysis of events(stats, anti spam etc) – Using Redis primitives it’s really simple to implement a real-time tracking filtering system or a spam filtering system.

Order by user votes and time: Leaderboard type functionality(Quora/Reddit/Digg), where the score is changes over time.

Transactional support: Provides transactional support. See Transactions – Redis.

Caching: Can be used as a general purpose cache. keys can strings, or more complex types (lists, sets, hashes etc). Also allows LRU eviction of items.

As a conclusion:
The microservice should include a straight forward setup for Redis: by default it contains database caching. If the dev wants to add more “areas” to cache then it is just a matter of configuring the bundle for:

  • Sessions
  • Monolog logging
  • SwiftMailer spooling
  • Profiler storage

That’s about data caching. For opcode caching we enable Opcache by default and set it up as explained by Symfony docs.

PHP_CodeSniffer: Code Beautifier and Fixer, Symfony and PhpStorm

PHP_CodeSniffer is a set of two PHP scripts; the main phpcs script that tokenizes PHP, JavaScript and CSS files to detect violations of a defined coding standard, and a second phpcbf (PHP Code Beautifier and Fixer) script to automatically correct coding standard violations. PHP_CodeSniffer is an essential development tool that ensures your code remains clean and consistent.

In this step by step tutorial I show you how I use this tools to setup my PhpStorm development environment.

Requirement

Make sure composer bin is in your $PATH directory: check your current path with echo $PATH

Install PHP_CodeSniffer

If you use Composer, you can install PHP_CodeSniffer system-wide with the following command:
composer global require "squizlabs/php_codesniffer=*"

This will install PHP_CodeSniffer and all its dependencies into the ~/.composer/vendor/ directory and, most importantly, the PHP_CodeSniffer CLI tools are installed into ~/.composer/vendor/bin/.

See if the package is installed globally: composer global show

If you didn’t do it before, simply add ~/.composer/vendor/bin/ to your PATH in your ~/.bash_profile (or ~/.bashrc) like this:

export PATH=~/.composer/vendor/bin:$PATH

Now phpcs and phpcbf are now available on your command line:

phpcs -h

phpcbf -h

To keep your tools up to date, you simply do this:

composer global update

To remove a package, you edit ~/.composer/composer.json and then run composer global update.

Install Symfony code style

As described on the instructions here: Install the coding standard also system-wide:

composer global require --dev escapestudios/symfony2-coding-standard:3.x-dev

Add Symfony code style:

~/.composer/vendor/bin/phpcbf --config-set installed_paths ~/.composer/vendor/escapestudios/symfony2-coding-standard

Check if code style installed:

~/.composer/vendor/bin/phpcbf -i

You should get something like:
The installed coding standards are PEAR, Zend, PSR2, MySource, Squiz, PSR1 and Symfony

Configure PhpStorm

Open the PhpStorm settings and go to Tools => External Tools, and add a new one with this config settings (change your username!):

Name: phpcbf single file
Description: Fix PHP Codesniffer warnings using PHP Code Beautifier and Fixer
Program: /Users/aidrissi/.composer/vendor/bin/phpcbf
Parameters: –report=full –report-file=$ProjectFileDir$/var/logs/phpcbf.log –standard=Symfony $FileDir$/$FileName$
Working directory:  $ProjectFileDir$

PhpStorm settings window: add new external tool

You can assign a keyboard shortcut for this new tool to format the current open document.

Open the settings again and navigate to: Keymap and search for phpcbf-single file and assign your preferred shortcut: In my case I use Command + Shift + B

PhpStorm run window: results of the run tool

Enjoy 🙂

Symfony: get errors from Validator & Form components

This is a nice snippet to better format symfony errors on forms and validator:

private function getErrorsFromvalidator(ConstraintViolationListInterface $errors)
{
    $formattedErrors = [];
    foreach ($errors as $error) {
        $formattedErrors[$error->getPropertyPath()] = $error->getMessage();
    }

    return $formattedErrors;
}

private function getErrorsFromForm(FormInterface $form)
{
    $errors = array();
    foreach ($form->getErrors() as $error) {
        $errors[] = $error->getMessage();
    }
    foreach ($form->all() as $childForm) {
        if ($childForm instanceof FormInterface) {
            if ($childErrors = $this->getErrorsFromForm($childForm)) {
                $errors[$childForm->getName()] = $childErrors;
            }
        }
    }

    return $errors;
}

Usage for validator errors:

/** @var \Symfony\Component\Validator\ConstraintViolationListInterface */
$errors = null;

$errors = $this->validator->validate($review);
$this->getErrorsFromvalidator($errors)

Usage for form errors:
$this->getErrorsFromForm($form)