Using preInsert event for generating UUID with laminas-db
If you want to do something before insert data into database table, for example: generate id as UUID binary, you can do with preInsert
event. For example, you have the following album
table structure:
DROP TABLE IF EXISTS `album`; CREATE TABLE `album` ( `id` binary(16) NOT NULL COMMENT 'uuid binary', `artist` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; ALTER TABLE `album` ADD PRIMARY KEY (`id`);
Now, to generate the UUID data, you can use ramsey/uuid
, you can require:
➜ composer require ramsey/uuid
Now, time for the action!
Note, this is just a quick example to show you how it works. You can borrow your design architecture you love in real implementation.
For example, in laminas-mvc-skeleton application, we inject the IndexController with db adapter via factory:
namespace Application\Controller; use Laminas\Db\Adapter\AdapterInterface; class IndexControllerFactory { public function __invoke($c) { return new IndexController($c->get(AdapterInterface::class)); } }
Now, we can update the module/Application/config/module.config.php
controller factory:
// ... 'controllers' => [ 'factories' => [ Controller\IndexController::class => Controller\IndexControllerFactory::class, ], ], // ...
In our IndexController __construct, we can use the db adapter to create the TableGateway instance featuring EventFeature:
<?php declare(strict_types=1); namespace Application\Controller; use Laminas\Db\Adapter\AdapterInterface; use Laminas\Db\TableGateway\Feature\EventFeature; use Laminas\Db\TableGateway\Feature\EventFeature\TableGatewayEvent; use Laminas\Db\TableGateway\Feature\EventFeatureEventsInterface; use Laminas\Db\TableGateway\TableGateway; use Laminas\Mvc\Controller\AbstractActionController; use Laminas\View\Model\ViewModel; use Ramsey\Uuid\Uuid; class IndexController extends AbstractActionController { private $albumTableGateway; public function __construct(AdapterInterface $adapter) { $events = $this->getEventManager(); $events->attach(EventFeatureEventsInterface::EVENT_PRE_INSERT, function (TableGatewayEvent $event) { $insert = $event->getParam('insert'); $insert->id = Uuid::uuid4()->getBytes(); }); $this->albumTableGateway = new TableGateway('album', $adapter, new EventFeature($events)); } }
Above, with EventFeatureEventsInterface::EVENT_PRE_INSERT
, we update the insert id with the binary value generated.
Let’s check with index action for insert:
// ... public function indexAction() { $this->albumTableGateway->insert([ 'artist' => 'Sheila on 7', 'title' => 'Pejantan Tangguh', ]); return new ViewModel(); } // ..
Ok, when open the index page, we will have the album table inserted with id generated in preInsert event.
mysql> SELECT LOWER( -> CONCAT(SUBSTR(HEX(id), 1, 8) -> , '-' -> , SUBSTR(HEX(id), 9, 4) -> , '-' -> , SUBSTR(HEX(id), 13, 4) -> , '-' -> , SUBSTR(HEX(id), 17, 4) -> , '-' -> , SUBSTR(HEX(id), 21)) -> ) as id, -> artist, -> title -> FROM album; +--------------------------------------+-------------+------------------+ | id | artist | title | +--------------------------------------+-------------+------------------+ | 551a8518-cdd2-4f3a-968d-a45a4b232b5e | Sheila on 7 | Pejantan Tangguh | +--------------------------------------+-------------+------------------+ 1 row in set (0.00 sec)
For complete event list, you can read the documentation https://docs.laminas.dev/laminas-db/table-gateway/#tablegateway-lifecycle-events
Using laminas-cli to Consume Symfony Console Command in Mezzio Application
So, you want to use Symfony Console Command in Mezzio Application? You can! There is laminas-cli
for that. While it still in development, you already can give it a try. First, I assume that you already installed the mezzio application. Next, you can set minimum-stability and prefer-stable config in your composer.json:
➜ composer config minimum-stability dev ➜ composer config prefer-stable true
By above command, you can ensure that you can install the non-stable dependency, while prefer stable version if found. Next, you can require the laminas-cli via command:
➜ composer require laminas/laminas-cli
After installed, let’s create our first command: “HelloWorld command”, like the following:
namespace App\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use function sprintf; final class HelloWorld extends Command { protected function configure() { $this ->addArgument('message', InputArgument::REQUIRED, 'Greeting Message'); } protected function execute(InputInterface $input, OutputInterface $output) { $message = $input->getArgument('message'); $output->writeln(sprintf('<info>Hello to world: %s<info>! ', $message)); return 0; } }
Greet! Now, time to register it to our App\ConfigProvider
class:
<?php declare(strict_types=1); namespace App; class ConfigProvider { public function __invoke(): array { return [ // ... 'laminas-cli' => $this->getCliConfig(), // ... ]; } public function getCliConfig(): array { return [ 'commands' => [ // ... 'app:hello-world' => Command\HelloWorld::class, // ... ], ]; } public function getDependencies(): array { return [ 'invokables' => [ // ... Command\HelloWorld::class => Command\HelloWorld::class, // ... ], ]; } // ... }
First, in getDependencies()
, we register the command, if the command has dependency, you need to provide factory for it. And then, in __invoke()
method, we register the commands, which you can move the commands definition in separate method. That’s it! Now, you can run the command:
➜ vendor/bin/laminas app:hello-world "Good Morning" Hello to world: Good Morning!
Using Swoole in Mezzio application with Sdebug
If you didn’t try Swoole
, you need to try it. It is a PECL extension for developing asynchronous applications in PHP. If you build a Mezzio Application, there is already mezzio-swoole
component that ease for its settings and usage.
First, if you didn’t have a mezzio skeleton, you can install the skeleton:
➜ composer create-project mezzio/mezzio-skeleton
Next, install the swoole
extension:
➜ sudo pecl install swoole
After it, you can install the mezzio-swoole
component:
➜ composer require mezzio/mezzio-swoole
That’s it, you can now open mezzio-skeleton
directory and run the mezzio-swoole
command, and we will get the following output:
➜ cd mezzio-skeleton ➜ ./vendor/bin/mezzio-swoole start Swoole is running at 127.0.0.1:8080, in /Users/samsonasik/www/mezzio-skeleton PHP Warning: Swoole\Server::start(): Using Xdebug in coroutines is extremely dangerous, please notice that it may lead to coredump! in /Users/samsonasik/www/mezzio-skeleton/vendor/mezzio/mezzio-swoole/src/SwooleRequestHandlerRunner.php on line 169
If you have Xdebug
installed, you will get above command output “PHP Warning” output. To fix it, we can uninstall the Xdebug
, and install Sdebug
instead. We can do the following command:
➜ sudo pecl uninstall xdebug ➜ git clone https://github.com/swoole/sdebug.git ➜ cd sdebug && sudo ./rebuild.sh
Now, you will get the Sdebug
information if we run php -v
:
➜ ~ php -v PHP 7.4.4 (cli) (built: Mar 24 2020 10:45:52) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Sdebug v2.9.3-dev, Copyright (c) 2002-2020, by Derick Rethans with Zend OPcache v7.4.4, Copyright (c), by Zend Technologies
Let’s try run mezzio-swoole
command again:
➜ cd mezzio-skeleton ➜ ./vendor/bin/mezzio-swoole start Swoole is running at 127.0.0.1:8080, in /Users/samsonasik/www/mezzio-skeleton Worker started in /Users/samsonasik/www/mezzio-skeleton with ID 0
If you got Segmentation fault in the future, that may because of the `Sdebug`, if you don’t require the ‘Xdebug’/’Sdebug’ feature. You can just uninstall them all together
Succeed! Now, time to benchmark! I used wrk for it. I tested it in Macbook Pro 2011, core i5, with 16GB RAM. I access the page with HTML+JS+CSS in there.
1. Without Swoole
Let’s CUT the previous mezzio-swoole
( type CTRL + C ) command and use PHP Development server:
➜ cd mezzio-skeleton ➜ composer serve > php -S 0.0.0.0:8080 -t public/ [Sun Apr 5 12:24:15 2020] PHP 7.4.4 Development Server (http://0.0.0.0:8080) started
Now, we can run the benchmark with run wrk
command in separate terminal:
➜ wrk -c 1000 -t 10 http://localhost:8080/ Running 10s test @ http://localhost:8080/ 10 threads and 1000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 1.33s 629.53ms 2.00s 50.33% Req/Sec 16.09 12.96 60.00 69.26% 544 requests in 10.09s, 4.25MB read Socket errors: connect 759, read 580, write 1, timeout 393 Requests/sec: 53.90 Transfer/sec: 430.92KB
2. With Swoole
Let’s CUT the previous PHP Development server command ( type CTRL + C ) command and use mezzio-swoole
command:
➜ cd mezzio-skeleton ➜ ./vendor/bin/mezzio-swoole start Swoole is running at 127.0.0.1:8080, in /Users/samsonasik/www/mezzio-skeleton Worker started in /Users/samsonasik/www/mezzio-skeleton with ID 0
Now, we can run the benchmark with run wrk
command in separate terminal:
➜ wrk -c 1000 -t 10 http://localhost:8080/ Running 10s test @ http://localhost:8080/ 10 threads and 1000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 1.15s 590.35ms 2.00s 54.14% Req/Sec 30.13 35.31 170.00 83.03% 1373 requests in 10.09s, 25.10MB read Socket errors: connect 759, read 80, write 0, timeout 418 Requests/sec: 136.07 Transfer/sec: 2.49MB
Above, we get double total requests with swoole in same time! That’s it!
References:
5 comments