Browse Source

[imi] Update imi 2.0 (#6866)

* Update imi 2.0

* optimize

* optimize

* update php 8.1

* Fix

* Fix
Yurun 3 years ago
parent
commit
8dd61b75eb
33 changed files with 960 additions and 496 deletions
  1. 1 0
      frameworks/PHP/imi/.env
  2. 0 2
      frameworks/PHP/imi/.env-with-redis
  3. 39 108
      frameworks/PHP/imi/ApiServer/Controller/IndexController.php
  4. 208 0
      frameworks/PHP/imi/ApiServer/Controller/PgController.php
  5. 0 13
      frameworks/PHP/imi/ApiServer/Main.php
  6. 1 11
      frameworks/PHP/imi/ApiServer/config/config.php
  7. 13 23
      frameworks/PHP/imi/Listener/AppInit.php
  8. 24 0
      frameworks/PHP/imi/Listener/WorkermanRequest.php
  9. 28 0
      frameworks/PHP/imi/Listener/WorkermanWorkerStart.php
  10. 8 2
      frameworks/PHP/imi/Main.php
  11. 25 21
      frameworks/PHP/imi/Model/Base/FortuneBase.php
  12. 25 21
      frameworks/PHP/imi/Model/Base/WorldBase.php
  13. 3 1
      frameworks/PHP/imi/Model/Fortune.php
  14. 76 0
      frameworks/PHP/imi/Model/PgSql/Base/FortuneBase.php
  15. 76 0
      frameworks/PHP/imi/Model/PgSql/Base/WorldBase.php
  16. 16 0
      frameworks/PHP/imi/Model/PgSql/Fortune.php
  17. 16 0
      frameworks/PHP/imi/Model/PgSql/World.php
  18. 3 1
      frameworks/PHP/imi/Model/World.php
  19. 0 137
      frameworks/PHP/imi/README.md
  20. 128 11
      frameworks/PHP/imi/benchmark_config.json
  21. 6 5
      frameworks/PHP/imi/composer.json
  22. 93 6
      frameworks/PHP/imi/config.toml
  23. 0 2
      frameworks/PHP/imi/config/beans.php
  24. 84 57
      frameworks/PHP/imi/config/config.php
  25. 0 28
      frameworks/PHP/imi/imi-query-builder.dockerfile
  26. 37 0
      frameworks/PHP/imi/imi-swoole-pgsql.dockerfile
  27. 13 10
      frameworks/PHP/imi/imi-swoole.dockerfile
  28. 30 0
      frameworks/PHP/imi/imi-workerman.dockerfile
  29. 0 34
      frameworks/PHP/imi/imi.dockerfile
  30. 3 0
      frameworks/PHP/imi/php.ini
  31. 2 0
      frameworks/PHP/imi/run-swoole.sh
  32. 0 3
      frameworks/PHP/imi/run-with-redis.sh
  33. 2 0
      frameworks/PHP/imi/run-workerman.sh

+ 1 - 0
frameworks/PHP/imi/.env

@@ -0,0 +1 @@
+WITH_REDIS=1

+ 0 - 2
frameworks/PHP/imi/.env-with-redis

@@ -1,2 +0,0 @@
[email protected]=16
-WITH_REDIS=1

+ 39 - 108
frameworks/PHP/imi/ApiServer/Controller/IndexController.php

@@ -1,17 +1,20 @@
 <?php
 namespace ImiApp\ApiServer\Controller;
 
+use Imi\App;
 use Imi\Db\Db;
 use Imi\RequestContext;
 use ImiApp\Model\World;
 use ImiApp\Model\Fortune;
+use Imi\Db\Interfaces\IDb;
 use Imi\Redis\RedisManager;
 use Imi\Util\Stream\MemoryStream;
-use Imi\Controller\HttpController;
 use Imi\Server\View\Annotation\View;
-use Imi\Server\Route\Annotation\Route;
-use Imi\Server\Route\Annotation\Action;
-use Imi\Server\Route\Annotation\Controller;
+use Imi\Server\Http\Route\Annotation\Route;
+use Imi\Server\Http\Route\Annotation\Action;
+use Imi\Server\Http\Controller\HttpController;
+use Imi\Server\Http\Route\Annotation\Controller;
+use Imi\Server\Http\Message\Contract\IHttpResponse;
 
 /**
  * @Controller("/")
@@ -20,51 +23,36 @@ class IndexController extends HttpController
 {
     /**
      * @Action
-     *
-     * @return void
      */
-    public function json()
+    public function json(): array
     {
         return ['message' => 'Hello, World!'];
     }
 
     /**
      * @Action
-     * @View(renderType="html")
-     *
-     * @return void
      */
-    public function plaintext()
+    public function plaintext(): IHttpResponse
     {
-        return RequestContext::get('response')->withHeader('Content-Type', 'text/plain; charset=utf-8')->write('Hello, World!');
+        $response = $this->response;
+        $response->setHeader('Content-Type', 'text/plain; charset=utf-8')
+                 ->getBody()
+                 ->write('Hello, World!');
+        return $response;
     }
 
     /**
      * @Action
-     *
-     * @return void
      */
-    public function dbModel()
+    public function dbModel(): ?World
     {
         return World::find(\mt_rand(1, 10000));
     }
 
     /**
      * @Action
-     *
-     * @return void
-     */
-    public function dbQueryBuilder()
-    {
-        return Db::query()->from('World')->field('id', 'randomNumber')->where('id', '=', \mt_rand(1, 10000))->limit(1)->select()->get();
-    }
-
-    /**
-     * @Action
-     *
-     * @return void
      */
-    public function dbRaw()
+    public function dbRaw(): array
     {
         $db = Db::getInstance();
         $stmt = $db->prepare('SELECT id, randomNumber FROM World WHERE id = ? LIMIT 1');
@@ -74,10 +62,8 @@ class IndexController extends HttpController
 
     /**
      * @Action
-     *
-     * @return void
      */
-    public function queryModel($queries)
+    public function queryModel($queries): array
     {
         $queries = (int)$queries;
         if($queries > 1)
@@ -101,31 +87,7 @@ class IndexController extends HttpController
      *
      * @return void
      */
-    public function queryQueryBuilder($queries)
-    {
-        $queries = (int)$queries;
-        if($queries > 1)
-        {
-            $queryCount = \min($queries, 500);
-        }
-        else
-        {
-            $queryCount = 1;
-        }
-        $list = [];
-        while ($queryCount--)
-        {
-            $list[] = Db::query()->from('World')->field('id', 'randomNumber')->where('id', '=', \mt_rand(1, 10000))->limit(1)->select()->get();
-        }
-        return $list;
-    }
-
-    /**
-     * @Action
-     *
-     * @return void
-     */
-    public function queryRaw($queries)
+    public function queryRaw($queries): array
     {
         $queries = (int)$queries;
         if($queries > 1)
@@ -150,14 +112,10 @@ class IndexController extends HttpController
     /**
      * @Action
      * @View(renderType="html")
-     *
-     * @return void
      */
-    public function fortunes()
+    public function fortunes(): array
     {
-        RequestContext::use(function(&$context){
-            $context['response'] = $context['response']->withHeader('Content-Type', 'text/html; charset=UTF-8');
-        });
+        $this->response->setHeader('Content-Type', 'text/html; charset=UTF-8');
         $list = Fortune::select();
         $rows = [];
         foreach($list as $item)
@@ -177,7 +135,7 @@ class IndexController extends HttpController
      *
      * @return void
      */
-    public function fortunesRaw()
+    public function fortunesRaw(): IHttpResponse
     {
         $rows = [];
         foreach(Db::getInstance()->query('SELECT id, message FROM Fortune')->fetchAll() as $item)
@@ -194,16 +152,14 @@ class IndexController extends HttpController
             $html .= "<tr><td>{$id}</td><td>{$message}</td></tr>";
         }
 
-        return RequestContext::get('response')->withHeader('Content-Type', 'text/html; charset=UTF-8')
-                                              ->withBody(new MemoryStream("<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>{$html}</table></body></html>"));
+        return $this->response->setHeader('Content-Type', 'text/html; charset=UTF-8')
+                              ->setBody(new MemoryStream("<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>{$html}</table></body></html>"));
     }
 
     /**
      * @Action
-     *
-     * @return void
      */
-    public function updateModel($queries)
+    public function updateModel($queries): array
     {
         $queries = (int)$queries;
         if($queries > 1)
@@ -226,40 +182,8 @@ class IndexController extends HttpController
 
     /**
      * @Action
-     *
-     * @return void
      */
-    public function updateQueryBuilder($queries)
-    {
-        $queries = (int)$queries;
-        if($queries > 1)
-        {
-            $queryCount = \min($queries, 500);
-        }
-        else
-        {
-            $queryCount = 1;
-        }
-        $list = [];
-        while ($queryCount--)
-        {
-            $id = \mt_rand(1, 10000);
-            $row = Db::query()->from('World')->field('id', 'randomNumber')->where('id', '=', $id)->limit(1)->select()->get();
-            $row['randomNumber'] = $randomNumber = \mt_rand(1, 10000);
-            Db::query()->from('World')->where('id', '=', $id)->limit(1)->update([
-                'randomNumber'  =>  $randomNumber,
-            ]);
-            $list[] = $row;
-        }
-        return $list;
-    }
-
-    /**
-     * @Action
-     *
-     * @return void
-     */
-    public function updateRaw($queries)
+    public function updateRaw($queries): array
     {
         $queries = (int)$queries;
         if($queries > 1)
@@ -283,16 +207,15 @@ class IndexController extends HttpController
             $stmtUpdate->execute([$randomNumber, $id]);
             $list[] = $row;
         }
+
         return $list;
     }
 
     /**
      * @Action
      * @Route("cached-worlds")
-     *
-     * @return void
      */
-    public function cachedWorlds($count)
+    public function cachedWorlds($count): array
     {
         $count = (int)$count;
         if($count > 1)
@@ -303,12 +226,20 @@ class IndexController extends HttpController
         {
             $queryCount = 1;
         }
-        $ids = [];
-        while ($queryCount--)
+
+        $list = App::get('worlds');
+        $result = [];
+        $keys = \array_rand($list, $queryCount);
+        foreach ((array) $keys as $key)
         {
-            $ids[] = 'world:' . \mt_rand(1, 10000);
+            if (!isset($list[$key]))
+            {
+                break;
+            }
+            $result[] = $list[$key];
         }
-        return RedisManager::getInstance()->mget($ids);
+
+        return $result;
     }
 
 }

+ 208 - 0
frameworks/PHP/imi/ApiServer/Controller/PgController.php

@@ -0,0 +1,208 @@
+<?php
+namespace ImiApp\ApiServer\Controller;
+
+use Imi\Db\Db;
+use Imi\Db\Interfaces\IDb;
+use Imi\RequestContext;
+use Imi\Redis\RedisManager;
+use ImiApp\Model\PgSql\World;
+use ImiApp\Model\PgSql\Fortune;
+use Imi\Util\Stream\MemoryStream;
+use Imi\Server\View\Annotation\View;
+use Imi\Server\View\Annotation\HtmlView;
+use Imi\Server\Http\Route\Annotation\Route;
+use Imi\Server\Http\Route\Annotation\Action;
+use Imi\Server\Http\Controller\HttpController;
+use Imi\Server\Http\Route\Annotation\Controller;
+use Imi\Server\Http\Message\Contract\IHttpResponse;
+
+/**
+ * @Controller("/")
+ */
+class PgController extends HttpController
+{
+    const POOL_NAME = 'pgsql';
+
+    /**
+     * @Action
+     */
+    public function pgDbModel(): ?World
+    {
+        return World::find(\mt_rand(1, 10000));
+    }
+
+    /**
+     * @Action
+     */
+    public function pgDbRaw(): array
+    {
+        $db = Db::getInstance(self::POOL_NAME);
+        $stmt = $db->prepare('SELECT id, randomnumber FROM World WHERE id = ? LIMIT 1');
+        $stmt->execute([\mt_rand(1, 10000)]);
+        return $stmt->fetch();
+    }
+
+    /**
+     * @Action
+     */
+    public function pgQueryModel($queries): array
+    {
+        $queries = (int)$queries;
+        if($queries > 1)
+        {
+            $queryCount = \min($queries, 500);
+        }
+        else
+        {
+            $queryCount = 1;
+        }
+        $list = [];
+        while ($queryCount--)
+        {
+            $list[] = World::find(\mt_rand(1, 10000));
+        }
+        return $list;
+    }
+
+    /**
+     * @Action
+     *
+     * @return void
+     */
+    public function pgQueryRaw($queries): array
+    {
+        $queries = (int)$queries;
+        if($queries > 1)
+        {
+            $queryCount = \min($queries, 500);
+        }
+        else
+        {
+            $queryCount = 1;
+        }
+        $list = [];
+        $db = Db::getInstance(self::POOL_NAME);
+        $stmt = $db->prepare('SELECT id, randomnumber FROM World WHERE id = ? LIMIT 1');
+        while ($queryCount--)
+        {
+            $stmt->execute([\mt_rand(1, 10000)]);
+            $list[] = $stmt->fetch();
+        }
+        return $list;
+    }
+
+    /**
+     * @Action
+     * @View(renderType="html")
+     * @HtmlView("fortunes")
+     */
+    public function pgFortunes(): array
+    {
+        $this->response->setHeader('Content-Type', 'text/html; charset=UTF-8');
+        $list = Fortune::select();
+        $rows = [];
+        foreach($list as $item)
+        {
+            $rows[$item->id] = $item->message;
+        }
+        $rows[0] = 'Additional fortune added at request time.';
+        \asort($rows);
+        return [
+            'rows'  =>  $rows,
+        ];
+    }
+
+    /**
+     * @Action
+     * @View(renderType="html")
+     *
+     * @return void
+     */
+    public function pgFortunesRaw(): IHttpResponse
+    {
+        $rows = [];
+        foreach(Db::getInstance(self::POOL_NAME)->query('SELECT id, message FROM Fortune')->fetchAll() as $item)
+        {
+            $rows[$item['id']] = $item['message'];
+        }
+        $rows[0] = 'Additional fortune added at request time.';
+        \asort($rows);
+
+        $html = '';
+        foreach ($rows as $id => $message)
+        {
+            $message = \htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
+            $html .= "<tr><td>{$id}</td><td>{$message}</td></tr>";
+        }
+
+        return $this->response->setHeader('Content-Type', 'text/html; charset=UTF-8')
+                              ->setBody(new MemoryStream("<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>{$html}</table></body></html>"));
+    }
+
+    /**
+     * @Action
+     */
+    public function pgUpdateModel($queries): array
+    {
+        $queries = (int)$queries;
+        if($queries > 1)
+        {
+            $queryCount = \min($queries, 500);
+        }
+        else
+        {
+            $queryCount = 1;
+        }
+        $list = [];
+        while ($queryCount--)
+        {
+            $list[] = $row = World::find(\mt_rand(1, 10000));
+            $row->randomNumber = \mt_rand(1, 10000);
+            $row->update();
+        }
+        return $list;
+    }
+
+    /**
+     * @Action
+     */
+    public function pgUpdateRaw($queries): array
+    {
+        $queries = (int)$queries;
+        if($queries > 1)
+        {
+            $queryCount = \min($queries, 500);
+        }
+        else
+        {
+            $queryCount = 1;
+        }
+        $db = Db::getInstance(self::POOL_NAME);
+        $stmtSelect = $db->prepare('SELECT id, randomnumber FROM World WHERE id = ? LIMIT 1');
+        $stmtUpdate = $db->prepare('UPDATE World SET randomNumber = CASE id' . \str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $queryCount) . 'END WHERE id IN (' . \str_repeat('?::INTEGER,', $queryCount - 1) . '?::INTEGER)');
+        $list = [];
+        $keys = $values = [];
+        while ($queryCount--)
+        {
+            $values[] = $keys[] = $id = \mt_rand(1, 10000);
+            $stmtSelect->execute([$id]);
+            $row = $stmtSelect->fetch();
+
+            $values[] = $row['randomNumber'] = \mt_rand(1, 10000);
+            $list[] = $row;
+        }
+        $db->beginTransaction();
+        try {
+            $stmtUpdate->execute([
+                ...$values,
+                ...$keys
+            ]);
+            $db->commit();
+        } catch(\Throwable $th) {
+            $db->rollBack();
+            throw $th;
+        }
+
+        return $list;
+    }
+}

+ 0 - 13
frameworks/PHP/imi/ApiServer/Main.php

@@ -1,13 +0,0 @@
-<?php
-namespace ImiApp\ApiServer;
-
-use Imi\Main\BaseMain;
-
-class Main extends BaseMain
-{
-    public function __init()
-    {
-        // 可以做一些初始化操作
-    }
-
-}

+ 1 - 11
frameworks/PHP/imi/ApiServer/config/config.php

@@ -2,16 +2,9 @@
 return [
     'configs'    =>    [
     ],
-    // bean扫描目录
-    'beanScan'    =>    [
-        'ImiApp\ApiServer\Controller',
-        'ImiApp\Model',
-    ],
     'beans'    =>    [
         'HttpDispatcher'    =>    [
-            'middlewares'    =>    [
-                \Imi\Server\Http\Middleware\RouteMiddleware::class,
-            ],
+            'middleware' => false,
         ],
         'HtmlView'    =>    [
             'templatePath'    =>    dirname(__DIR__) . '/template/',
@@ -23,7 +16,4 @@ return [
             ],
         ]
     ],
-    'controller'    =>  [
-        'singleton' => true,
-    ],
 ];

+ 13 - 23
frameworks/PHP/imi/Listener/AppInit.php

@@ -1,39 +1,29 @@
 <?php
+
+declare(strict_types=1);
+
 namespace ImiApp\Listener;
 
+use Imi\App;
 use Imi\Db\Db;
+use Imi\Timer\Timer;
 use Imi\Event\EventParam;
-use Imi\Redis\RedisManager;
+use Imi\Queue\Model\Message;
 use Imi\Event\IEventListener;
+use Imi\Aop\Annotation\Inject;
 use Imi\Bean\Annotation\Listener;
 
 /**
- * @Listener("IMI.APP.INIT")
+ * @Listener("IMI.MAIN_SERVER.WORKER.START.APP")
+ * @Listener("IMI.WORKERMAN.SERVER.WORKER_START")
  */
 class AppInit implements IEventListener
 {
     /**
-     * 事件处理方法
-     * @param EventParam $e
-     * @return void
+     * 事件处理方法.
      */
-    public function handle(EventParam $e)
+    public function handle(EventParam $e): void
     {
-        if(getenv('WITH_REDIS') ?? false)
-        {
-            $redis = RedisManager::getInstance();
-            $page = 1;
-            while($list = Db::query()->from('world')->page($page, 1000)->select()->getArray())
-            {
-                $redisList = [];
-                foreach($list as $row)
-                {
-                    $redisList['world:' . $row['id']] = $row;
-                }
-                $redis->mset($redisList);
-                ++$page;
-            }
-        }
+        App::set('worlds', Db::query()->from('world')->select()->getArray());
     }
-
-}
+}

+ 24 - 0
frameworks/PHP/imi/Listener/WorkermanRequest.php

@@ -0,0 +1,24 @@
+<?php
+namespace ImiApp\Listener;
+
+use Imi\App;
+use Imi\Db\Db;
+use Imi\Timer\Timer;
+use Imi\Event\EventParam;
+use Imi\Redis\RedisManager;
+use Imi\Event\IEventListener;
+use Imi\Bean\Annotation\Listener;
+
+/**
+ * @Listener(eventName="IMI.WORKERMAN.SERVER.HTTP.REQUEST", priority=20000000)
+ */
+class WorkermanRequest implements IEventListener
+{
+    /**
+     * 事件处理方法.
+     */
+    public function handle(EventParam $e): void
+    {
+        $e->getData()['response']->setHeader('Date', App::get('test_date'));
+    }
+}

+ 28 - 0
frameworks/PHP/imi/Listener/WorkermanWorkerStart.php

@@ -0,0 +1,28 @@
+<?php
+namespace ImiApp\Listener;
+
+use Imi\App;
+use Imi\Db\Db;
+use Imi\Timer\Timer;
+use Imi\Event\EventParam;
+use Imi\Redis\RedisManager;
+use Imi\Event\IEventListener;
+use Imi\Bean\Annotation\Listener;
+
+/**
+ * @Listener("IMI.WORKERMAN.SERVER.WORKER_START")
+ */
+class WorkermanWorkerStart implements IEventListener
+{
+    /**
+     * 事件处理方法.
+     */
+    public function handle(EventParam $e): void
+    {
+        App::set('test_date', gmdate('D, d M Y H:i:s').' GMT');
+        Timer::tick(1000, function() {
+            App::set('test_date', gmdate('D, d M Y H:i:s').' GMT');
+        });
+    }
+
+}

+ 8 - 2
frameworks/PHP/imi/Main.php

@@ -6,11 +6,17 @@ use Imi\Main\AppBaseMain;
 
 class Main extends AppBaseMain
 {
-    public function __init()
+    public function __init(): void
     {
         // 这里可以做一些初始化操作,如果需要的话
         ini_set('memory_limit', -1);
-        App::setDebug(true);
+        App::setDebug(false);
+        if(extension_loaded('swoole'))
+        {
+            \Co::set([
+                'socket_connect_timeout' => 5,
+            ]);
+        }
     }
 
 }

+ 25 - 21
frameworks/PHP/imi/Model/Base/FortuneBase.php

@@ -1,73 +1,77 @@
 <?php
+declare(strict_types=1);
+
 namespace ImiApp\Model\Base;
 
-use Imi\Model\Model;
+use Imi\Model\Model as Model;
+use Imi\Model\Annotation\DDL;
 use Imi\Model\Annotation\Table;
 use Imi\Model\Annotation\Column;
 use Imi\Model\Annotation\Entity;
 
 /**
- * FortuneBase
- * @Entity
+ * fortune 基类
+ * @Entity(bean=false)
  * @Table(name="fortune", id={"id"})
- * @property int $id 
- * @property string $message 
+ * @DDL(sql="CREATE TABLE `fortune` (   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,   `message` varchar(2048) CHARACTER SET utf8 NOT NULL,   PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", decode="")
+ * @property int|null $id 
+ * @property string|null $message 
  */
 abstract class FortuneBase extends Model
 {
     /**
      * id
      * @Column(name="id", type="int", length=10, accuracy=0, nullable=false, default="", isPrimaryKey=true, primaryKeyIndex=0, isAutoIncrement=true)
-     * @var int
+     * @var int|null
      */
-    protected $id;
+    protected ?int $id = null;
 
     /**
      * 获取 id
      *
-     * @return int
-     */ 
-    public function getId()
+     * @return int|null
+     */
+    public function getId(): ?int
     {
         return $this->id;
     }
 
     /**
      * 赋值 id
-     * @param int $id id
+     * @param int|null $id id
      * @return static
-     */ 
+     */
     public function setId($id)
     {
-        $this->id = $id;
+        $this->id = null === $id ? null : (int)$id;
         return $this;
     }
 
     /**
      * message
      * @Column(name="message", type="varchar", length=2048, accuracy=0, nullable=false, default="", isPrimaryKey=false, primaryKeyIndex=-1, isAutoIncrement=false)
-     * @var string
+     * @var string|null
      */
-    protected $message;
+    protected ?string $message = null;
 
     /**
      * 获取 message
      *
-     * @return string
-     */ 
-    public function getMessage()
+     * @return string|null
+     */
+    public function getMessage(): ?string
     {
         return $this->message;
     }
 
     /**
      * 赋值 message
-     * @param string $message message
+     * @param string|null $message message
      * @return static
-     */ 
+     */
     public function setMessage($message)
     {
-        $this->message = $message;
+        $this->message = null === $message ? null : (string)$message;
         return $this;
     }
 

+ 25 - 21
frameworks/PHP/imi/Model/Base/WorldBase.php

@@ -1,73 +1,77 @@
 <?php
+declare(strict_types=1);
+
 namespace ImiApp\Model\Base;
 
-use Imi\Model\Model;
+use Imi\Model\Model as Model;
+use Imi\Model\Annotation\DDL;
 use Imi\Model\Annotation\Table;
 use Imi\Model\Annotation\Column;
 use Imi\Model\Annotation\Entity;
 
 /**
- * WorldBase
- * @Entity
+ * world 基类
+ * @Entity(bean=false)
  * @Table(name="world", id={"id"})
- * @property int $id 
- * @property int $randomNumber 
+ * @DDL(sql="CREATE TABLE `world` (   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,   `randomNumber` int(11) NOT NULL DEFAULT '0',   PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", decode="")
+ * @property int|null $id 
+ * @property int|null $randomNumber 
  */
 abstract class WorldBase extends Model
 {
     /**
      * id
      * @Column(name="id", type="int", length=10, accuracy=0, nullable=false, default="", isPrimaryKey=true, primaryKeyIndex=0, isAutoIncrement=true)
-     * @var int
+     * @var int|null
      */
-    protected $id;
+    protected ?int $id = null;
 
     /**
      * 获取 id
      *
-     * @return int
-     */ 
-    public function getId()
+     * @return int|null
+     */
+    public function getId(): ?int
     {
         return $this->id;
     }
 
     /**
      * 赋值 id
-     * @param int $id id
+     * @param int|null $id id
      * @return static
-     */ 
+     */
     public function setId($id)
     {
-        $this->id = $id;
+        $this->id = null === $id ? null : (int)$id;
         return $this;
     }
 
     /**
      * randomNumber
      * @Column(name="randomNumber", type="int", length=11, accuracy=0, nullable=false, default="0", isPrimaryKey=false, primaryKeyIndex=-1, isAutoIncrement=false)
-     * @var int
+     * @var int|null
      */
-    protected $randomNumber;
+    protected ?int $randomNumber = null;
 
     /**
      * 获取 randomNumber
      *
-     * @return int
-     */ 
-    public function getRandomNumber()
+     * @return int|null
+     */
+    public function getRandomNumber(): ?int
     {
         return $this->randomNumber;
     }
 
     /**
      * 赋值 randomNumber
-     * @param int $randomNumber randomNumber
+     * @param int|null $randomNumber randomNumber
      * @return static
-     */ 
+     */
     public function setRandomNumber($randomNumber)
     {
-        $this->randomNumber = $randomNumber;
+        $this->randomNumber = null === $randomNumber ? null : (int)$randomNumber;
         return $this;
     }
 

+ 3 - 1
frameworks/PHP/imi/Model/Fortune.php

@@ -1,11 +1,13 @@
 <?php
+declare(strict_types=1);
+
 namespace ImiApp\Model;
 
 use Imi\Bean\Annotation\Inherit;
 use ImiApp\Model\Base\FortuneBase;
 
 /**
- * Fortune
+ * fortune
  * @Inherit
  */
 class Fortune extends FortuneBase

+ 76 - 0
frameworks/PHP/imi/Model/PgSql/Base/FortuneBase.php

@@ -0,0 +1,76 @@
+<?php
+declare(strict_types=1);
+
+namespace ImiApp\Model\PgSql\Base;
+
+use Imi\Pgsql\Model\PgModel as Model;
+use Imi\Model\Annotation\Table;
+use Imi\Model\Annotation\Column;
+use Imi\Model\Annotation\Entity;
+
+/**
+ * Fortune 基类
+ * @Entity(bean=false)
+ * @Table(name="Fortune", id={"id"}, dbPoolName="pgsql")
+ * @property int|null $id 
+ * @property string|null $message 
+ */
+abstract class FortuneBase extends Model
+{
+    /**
+     * id
+     * @Column(name="id", type="int4", length=-1, accuracy=0, nullable=false, default="", isPrimaryKey=true, primaryKeyIndex=1, isAutoIncrement=false, ndims=0)
+     * @var int|null
+     */
+    protected ?int $id = null;
+
+    /**
+     * 获取 id
+     *
+     * @return int|null
+     */
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    /**
+     * 赋值 id
+     * @param int|null $id id
+     * @return static
+     */
+    public function setId(?int $id)
+    {
+        $this->id = $id;
+        return $this;
+    }
+
+    /**
+     * message
+     * @Column(name="message", type="varchar", length=0, accuracy=2048, nullable=false, default="", isPrimaryKey=false, primaryKeyIndex=-1, isAutoIncrement=false, ndims=0)
+     * @var string|null
+     */
+    protected ?string $message = null;
+
+    /**
+     * 获取 message
+     *
+     * @return string|null
+     */
+    public function getMessage(): ?string
+    {
+        return $this->message;
+    }
+
+    /**
+     * 赋值 message
+     * @param string|null $message message
+     * @return static
+     */
+    public function setMessage(?string $message)
+    {
+        $this->message = $message;
+        return $this;
+    }
+
+}

+ 76 - 0
frameworks/PHP/imi/Model/PgSql/Base/WorldBase.php

@@ -0,0 +1,76 @@
+<?php
+declare(strict_types=1);
+
+namespace ImiApp\Model\PgSql\Base;
+
+use Imi\Pgsql\Model\PgModel as Model;
+use Imi\Model\Annotation\Table;
+use Imi\Model\Annotation\Column;
+use Imi\Model\Annotation\Entity;
+
+/**
+ * World 基类
+ * @Entity(bean=false)
+ * @Table(name="World", id={"id"}, dbPoolName="pgsql")
+ * @property int|null $id 
+ * @property int|null $randomnumber 
+ */
+abstract class WorldBase extends Model
+{
+    /**
+     * id
+     * @Column(name="id", type="int4", length=-1, accuracy=0, nullable=false, default="", isPrimaryKey=true, primaryKeyIndex=1, isAutoIncrement=false, ndims=0)
+     * @var int|null
+     */
+    protected ?int $id = null;
+
+    /**
+     * 获取 id
+     *
+     * @return int|null
+     */
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    /**
+     * 赋值 id
+     * @param int|null $id id
+     * @return static
+     */
+    public function setId(?int $id)
+    {
+        $this->id = $id;
+        return $this;
+    }
+
+    /**
+     * randomnumber
+     * @Column(name="randomnumber", type="int4", length=-1, accuracy=0, nullable=false, default="0", isPrimaryKey=false, primaryKeyIndex=-1, isAutoIncrement=false, ndims=0)
+     * @var int|null
+     */
+    protected ?int $randomnumber = null;
+
+    /**
+     * 获取 randomnumber
+     *
+     * @return int|null
+     */
+    public function getRandomnumber(): ?int
+    {
+        return $this->randomnumber;
+    }
+
+    /**
+     * 赋值 randomnumber
+     * @param int|null $randomnumber randomnumber
+     * @return static
+     */
+    public function setRandomnumber(?int $randomnumber)
+    {
+        $this->randomnumber = $randomnumber;
+        return $this;
+    }
+
+}

+ 16 - 0
frameworks/PHP/imi/Model/PgSql/Fortune.php

@@ -0,0 +1,16 @@
+<?php
+declare(strict_types=1);
+
+namespace ImiApp\Model\PgSql;
+
+use Imi\Bean\Annotation\Inherit;
+use ImiApp\Model\PgSql\Base\FortuneBase;
+
+/**
+ * Fortune
+ * @Inherit
+ */
+class Fortune extends FortuneBase
+{
+
+}

+ 16 - 0
frameworks/PHP/imi/Model/PgSql/World.php

@@ -0,0 +1,16 @@
+<?php
+declare(strict_types=1);
+
+namespace ImiApp\Model\PgSql;
+
+use Imi\Bean\Annotation\Inherit;
+use ImiApp\Model\PgSql\Base\WorldBase;
+
+/**
+ * World
+ * @Inherit
+ */
+class World extends WorldBase
+{
+
+}

+ 3 - 1
frameworks/PHP/imi/Model/World.php

@@ -1,11 +1,13 @@
 <?php
+declare(strict_types=1);
+
 namespace ImiApp\Model;
 
 use Imi\Bean\Annotation\Inherit;
 use ImiApp\Model\Base\WorldBase;
 
 /**
- * World
+ * world
  * @Inherit
  */
 class World extends WorldBase

+ 0 - 137
frameworks/PHP/imi/README.md

@@ -1,137 +0,0 @@
-<p align="center">
-    <a href="https://www.imiphp.com" target="_blank">
-        <img src="https://raw.githubusercontent.com/Yurunsoft/IMI/dev/res/logo.png" alt="imi" />
-    </a>
-</p>
-
-[![Latest Version](https://img.shields.io/packagist/v/yurunsoft/imi.svg)](https://packagist.org/packages/yurunsoft/imi)
-[![Travis](https://img.shields.io/travis/Yurunsoft/IMI.svg)](https://travis-ci.org/Yurunsoft/IMI)
-[![Php Version](https://img.shields.io/badge/php-%3E=7.1-brightgreen.svg)](https://secure.php.net/)
-[![Swoole Version](https://img.shields.io/badge/swoole-%3E=4.3.0-brightgreen.svg)](https://github.com/swoole/swoole-src)
-[![imi Doc](https://img.shields.io/badge/docs-passing-green.svg)](https://doc.imiphp.com)
-[![imi License](https://img.shields.io/badge/license-MulanPSL%201.0-brightgreen.svg)](https://github.com/Yurunsoft/imi/blob/master/LICENSE)
-
-## 介绍
-
-imi 是基于 PHP Swoole 的高性能协程应用开发框架,它支持 HttpApi、WebSocket、TCP、UDP 服务的开发。
-
-在 Swoole 的加持下,相比 php-fpm 请求响应能力,I/O密集型场景处理能力,有着本质上的提升。
-
-imi 框架拥有丰富的功能组件,可以广泛应用于互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域。可以使企业 IT 研发团队的效率大大提升,更加专注于开发创新产品。
-
-imi 框架交流群:17916227 [![点击加群](https://pub.idqqimg.com/wpa/images/group.png "点击加群")](https://jq.qq.com/?_wv=1027&k=5wXf4Zq)
-
-### 核心组件
-
-* HttpApi、WebSocket、TCP、UDP 服务器
-* MySQL 连接池 (主从+负载均衡)
-* Redis 连接池 (主从+负载均衡)
-* 超好用的 ORM (Db、Redis、Tree)
-* 毫秒级热更新
-* AOP
-* Bean 容器
-* 缓存 (Cache)
-* 配置读写 (Config)
-* 枚举 (Enum)
-* 事件 (Event)
-* 门面 (Facade)
-* 验证器 (Validate)
-* 锁 (Lock)
-* 日志 (Log)
-* 异步任务 (Task)
-
-### 扩展组件
-
-* [RPC](https://github.com/imiphp/imi-rpc)
-* [Hprose](https://github.com/imiphp/imi-hprose)
-* [权限控制](https://github.com/imiphp/imi-access-control)
-* [Smarty 模版引擎](https://github.com/imiphp/imi-smarty)
-* [限流](https://github.com/imiphp/imi-rate-limit)
-* [跨进程变量共享](https://github.com/imiphp/imi-shared-memory)
-* [Swoole Tracker](https://github.com/imiphp/imi-swoole-tracker)
-
-## 开始使用
-
-创建 Http Server 项目:`composer create-project imiphp/project-http`
-
-创建 WebSocket Server 项目:`composer create-project imiphp/project-websocket`
-
-创建 TCP Server 项目:`composer create-project imiphp/project-tcp`
-
-创建 UDP Server 项目:`composer create-project imiphp/project-udp`
-
-[完全开发手册](https://doc.imiphp.com)
-
-## 运行环境
-
-- Linux 系统 (Swoole 不支持在 Windows 上运行)
-- [PHP](https://php.net/) >= 7.1
-- [Composer](https://getcomposer.org/)
-- [Swoole](https://www.swoole.com/) >= 4.3.0
-- Redis、PDO 扩展
-
-## 版权信息
-
-imi 遵循 木兰宽松许可证(Mulan PSL v1) 开源协议发布,并提供免费使用。
-
-## 鸣谢
-
-感谢以下开源项目 (按字母顺序排列) 为 imi 提供强力支持!
-
-- [doctrine/annotations](https://github.com/doctrine/annotations) (PHP 注解处理类库)
-- [PHP](https://php.net/) (没有 PHP 就没有 imi)
-- [Swoole](https://www.swoole.com/) (没有 Swoole 就没有 imi)
-
-## 贡献者
-
-<a href="https://github.com/Yurunsoft/IMI/graphs/contributors"><img src="https://opencollective.com/IMI/contributors.svg?width=890&button=false" /></a>
-
-你想出现在贡献者列表中吗?
-
-你可以做的事(包括但不限于以下):
-
-* 纠正拼写、错别字
-* 完善注释
-* bug修复
-* 功能开发
-* 文档编写(<https://github.com/Yurunsoft/imidoc>)
-* 教程、博客分享
-
-> 最新代码以 `dev` 分支为准,提交 `PR` 也请合并至 `dev` 分支!
-
-提交 `Pull Request` 到本仓库,你就有机会成为 imi 的作者之一!
-
-## 关于测试脚本
-
-### 环境要求
-
-Redis、MySQL
-
-### 首次运行测试
-
-* 创建 `db_imi_test` 数据库,将 `tests/db/db.sql` 导入到数据库
-
-* 配置系统环境变量,如果默认值跟你的一样就无需配置了
-
-名称 | 描述 | 默认值
--|-|-
-MYSQL_SERVER_HOST | MySQL 主机名 | 127.0.0.1 |
-MYSQL_SERVER_PORT | MySQL 端口 | 3306 |
-MYSQL_SERVER_USERNAME | MySQL 用户名 | root |
-MYSQL_SERVER_PASSWORD | MySQL 密码 | root |
-REDIS_SERVER_HOST | Redis 主机名 | 127.0.0.1 |
-REDIS_SERVER_PORT | Redis 端口 | 6379 |
-REDIS_SERVER_PASSWORD | Redis 密码 |  |
-REDIS_CACHE_DB | Redis 缓存用的 `db`,该 `db` 会被清空数据,请慎重设置 | 1 |
-
-配置命令:`export NAME=VALUE`
-
-* 首次运行测试脚本:`composer install-test`
-
-* 首次之后再运行测试的命令:`composer test`
-
-## 捐赠
-
-<img src="https://raw.githubusercontent.com/Yurunsoft/IMI/dev/res/pay.png"/>
-
-开源不求盈利,多少都是心意,生活不易,随缘随缘……

+ 128 - 11
frameworks/PHP/imi/benchmark_config.json

@@ -3,6 +3,7 @@
   "tests": [
     {
       "default": {
+        "dockerfile": "imi-swoole.dockerfile",
         "json_url": "/json",
         "plaintext_url": "/plaintext",
         "db_url": "/dbModel",
@@ -22,35 +23,63 @@
         "webserver": "None",
         "os": "Linux",
         "database_os": "Linux",
-        "display_name": "imi",
+        "display_name": "imi-swoole",
         "notes": "",
         "versus": "Swoole"
       },
-      "query-builder": {
-        "db_url": "/dbQueryBuilder",
-        "query_url": "/queryQueryBuilder?queries=",
-        "update_url": "/updateQueryBuilder?queries=",
+      "swoole-mysql-raw": {
+        "dockerfile": "imi-swoole.dockerfile",
+        "db_url": "/dbRaw",
+        "query_url": "/queryRaw?queries=",
+        "fortune_url": "/fortunesRaw",
+        "update_url": "/updateRaw?queries=",
         "port": 8080,
         "approach": "Realistic",
-        "classification": "Fullstack",
+        "classification": "Micro",
         "database": "MySQL",
         "framework": "imi",
         "language": "PHP",
         "flavor": "None",
-        "orm": "Micro",
+        "orm": "Raw",
         "platform": "Swoole",
         "webserver": "None",
         "os": "Linux",
         "database_os": "Linux",
-        "display_name": "imi-query-builder",
+        "display_name": "imi-swoole-mysql-raw",
         "notes": "",
         "versus": "Swoole"
       },
-      "raw": {
+      "workerman": {
+        "dockerfile": "imi-workerman.dockerfile",
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "db_url": "/dbModel",
+        "query_url": "/queryModel?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updateModel?queries=",
+        "cached_query_url": "/cached-worlds?count=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Fullstack",
+        "database": "MySQL",
+        "framework": "imi",
+        "language": "PHP",
+        "flavor": "None",
+        "orm": "Full",
+        "platform": "Workerman",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "imi-workerman",
+        "notes": "",
+        "versus": "Workerman"
+      },
+      "workerman-mysql-raw": {
+        "dockerfile": "imi-workerman.dockerfile",
         "db_url": "/dbRaw",
         "query_url": "/queryRaw?queries=",
-        "update_url": "/updateRaw?queries=",
         "fortune_url": "/fortunesRaw",
+        "update_url": "/updateRaw?queries=",
         "port": 8080,
         "approach": "Realistic",
         "classification": "Micro",
@@ -59,13 +88,101 @@
         "language": "PHP",
         "flavor": "None",
         "orm": "Raw",
+        "platform": "Workerman",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "imi-workerman-mysql-raw",
+        "notes": "",
+        "versus": "Workerman"
+      },
+      "swoole-pgsql": {
+        "dockerfile": "imi-swoole-pgsql.dockerfile",
+        "db_url": "/pgDbModel",
+        "query_url": "/pgQueryModel?queries=",
+        "fortune_url": "/pgFortunes",
+        "update_url": "/pgUpdateModel?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Fullstack",
+        "database": "Postgres",
+        "framework": "imi",
+        "language": "PHP",
+        "flavor": "None",
+        "orm": "Full",
+        "platform": "Swoole",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "imi-swoole-pgsql",
+        "notes": "",
+        "versus": "Swoole"
+      },
+      "swoole-pgsql-raw": {
+        "dockerfile": "imi-swoole-pgsql.dockerfile",
+        "db_url": "/pgDbRaw",
+        "query_url": "/pgQueryRaw?queries=",
+        "fortune_url": "/pgFortunesRaw",
+        "update_url": "/pgUpdateRaw?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "imi",
+        "language": "PHP",
+        "flavor": "None",
+        "orm": "Raw",
         "platform": "Swoole",
         "webserver": "None",
         "os": "Linux",
         "database_os": "Linux",
-        "display_name": "imi-raw",
+        "display_name": "imi-swoole-pgsql-raw",
         "notes": "",
         "versus": "Swoole"
+      },
+      "workerman-pgsql": {
+        "dockerfile": "imi-workerman.dockerfile",
+        "db_url": "/pgDbModel",
+        "query_url": "/pgQueryModel?queries=",
+        "fortune_url": "/pgFortunes",
+        "update_url": "/pgUpdateModel?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Fullstack",
+        "database": "Postgres",
+        "framework": "imi",
+        "language": "PHP",
+        "flavor": "None",
+        "orm": "Full",
+        "platform": "Workerman",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "imi-workerman-pgsql",
+        "notes": "",
+        "versus": "Workerman"
+      },
+      "workerman-pgsql-raw": {
+        "dockerfile": "imi-workerman.dockerfile",
+        "db_url": "/pgDbRaw",
+        "query_url": "/pgQueryRaw?queries=",
+        "fortune_url": "/pgFortunesRaw",
+        "update_url": "/pgUpdateRaw?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "imi",
+        "language": "PHP",
+        "flavor": "None",
+        "orm": "Raw",
+        "platform": "Workerman",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "imi-workerman-pgsql-raw",
+        "notes": "",
+        "versus": "Workerman"
       }
     }
   ]

+ 6 - 5
frameworks/PHP/imi/composer.json

@@ -1,10 +1,11 @@
 {
-	"require": {
-		"yurunsoft/imi": "~1.0"
-	},
+    "require": {
+        "imiphp/imi": "~2.0",
+        "imiphp/imi-pgsql": "~2.0"
+    },
     "autoload": {
         "psr-4" : {
-			"ImiApp\\" : "./"
+            "ImiApp\\" : "./"
         }
-	}
+    }
 }

+ 93 - 6
frameworks/PHP/imi/config.toml

@@ -2,6 +2,7 @@
 name = "imi"
 
 [main]
+dockerfile = "imi-swoole.dockerfile"
 urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.db = "/dbModel"
@@ -19,7 +20,8 @@ platform = "Swoole"
 webserver = "None"
 versus = "Swoole"
 
-[raw]
+[swoole-mysql-raw]
+dockerfile = "imi-swoole.dockerfile"
 urls.db = "/dbRaw"
 urls.query = "/queryRaw?queries="
 urls.update = "/updateRaw?queries="
@@ -34,16 +36,101 @@ platform = "Swoole"
 webserver = "None"
 versus = "Swoole"
 
-[query-builder]
-urls.db = "/dbQueryBuilder"
-urls.query = "/queryQueryBuilder?queries="
-urls.update = "/updateQueryBuilder?queries="
+[workerman]
+dockerfile = "imi-workerman.dockerfile"
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/dbModel"
+urls.query = "/queryModel?queries="
+urls.update = "/updateModel?queries="
+urls.fortune = "/fortunes"
+urls.cached_query = "/cached-worlds?count="
 approach = "Realistic"
 classification = "Fullstack"
 database = "MySQL"
 database_os = "Linux"
 os = "Linux"
-orm = "Micro"
+orm = "Full"
+platform = "Workerman"
+webserver = "None"
+versus = "Workerman"
+
+[workerman-mysql-raw]
+dockerfile = "imi-workerman.dockerfile"
+urls.db = "/dbRaw"
+urls.query = "/queryRaw?queries="
+urls.update = "/updateRaw?queries="
+urls.fortune = "/fortunesRaw"
+approach = "Realistic"
+classification = "Micro"
+database = "MySQL"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "Workerman"
+webserver = "None"
+versus = "Workerman"
+
+[swoole-pgsql]
+dockerfile = "imi-swoole.dockerfile"
+urls.db = "/pgDbModel"
+urls.query = "/pgQueryModel?queries="
+urls.update = "/pgUpdateModel?queries="
+urls.fortune = "/pgFortunes"
+approach = "Realistic"
+classification = "Fullstack"
+database = "Postgres"
+database_os = "Linux"
+os = "Linux"
+orm = "Full"
 platform = "Swoole"
 webserver = "None"
 versus = "Swoole"
+
+[swoole-pgsql-raw]
+dockerfile = "imi-swoole.dockerfile"
+urls.db = "/dbRaw"
+urls.query = "/pgQueryRaw?queries="
+urls.update = "/pgUpdateRaw?queries="
+urls.fortune = "/pgFortunesRaw"
+approach = "Realistic"
+classification = "Micro"
+database = "Postgres"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "Swoole"
+webserver = "None"
+versus = "Swoole"
+
+[workerman-pgsql]
+dockerfile = "imi-workerman.dockerfile"
+urls.db = "/pgDbModel"
+urls.query = "/pgQueryModel?queries="
+urls.update = "/pgUpdateModel?queries="
+urls.fortune = "/pgFortunes"
+approach = "Realistic"
+classification = "Fullstack"
+database = "Postgres"
+database_os = "Linux"
+os = "Linux"
+orm = "Full"
+platform = "Workerman"
+webserver = "None"
+versus = "Workerman"
+
+[workerman-pgsql-raw]
+dockerfile = "imi-workerman.dockerfile"
+urls.db = "/dbRaw"
+urls.query = "/pgQueryRaw?queries="
+urls.update = "/pgUpdateRaw?queries="
+urls.fortune = "/pgFortunesRaw"
+approach = "Realistic"
+classification = "Micro"
+database = "Postgres"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "Workerman"
+webserver = "None"
+versus = "Workerman"

+ 0 - 2
frameworks/PHP/imi/config/beans.php

@@ -3,6 +3,4 @@ return [
     'hotUpdate'    =>    [
         'status'    =>    false, // 关闭热更新去除注释,不设置即为开启,建议生产环境关闭
     ],
-    'Logger'    =>    [
-    ],
 ];

+ 84 - 57
frameworks/PHP/imi/config/config.php

@@ -1,11 +1,13 @@
 <?php
-$dbResourceConfig = [
-    'host'        => 'tfb-database',
-    'username'    => 'benchmarkdbuser',
-    'password'    => 'benchmarkdbpass',
-    'database'    => 'hello_world',
-    'dbClass'     => \Imi\Db\Drivers\Swoole\Driver::class,
-];
+
+use Imi\App;
+
+$mode = App::isInited() ? App::getApp()->getType() : '';
+$isMysql = ('mysql' === strtolower(getenv('TFB_TEST_DATABASE') ?: 'mysql'));
+$host = 'tfb-database';
+$username = 'benchmarkdbuser';
+$password = 'benchmarkdbpass';
+
 return [
     // 项目根命名空间
     'namespace'    =>    'ImiApp',
@@ -15,18 +17,13 @@ return [
         'beans'        =>    __DIR__ . '/beans.php',
     ],
 
-    // 扫描目录
-    'beanScan'    =>    [
-        'ImiApp\Listener',
-    ],
-
     // 组件命名空间
     'components'    =>  [],
 
     // 主服务器配置
-    'mainServer'    =>    [
+    'mainServer'    => 'swoole' === $mode ? [
         'namespace' =>  'ImiApp\ApiServer',
-        'type'      =>  Imi\Server\Type::HTTP,
+        'type'      =>  Imi\Swoole\Server\Type::HTTP,
         'host'      =>  '0.0.0.0',
         'port'      =>  8080,
         'mode'      =>  SWOOLE_BASE,
@@ -39,61 +36,91 @@ return [
             'http_parse_files'  => false,
             'http_compression'  => false,
         ],
-    ],
+    ] : [],
+
+    // Workerman 服务器配置
+    'workermanServer' => 'workerman' === $mode ? [
+        // 服务器名,http 也可以改成 abc 等等,完全自定义
+        'http' => [
+            // 指定服务器命名空间
+            'namespace' => 'ImiApp\ApiServer',
+            // 服务器类型
+            'type'      => Imi\Workerman\Server\Type::HTTP, // HTTP、WEBSOCKET、TCP、UDP
+            'host'      => '0.0.0.0',
+            'port'      => 8080,
+            // socket的上下文选项,参考:http://doc3.workerman.net/315128
+            'context'   => [],
+            'configs'   => [
+                // 支持设置 Workerman 参数
+                'count' => (int) shell_exec('nproc') * 4,
+            ],
+        ],
+    ] : [],
 
     'db'    => [
-        'defaultPool'   => 'db', // 默认连接池
-    ],
-    'redis'    =>    [
-        'defaultPool'               =>    'redis', // 默认连接池
-        'quickFromRequestContext'   =>    true, // 从当前上下文中获取公用连接
+        'defaultPool'   => $isMysql ? 'mysql' : 'pgsql', // 默认连接池
+        'connections'   => [
+            'mysql' => [
+                'host'        => $host,
+                'username'    => $username,
+                'password'    => $password,
+                'database'    => 'hello_world',
+                'dbClass'     => \Imi\Db\Mysql\Drivers\Mysqli\Driver::class,
+            ],
+            'pgsql' => [
+                'host'        => $host,
+                'username'    => $username,
+                'password'    => $password,
+                'database'    => 'hello_world',
+                'dbClass'     => \Imi\Pgsql\Db\Drivers\PdoPgsql\Driver::class,
+            ],
+        ],
     ],
-    'pools' => [
+
+    'pools' => 'swoole' === $mode ? [
         // 连接池名称
-        'db' => [
-            // 异步池子,worker进程使用
-            'async' => [
-                'pool'    =>    [
-                    'class'        =>    \Imi\Db\Pool\CoroutineDbPool::class,
-                    'config'    =>    [
-                        // 池子中最多资源数
-                        'maxResources' => 512,
-                        // 池子中最少资源数
-                        'minResources' => 16,
-                        'gcInterval'   => null,
-                        'checkStateWhenGetResource' =>  false,
-                        'requestResourceCheckInterval' => 30,
-                    ],
+        'mysql' => [
+            'pool'    =>    [
+                'class'        =>    \Imi\Swoole\Db\Pool\CoroutineDbPool::class,
+                'config'    =>    [
+                    // 池子中最多资源数
+                    'maxResources' => intval(1024 / swoole_cpu_num()),
+                    // 池子中最少资源数
+                    'minResources' => $isMysql ? 16 : 0,
+                    'gcInterval'   => 0,
+                    'checkStateWhenGetResource' =>  false,
+                    'requestResourceCheckInterval' => 0,
                 ],
-                // resource也可以定义多个连接
-                'resource'    =>    $dbResourceConfig,
+            ],
+            // resource也可以定义多个连接
+            'resource'    =>    [
+                'host'        => $host,
+                'username'    => $username,
+                'password'    => $password,
+                'database'    => 'hello_world',
+                'dbClass'     => \Imi\Swoole\Db\Driver\Swoole\Driver::class,
             ],
         ],
-        'redis' =>  [
-            'pool' => [
-                // 协程池类名
-                'asyncClass'    =>    \Imi\Redis\CoroutineRedisPool::class,
-                'config' => [
+        'pgsql' => [
+            'pool'    =>    [
+                'class'        =>    \Imi\Swoole\Db\Pool\CoroutineDbPool::class,
+                'config'    =>    [
                     // 池子中最多资源数
-                    'maxResources' => 512,
+                    'maxResources' => intval(1024 / swoole_cpu_num()),
                     // 池子中最少资源数
-                    'minResources' => 0,
-                    'gcInterval'   => null,
+                    'minResources' => $isMysql ? 0 : 16,
                     'checkStateWhenGetResource' =>  false,
-                    'requestResourceCheckInterval' => 30,
+                    'requestResourceCheckInterval' => 0,
                 ],
             ],
-            // 数组资源配置
-            'resource' => [
-                'host'      =>  '127.0.0.1',
-                'port'      =>  6379,
-                // 是否自动序列化变量
-                'serialize' =>  true,
-                // 密码
-                'password'  =>  null,
-                // 第几个库
-                'db'        =>  0,
+            // resource也可以定义多个连接
+            'resource'    =>    [
+                'host'        => $host,
+                'username'    => $username,
+                'password'    => $password,
+                'database'    => 'hello_world',
+                'dbClass'     => \Imi\Pgsql\Db\Drivers\Swoole\Driver::class,
             ],
         ],
-    ],
+    ] : [],
 ];

+ 0 - 28
frameworks/PHP/imi/imi-query-builder.dockerfile

@@ -1,28 +0,0 @@
-FROM php:8.0-cli
-
-RUN pecl install swoole > /dev/null && \
-    docker-php-ext-enable swoole
-
-RUN docker-php-ext-install bcmath pdo_mysql opcache > /dev/null
-
-RUN apt -yqq update > /dev/null && \
-    apt -yqq install git unzip > /dev/null
-
-RUN echo "opcache.enable_cli=On" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
-RUN echo "opcache.jit=Off" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
-RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
-
-COPY . /imi
-COPY php.ini /usr/local/etc/php/
-
-WORKDIR /imi
-
-RUN chmod -R ug+rwx /imi/.runtime
-
-RUN curl -sSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
-RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null
-RUN composer dumpautoload -o
-
-EXPOSE 8080
-
-CMD php vendor/bin/imi server/start

+ 37 - 0
frameworks/PHP/imi/imi-swoole-pgsql.dockerfile

@@ -0,0 +1,37 @@
+FROM php:8.0-cli
+
+ENV SWOOLE_VERSION 4.8.3
+ENV SWOOLE_POSTGRES 4.8.0
+ARG TFB_TEST_DATABASE
+ENV TFB_TEST_DATABASE=${TFB_TEST_DATABASE}
+
+RUN docker-php-ext-install -j$(nproc) opcache > /dev/null
+
+RUN apt -yqq update > /dev/null && \
+    apt -yqq install git unzip libpq-dev > /dev/null
+
+RUN cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \
+        && cd swoole-src-${SWOOLE_VERSION} \
+        && phpize && ./configure > /dev/null && make -j > /dev/null && make install > /dev/null \
+        && docker-php-ext-enable swoole
+
+RUN cd /tmp && curl -sSL "https://github.com/swoole/ext-postgresql/archive/v${SWOOLE_POSTGRES}.tar.gz" | tar xzf - \
+        && cd ext-postgresql-${SWOOLE_POSTGRES} \
+        && phpize && ./configure > /dev/null && make -j > /dev/null && make install > /dev/null \
+        && docker-php-ext-enable swoole_postgresql
+
+COPY . /imi
+COPY php.ini /usr/local/etc/php/
+
+RUN chmod -R ug+rwx /imi/.runtime
+
+WORKDIR /imi
+
+RUN curl -sSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
+RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null
+RUN composer require imiphp/imi-swoole:~2.0 -W
+RUN composer dumpautoload -o
+
+EXPOSE 8080
+
+CMD ./run-swoole.sh

+ 13 - 10
frameworks/PHP/imi/imi-raw.dockerfile → frameworks/PHP/imi/imi-swoole.dockerfile

@@ -1,28 +1,31 @@
-FROM php:8.0-cli
+FROM php:8.1-cli
 
-RUN pecl install swoole > /dev/null && \
-    docker-php-ext-enable swoole
+ENV SWOOLE_VERSION 4.8.3
+ARG TFB_TEST_DATABASE
+ENV TFB_TEST_DATABASE=${TFB_TEST_DATABASE}
 
-RUN docker-php-ext-install bcmath pdo_mysql opcache > /dev/null
+RUN docker-php-ext-install -j$(nproc) opcache > /dev/null
 
 RUN apt -yqq update > /dev/null && \
     apt -yqq install git unzip > /dev/null
 
-RUN echo "opcache.enable_cli=On" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
-RUN echo "opcache.jit=Off" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
-RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
+RUN pecl update-channels
+
+RUN pecl install swoole-${SWOOLE_VERSION} > /dev/null && \
+    docker-php-ext-enable swoole
 
 COPY . /imi
 COPY php.ini /usr/local/etc/php/
 
-WORKDIR /imi
-
 RUN chmod -R ug+rwx /imi/.runtime
 
+WORKDIR /imi
+
 RUN curl -sSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
 RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null
+RUN composer require imiphp/imi-swoole:~2.0 -W
 RUN composer dumpautoload -o
 
 EXPOSE 8080
 
-CMD php vendor/bin/imi server/start
+CMD ./run-swoole.sh

+ 30 - 0
frameworks/PHP/imi/imi-workerman.dockerfile

@@ -0,0 +1,30 @@
+FROM php:8.1-cli
+
+ARG TFB_TEST_DATABASE
+ENV TFB_TEST_DATABASE=${TFB_TEST_DATABASE}
+
+RUN apt -yqq update > /dev/null && \
+    apt -yqq install git unzip libevent-dev libssl-dev libpq-dev > /dev/null
+
+RUN docker-php-ext-install -j$(nproc) opcache mysqli pcntl sockets pdo_pgsql > /dev/null
+
+RUN pecl update-channels
+
+RUN pecl install event > /dev/null && \
+    echo "extension=event.so" > /usr/local/etc/php/conf.d/event.ini
+
+COPY . /imi
+COPY php.ini /usr/local/etc/php/
+
+RUN chmod -R ug+rwx /imi/.runtime
+
+WORKDIR /imi
+
+RUN curl -sSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
+RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null
+RUN composer require imiphp/imi-workerman:~2.0 -W
+RUN composer dumpautoload -o
+
+EXPOSE 8080
+
+CMD ./run-workerman.sh

+ 0 - 34
frameworks/PHP/imi/imi.dockerfile

@@ -1,34 +0,0 @@
-FROM php:8.0-cli
-
-RUN pecl install swoole > /dev/null && \
-    docker-php-ext-enable swoole
-
-RUN docker-php-ext-install bcmath pdo_mysql opcache > /dev/null
-
-RUN pecl install redis > /dev/null && \
-    docker-php-ext-enable redis
-
-RUN apt -yqq update > /dev/null && \
-    apt -yqq install git unzip > /dev/null
-
-RUN apt -yqq install redis-server > /dev/null
-
-RUN echo "opcache.enable_cli=On" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
-RUN echo "opcache.jit=Off" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
-RUN echo "opcache.jit_buffer_size=128M" >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
-
-COPY . /imi
-COPY php.ini /usr/local/etc/php/
-
-WORKDIR /imi
-COPY .env-with-redis .env
-
-RUN chmod -R ug+rwx /imi/.runtime
-
-RUN curl -sSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
-RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null
-RUN composer dumpautoload -o
-
-EXPOSE 8080
-
-CMD ./run-with-redis.sh

+ 3 - 0
frameworks/PHP/imi/php.ini

@@ -1,2 +1,5 @@
+opcache.enable=1
 opcache.enable_cli=1
 opcache.validate_timestamps=0
+opcache.enable_file_override=1
+opcache.huge_code_pages=1

+ 2 - 0
frameworks/PHP/imi/run-swoole.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+php vendor/bin/imi-swoole swoole/start

+ 0 - 3
frameworks/PHP/imi/run-with-redis.sh

@@ -1,3 +0,0 @@
-#!/bin/bash
-service redis-server start
-php vendor/bin/imi server/start

+ 2 - 0
frameworks/PHP/imi/run-workerman.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+php vendor/bin/imi-workerman workerman/start