├── .scrutinizer.yml ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── rector.php ├── sql ├── mysql-down.sql ├── mysql-up.sql ├── oci-down.sql ├── oci-up.sql ├── pgsql-down.sql ├── pgsql-up.sql ├── sqlite-down.sql ├── sqlite-up.sql ├── sqlsrv-down.sql └── sqlsrv-up.sql └── src ├── DbSchemaManager.php └── DbTarget.php /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | checks: 2 | php: true 3 | 4 | filter: 5 | paths: 6 | - src/* 7 | 8 | build: 9 | image: default-bionic 10 | 11 | environment: 12 | php: 13 | version: 8.1.18 14 | ini: 15 | xdebug.mode: coverage 16 | 17 | nodes: 18 | analysis: 19 | tests: 20 | override: 21 | - php-scrutinizer-run 22 | 23 | phpunit: 24 | services: 25 | db-mssql: 26 | image: mcr.microsoft.com/mssql/server:2017-latest 27 | 28 | # Define any additional environment variables that are needed by the service. 29 | env: 30 | SA_PASSWORD: YourStrong!Passw0rd 31 | ACCEPT_EULA: Y 32 | MSSQL_PID: Developer 33 | 34 | # We automatically forward these ports from your localhost to the service's port. 35 | # Alternatively, you can also access the service on the "$SERVICE_SOME_NAME_IP" 36 | # environment variable. 37 | ports: 38 | # Forward 127.0.0.1:12345 -> SERVICE_IP:12345 39 | - 1433 40 | 41 | # If your service writes data to disk like most databases do, you can significantly 42 | # speed up tests by mounting a ramdisk at those paths. 43 | ramdisks: 44 | - /var/lib/data 45 | 46 | db-mysql: 47 | image: mysql:8.0.29 48 | 49 | # Define any additional environment variables that are needed by the service. 50 | env: 51 | MYSQL_ALLOW_EMPTY_PASSWORD: 1 52 | MYSQL_ROOT_PASSWORD: '' 53 | MYSQL_DATABASE: yiitest 54 | 55 | # We automatically forward these ports from your localhost to the service's port. 56 | # Alternatively, you can also access the service on the "$SERVICE_SOME_NAME_IP" 57 | # environment variable. 58 | ports: 59 | # Forward 127.0.0.1:12345 -> SERVICE_IP:12345 60 | - 3306 61 | 62 | # If your service writes data to disk like most databases do, you can significantly 63 | # speed up tests by mounting a ramdisk at those paths. 64 | ramdisks: 65 | - /var/lib/data 66 | 67 | db-pgsql: 68 | image: postgres:14 69 | 70 | # Define any additional environment variables that are needed by the service. 71 | env: 72 | POSTGRES_USER: root 73 | POSTGRES_PASSWORD: root 74 | POSTGRES_DB: yiitest 75 | 76 | # We automatically forward these ports from your localhost to the service's port. 77 | # Alternatively, you can also access the service on the "$SERVICE_SOME_NAME_IP" 78 | # environment variable. 79 | ports: 80 | # Forward 127.0.0.1:12345 -> SERVICE_IP:12345 81 | - 5432 82 | 83 | # If your service writes data to disk like most databases do, you can significantly 84 | # speed up tests by mounting a ramdisk at those paths. 85 | ramdisks: 86 | - /var/lib/data 87 | 88 | db-oracle: 89 | image: gvenzl/oracle-xe:21 90 | 91 | # We automatically forward these ports from your localhost to the service's port. 92 | # Alternatively, you can also access the service on the "$SERVICE_SOME_NAME_IP" 93 | # environment variable. 94 | ports: 95 | # Forward 127.0.0.1:12345 -> SERVICE_IP:12345 96 | - 1521 97 | 98 | env: 99 | ORACLE_DATABASE : yiitest 100 | ORACLE_PASSWORD : root 101 | 102 | # If your service writes data to disk like most databases do, you can significantly 103 | # speed up tests by mounting a ramdisk at those paths. 104 | ramdisks: 105 | - /var/lib/data 106 | 107 | tests: 108 | before: 109 | - curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - 110 | - curl https://packages.microsoft.com/config/ubuntu/18.04/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list 111 | - sudo apt-get update -y 112 | - sudo ACCEPT_EULA=Y apt-get install mssql-tools unixodbc-dev -y 113 | - sudo ls /opt/mssql-tools/bin/sqlcmd* 114 | - /opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -U SA -P 'YourStrong!Passw0rd' -Q 'CREATE DATABASE yiitest' 115 | - pecl -q install pdo_sqlsrv 116 | - sudo mkdir -p /opt/oracle 117 | - sudo curl -k -L --output /opt/oracle/instantclient-basic-linux.x64-21.3.0.0.0.zip https://download.oracle.com/otn_software/linux/instantclient/213000/instantclient-basic-linux.x64-21.3.0.0.0.zip 118 | - sudo curl -k -L --output /opt/oracle/instantclient-sdk-linux.x64-21.3.0.0.0.zip https://download.oracle.com/otn_software/linux/instantclient/213000/instantclient-sdk-linux.x64-21.3.0.0.0.zip 119 | - sudo unzip /opt/oracle/instantclient-basic-linux.x64-21.3.0.0.0.zip -d /opt/oracle 120 | - sudo unzip /opt/oracle/instantclient-sdk-linux.x64-21.3.0.0.0.zip -d /opt/oracle 121 | - sudo apt-get install libaio1 -y 122 | - export ORACLE_HOME=/opt/oracle/instantclient_21_3 123 | - sudo sh -c "echo /opt/oracle/instantclient_21_3 > /etc/ld.so.conf.d/oracle-instantclient.conf" 124 | - sudo ldconfig 125 | - curl -k -L --output /home/scrutinizer/oci8-3.0.1.tgz https://pecl.php.net/get/oci8-3.0.1.tgz 126 | - cd /home/scrutinizer 127 | - tar -zxf oci8-3.0.1.tgz 128 | - cd oci8-3.0.1 129 | - phpize 130 | - ./configure --with-oci8=instantclient,/opt/oracle/instantclient_21_3 131 | - make 132 | - sudo make install 133 | - sudo ldconfig 134 | - curl -k -L --output /home/scrutinizer/php-8.1.18.tar.gz https://www.php.net/distributions/php-8.1.18.tar.gz 135 | - cd /home/scrutinizer 136 | - tar -zxf php-8.1.18.tar.gz 137 | - cd php-8.1.18/ext/pdo_oci 138 | - phpize 139 | - ./configure --with-pdo-oci=instantclient,/opt/oracle/instantclient_21_3 140 | - make 141 | - sudo make install 142 | - sudo ldconfig 143 | - cd /home/scrutinizer/build/ 144 | - composer require yiisoft/db-mssql --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi 145 | - composer require yiisoft/db-mysql --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi 146 | - composer require yiisoft/db-oracle --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi 147 | - composer require yiisoft/db-pgsql --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi 148 | - composer require yiisoft/db-sqlite --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi 149 | - echo 'extension=pdo_oci' >> /home/scrutinizer/.phpenv/versions/8.1.18/etc/php.ini 150 | 151 | override: 152 | - command: ./vendor/bin/phpunit --coverage-clover ./coverage.xml 153 | coverage: 154 | file: coverage.xml 155 | format: php-clover 156 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Yii Logging Library - DB Target Change Log 2 | 3 | ## 1.0.1 under development 4 | 5 | - no changes in this release. 6 | 7 | ## 1.0.0 May 09, 2023 8 | 9 | - Initial release. -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright © 2008 by Yii Software () 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Yii Software nor the names of its 15 | contributors may be used to endorse or promote products derived 16 | from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Yii 4 | 5 |

Yii Logging Library - DB Target

6 |
7 |

8 | 9 | [![Latest Stable Version](https://poser.pugx.org/yiisoft/log-target-db/v/stable.png)](https://packagist.org/packages/yiisoft/log-target-db) 10 | [![Total Downloads](https://poser.pugx.org/yiisoft/log-target-db/downloads.png)](https://packagist.org/packages/yiisoft/log-target-db) 11 | [![codecov](https://codecov.io/gh/yiisoft/log-target-db/branch/master/graph/badge.svg?token=AP7VK8ZYIF)](https://codecov.io/gh/yiisoft/log-target-db) 12 | [![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fyiisoft%2Flog-target-db%2Fmaster)](https://dashboard.stryker-mutator.io/reports/github.com/yiisoft/log-target-db/master) 13 | [![static analysis](https://github.com/yiisoft/log-target-db/workflows/static%20analysis/badge.svg)](https://github.com/yiisoft/log-target-db/actions?query=workflow%3A%22static+analysis%22) 14 | [![type-coverage](https://shepherd.dev/github/yiisoft/log-target-db/coverage.svg)](https://shepherd.dev/github/yiisoft/log-target-db) 15 | 16 | This package provides the Database target for the [yiisoft/log](https://github.com/yiisoft/log) library. 17 | 18 | ## Supported databases 19 | 20 | | Packages | PHP | Versions | CI-Actions | 21 | |----------|-----|----------|------------| 22 | | [[db-mssql]](https://github.com/yiisoft/db-mssql) | **8.0 - 8.2** | **2017 - 2022** | [![mssql](https://github.com/yiisoft/log-target-db/actions/workflows/mssql.yml/badge.svg)](https://github.com/yiisoft/log-target-db/actions/workflows/mssql.yml) | | 23 | | [[db-mysql/mariadb]](https://github.com/yiisoft/db-mysql) | **8.0 - 8.2** | **5.7-8.0**/**10.4-10.10** | [![mysql](https://github.com/yiisoft/log-target-db/actions/workflows/mysql.yml/badge.svg)](https://github.com/yiisoft/log-target-db/actions/workflows/mysql.yml) | 24 | | [[db-oracle]](https://github.com/yiisoft/db-oracle) | **8.0 - 8.2** | **11C - 21C** | [![oracle](https://github.com/yiisoft/log-target-db/actions/workflows/oracle.yml/badge.svg)](https://github.com/yiisoft/log-target-db/actions/workflows/oracle.yml) | 25 | | [[db-pgsql]](https://github.com/yiisoft/db-pgsql) | **8.0 - 8.2** | **9.0 - 15.0** | [![pgsql](https://github.com/yiisoft/log-target-db/actions/workflows/pgsql.yml/badge.svg)](https://github.com/yiisoft/log-target-db/actions/workflows/pgsql.yml) | 26 | | [[db-sqlite]](https://github.com/yiisoft/db-sqlite) | **8.0 - 8.2** | **3:latest** | [![sqlite](https://github.com/yiisoft/log-target-db/actions/workflows/sqlite.yml/badge.svg)](https://github.com/yiisoft/log-target-db/actions/workflows/sqlite.yml) | 27 | 28 | ## Requirements 29 | 30 | - PHP 8.0 or higher. 31 | - `PDO` PHP extension. 32 | 33 | ## Installation 34 | 35 | The package could be installed with [Composer](https://getcomposer.org): 36 | 37 | ```shell 38 | composer require yiisoft/log-target-db 39 | ``` 40 | 41 | ## Create database connection 42 | 43 | For more information see [yiisoft/db](https://github.com/yiisoft/db/tree/master/docs/guide/en#create-connection). 44 | 45 | ## Database Preparing 46 | 47 | Package provides two way for preparing database: 48 | 49 | 1. Raw SQL. You can use it with the migration package used in your application. 50 | 51 | - Ensure tables: 52 | - [MSSQL](sql/sqlsrv-up.sql), 53 | - [MySQL / MariaDB](sql/mysql-up.sql), 54 | - [Oracle](sql/oci-up.sql), 55 | - [PostgreSQL](sql/pgsql-up.sql) 56 | - [SQLite](sql/sqlite-up.sql) 57 | 58 | - Ensure no tables: 59 | - [MSSQL](sql/sqlsrv-down.sql), 60 | - [MySQL / MariaDB](sql/mysql-down.sql), 61 | - [Oracle](sql/oci-down.sql), 62 | - [PostgreSQL](sql/pgsql-down.sql) 63 | - [SQLite](sql/sqlite-down.sql) 64 | 65 | 2. `DbSchemaManager` for `ensureTable()`, `ensureNoTable()` methods for log table (by default `{{%yii_log}}`). 66 | 67 | ```php 68 | // Create db schema manager 69 | $dbSchemaManager = new DbSchemaManager($db); 70 | 71 | // Ensure table with default name 72 | $dbSchemaManager->ensureTable(); 73 | 74 | // Ensure table with custom name 75 | $dbSchemaManager->ensureTable('{{%custom_log_table}}'); 76 | 77 | // Ensure no table with default name 78 | $dbSchemaManager->ensureNoTable(); 79 | 80 | // Ensure no table with custom name 81 | $dbSchemaManager->ensureNoTable('{{%custom_log_table}}'); 82 | ``` 83 | 84 | ## General usage 85 | 86 | When creating an instance of `\Yiisoft\Log\Logger`, you must pass an instance of the database connection. 87 | 88 | Creating a target: 89 | 90 | ```php 91 | $dbTarget = new \Yiisoft\Log\Target\Db\DbTarget($db, $table); 92 | ``` 93 | 94 | - `$db (\Yiisoft\Db\Connection\ConnectionInterface)` - The database connection instance. 95 | - `$table (string)` - The name of the database table to store the log messages. Defaults to "log". 96 | 97 | Creating a logger: 98 | 99 | ```php 100 | $logger = new \Yiisoft\Log\Logger([$dbTarget]); 101 | ``` 102 | 103 | You can use multiple databases to store log messages: 104 | 105 | ```php 106 | /** 107 | * @var \Yiisoft\Db\Connection\ConnectionInterface $mysqlDb 108 | * @var \Yiisoft\Db\Connection\ConnectionInterface $sqliteDb 109 | */ 110 | 111 | $logger = new \Yiisoft\Log\Logger([ 112 | new \Yiisoft\Log\Target\Db\DbTarget($mysqlDb), 113 | new \Yiisoft\Log\Target\Db\DbTarget($sqliteDb), 114 | ]); 115 | ``` 116 | 117 | ## Documentation 118 | 119 | For a description of using the logger, see the [yiisoft/log](https://github.com/yiisoft/log) package. 120 | 121 | - [Yii guide to logging](https://github.com/yiisoft/docs/blob/master/guide/en/runtime/logging.md) 122 | - [Internals](docs/internals.md) 123 | 124 | If you need help or have a question, the [Yii Forum](https://forum.yiiframework.com/c/yii-3-0/63) is a good place for that. 125 | You may also check out other [Yii Community Resources](https://www.yiiframework.com/community). 126 | 127 | ## License 128 | 129 | The Yii Logging Library - DB Target is free software. It is released under the terms of the BSD License. 130 | Please see [`LICENSE`](./LICENSE.md) for more information. 131 | 132 | Maintained by [Yii Software](https://www.yiiframework.com/). 133 | 134 | ## Support the project 135 | 136 | [![Open Collective](https://img.shields.io/badge/Open%20Collective-sponsor-7eadf1?logo=open%20collective&logoColor=7eadf1&labelColor=555555)](https://opencollective.com/yiisoft) 137 | 138 | ## Follow updates 139 | 140 | [![Official website](https://img.shields.io/badge/Powered_by-Yii_Framework-green.svg?style=flat)](https://www.yiiframework.com/) 141 | [![Twitter](https://img.shields.io/badge/twitter-follow-1DA1F2?logo=twitter&logoColor=1DA1F2&labelColor=555555?style=flat)](https://twitter.com/yiiframework) 142 | [![Telegram](https://img.shields.io/badge/telegram-join-1DA1F2?style=flat&logo=telegram)](https://t.me/yii3en) 143 | [![Facebook](https://img.shields.io/badge/facebook-join-1DA1F2?style=flat&logo=facebook&logoColor=ffffff)](https://www.facebook.com/groups/yiitalk) 144 | [![Slack](https://img.shields.io/badge/slack-join-1DA1F2?style=flat&logo=slack)](https://yiiframework.com/go/slack) 145 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yiisoft/log-target-db", 3 | "type": "library", 4 | "description": "Yii Logging Library - DB Target", 5 | "keywords": [ 6 | "yii", 7 | "framework", 8 | "log", 9 | "logger" 10 | ], 11 | "homepage": "https://www.yiiframework.com/", 12 | "license": "BSD-3-Clause", 13 | "support": { 14 | "issues": "https://github.com/yiisoft/log-target-db/issues", 15 | "source": "https://github.com/yiisoft/log-target-db", 16 | "forum": "https://www.yiiframework.com/forum/", 17 | "wiki": "https://www.yiiframework.com/wiki/", 18 | "irc": "ircs://irc.libera.chat:6697/yii", 19 | "chat": "https://t.me/yii3en" 20 | }, 21 | "funding": [ 22 | { 23 | "type": "opencollective", 24 | "url": "https://opencollective.com/yiisoft" 25 | }, 26 | { 27 | "type": "github", 28 | "url": "https://github.com/sponsors/yiisoft" 29 | } 30 | ], 31 | "require": { 32 | "php": "^8.0", 33 | "ext-pdo": "*", 34 | "psr/log": "^3.0", 35 | "yiisoft/db": "^1.0", 36 | "yiisoft/log": "^2.0" 37 | }, 38 | "require-dev": { 39 | "maglnet/composer-require-checker": "^4.2", 40 | "phpunit/phpunit": "^9.6|^10.1", 41 | "rector/rector": "^2.0.3", 42 | "roave/infection-static-analysis-plugin": "^1.25|^1.29", 43 | "spatie/phpunit-watcher": "^1.23", 44 | "vimeo/psalm": "^4.8|^5.8", 45 | "yiisoft/cache": "^3.0" 46 | }, 47 | "autoload": { 48 | "psr-4": { 49 | "Yiisoft\\Log\\Target\\Db\\": "src" 50 | } 51 | }, 52 | "autoload-dev": { 53 | "psr-4": { 54 | "Yiisoft\\Log\\Target\\Db\\Tests\\": "tests" 55 | } 56 | }, 57 | "config": { 58 | "sort-packages": true, 59 | "allow-plugins": { 60 | "infection/extension-installer": true, 61 | "composer/package-versions-deprecated": true 62 | } 63 | }, 64 | "scripts": { 65 | "test": "phpunit --testdox --no-interaction", 66 | "test-watch": "phpunit-watcher watch" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /rector.php: -------------------------------------------------------------------------------- 1 | paths([ 11 | __DIR__ . '/src', 12 | __DIR__ . '/tests', 13 | ]); 14 | 15 | // register a single rule 16 | $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class); 17 | 18 | // define sets of rules 19 | $rectorConfig->sets([ 20 | LevelSetList::UP_TO_PHP_80, 21 | ]); 22 | }; 23 | -------------------------------------------------------------------------------- /sql/mysql-down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE `yii_log`; 2 | -------------------------------------------------------------------------------- /sql/mysql-up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `yii_log` ( 2 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 3 | `level` varchar(16), 4 | `category` varchar(255), 5 | `log_time` timestamp(6) DEFAULT CURRENT_TIMESTAMP(6), 6 | `message` text, 7 | CONSTRAINT `PK_yii_log` PRIMARY KEY (`id`) 8 | ); 9 | CREATE INDEX `IDX_yii_log-category` ON `yii_log` (`category`); 10 | CREATE INDEX `IDX_yii_log-level` ON `yii_log` (`level`); 11 | CREATE INDEX `IDX_yii_log-time` ON `yii_log` (`log_time`); 12 | -------------------------------------------------------------------------------- /sql/oci-down.sql: -------------------------------------------------------------------------------- 1 | /* STATEMENTS */ 2 | DROP TRIGGER "yii_log_TRG"; 3 | DROP SEQUENCE "yii_log_SEQ"; 4 | DROP TABLE "yii_log"; 5 | -------------------------------------------------------------------------------- /sql/oci-up.sql: -------------------------------------------------------------------------------- 1 | /* STATEMENTS */ 2 | CREATE TABLE "yii_log" ( 3 | "id" NUMBER(20) NOT NULL, 4 | "level" VARCHAR2(16), 5 | "category" VARCHAR2(255), 6 | "log_time" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, 7 | "message" CLOB, 8 | CONSTRAINT "PK_yii_log" PRIMARY KEY ("id") 9 | ); 10 | CREATE SEQUENCE "yii_log_SEQ" START WITH 1 INCREMENT BY 1 NOMAXVALUE; 11 | CREATE INDEX "IDX_yii_log-category" ON "yii_log" ("category"); 12 | CREATE INDEX "IDX_yii_log-level" ON "yii_log" ("level"); 13 | CREATE INDEX "IDX_yii_log-time" ON "yii_log" ("log_time"); 14 | 15 | /* TRIGGERS */ 16 | CREATE TRIGGER "yii_log_TRG" BEFORE INSERT ON "yii_log" FOR EACH ROW BEGIN <> BEGIN 17 | IF INSERTING AND :NEW."id" IS NULL THEN SELECT "yii_log_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; 18 | END COLUMN_SEQUENCES; 19 | END; 20 | / 21 | -------------------------------------------------------------------------------- /sql/pgsql-down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE "yii_log"; 2 | -------------------------------------------------------------------------------- /sql/pgsql-up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE "yii_log" ( 2 | "id" BIGSERIAL NOT NULL, 3 | "level" varchar(16), 4 | "category" varchar(255), 5 | "log_time" timestamp(6) DEFAULT CURRENT_TIMESTAMP, 6 | "message" text, 7 | CONSTRAINT "PK_yii_log" PRIMARY KEY ("id") 8 | ); 9 | CREATE INDEX "IDX_yii_log-category" ON "yii_log" ("category"); 10 | CREATE INDEX "IDX_yii_log-level" ON "yii_log" ("level"); 11 | CREATE INDEX "IDX_yii_log-time" ON "yii_log" ("log_time"); 12 | -------------------------------------------------------------------------------- /sql/sqlite-down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE `yii_log`; 2 | -------------------------------------------------------------------------------- /sql/sqlite-up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `yii_log` ( 2 | `id` integer, 3 | `level` varchar(16), 4 | `category` varchar(255), 5 | `log_time` timestamp DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW', 'UTC')), 6 | `message` text, 7 | CONSTRAINT `PK_yii_log` PRIMARY KEY (`id`) 8 | ); 9 | CREATE INDEX `IDX_yii_log-category` ON `yii_log` (`category`); 10 | CREATE INDEX `IDX_yii_log-level` ON `yii_log` (`level`); 11 | CREATE INDEX `IDX_yii_log-time` ON `yii_log` (`log_time`); 12 | -------------------------------------------------------------------------------- /sql/sqlsrv-down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE [yii_log]; 2 | -------------------------------------------------------------------------------- /sql/sqlsrv-up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [yii_log] ( 2 | [id] bigint NOT NULL IDENTITY, 3 | [level] nvarchar(16), 4 | [category] nvarchar(255), 5 | [log_time] DATETIME2(6) DEFAULT CURRENT_TIMESTAMP, 6 | [message] nvarchar(max), 7 | CONSTRAINT [PK_yii_log] PRIMARY KEY ([id]) 8 | ); 9 | CREATE INDEX [IDX_yii_log-category] ON [yii_log] ([category]); 10 | CREATE INDEX [IDX_yii_log-level] ON [yii_log] ([level]); 11 | CREATE INDEX [IDX_yii_log-time] ON [yii_log] ([log_time]); 12 | -------------------------------------------------------------------------------- /src/DbSchemaManager.php: -------------------------------------------------------------------------------- 1 | db->getDriverName(); 39 | $schema = $this->db->getSchema(); 40 | $tableRawName = $schema->getRawTableName($table); 41 | 42 | if ($this->hasTable($table)) { 43 | return; 44 | } 45 | 46 | // `log_Time` Default value custom for all dbms 47 | $defaultValue = match ($driverName) { 48 | 'mysql' => new Expression('CURRENT_TIMESTAMP(6)'), 49 | 'sqlite' => new Expression("(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW', 'UTC'))"), 50 | default => new Expression('CURRENT_TIMESTAMP'), 51 | }; 52 | 53 | // `log_Time` Type custom for all dbms 54 | $logTimeType = match ($driverName) { 55 | 'sqlsrv' => $schema->createColumn('DATETIME2(6)')->defaultValue($defaultValue), 56 | default => $schema->createColumn(SchemaInterface::TYPE_TIMESTAMP, 6)->defaultValue($defaultValue), 57 | }; 58 | 59 | // `id` AutoIncrement custom for all dbms 60 | $id = match ($driverName) { 61 | 'mysql' => $schema->createColumn(SchemaInterface::TYPE_BIGINT)->notNull()->append('AUTO_INCREMENT'), 62 | 'pgsql' => $schema->createColumn('BIGSERIAL')->notNull(), 63 | 'sqlsrv' => $schema->createColumn(SchemaInterface::TYPE_BIGINT)->notNull()->append('IDENTITY'), 64 | default => $schema->createColumn(SchemaInterface::TYPE_INTEGER)->notNull(), 65 | }; 66 | 67 | // create table 68 | $this->db->createCommand()->createTable( 69 | $table, 70 | [ 71 | 'id' => $id, 72 | 'level' => $schema->createColumn(SchemaInterface::TYPE_STRING, 16), 73 | 'category' => $schema->createColumn(SchemaInterface::TYPE_STRING), 74 | 'log_time' => $logTimeType, 75 | 'message' => $schema->createColumn(SchemaInterface::TYPE_TEXT), 76 | "CONSTRAINT [[PK_$tableRawName]] PRIMARY KEY ([[id]])", 77 | ], 78 | )->execute(); 79 | 80 | if ($driverName === 'oci') { 81 | $this->addSequenceAndTrigger($tableRawName); 82 | } 83 | 84 | $this->db->createCommand()->createIndex($table, "IDX_{$tableRawName}-category", 'category')->execute(); 85 | $this->db->createCommand()->createIndex($table, "IDX_{$tableRawName}-level", 'level')->execute(); 86 | $this->db->createCommand()->createIndex($table, "IDX_{$tableRawName}-time", 'log_time')->execute(); 87 | } 88 | 89 | /** 90 | * Ensures that the log table does not exist in the database. 91 | * 92 | * @param string $table The name of the log table. Defaults to '{{%yii_log}}'. 93 | * 94 | * @throws Exception 95 | * @throws InvalidConfigException 96 | * @throws Throwable 97 | */ 98 | public function ensureNoTable(string $table = '{{%yii_log}}'): void 99 | { 100 | $schema = $this->db->getSchema(); 101 | $tableRawName = $schema->getRawTableName($table); 102 | 103 | // drop table 104 | if ($this->db->getTableSchema($table, true) !== null) { 105 | $this->db->createCommand()->dropTable($tableRawName)->execute(); 106 | 107 | // drop sequence oracle 108 | if ($this->db->getDriverName() === 'oci') { 109 | $this->db 110 | ->createCommand() 111 | ->setSql( 112 | <<execute(); 117 | } 118 | } 119 | } 120 | 121 | /** 122 | * @throws Exception 123 | * @throws Throwable 124 | */ 125 | private function addSequenceAndTrigger(string $tableRawName): void 126 | { 127 | // create sequence oracle 128 | $this->db 129 | ->createCommand() 130 | ->setSql( 131 | <<execute(); 139 | 140 | // create trigger oracle 141 | $this->db 142 | ->createCommand() 143 | ->setSql( 144 | <<> BEGIN 146 | IF INSERTING AND :NEW."id" IS NULL THEN SELECT {{{$tableRawName}_SEQ}}.NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; 147 | END COLUMN_SEQUENCES; 148 | END; 149 | SQL, 150 | ) 151 | ->execute(); 152 | } 153 | 154 | /** 155 | * Checks if the given table exists in the database. 156 | * 157 | * @param string $table The name of the table to check. 158 | * 159 | * @return bool Whether the table exists or not. 160 | */ 161 | private function hasTable(string $table): bool 162 | { 163 | return $this->db->getTableSchema($table, true) !== null; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/DbTarget.php: -------------------------------------------------------------------------------- 1 | db; 36 | } 37 | 38 | /** 39 | * Gets the name of the database table to store the log messages. 40 | */ 41 | public function getTable(): string 42 | { 43 | return $this->table; 44 | } 45 | 46 | /** 47 | * Stores log messages to the database. 48 | * 49 | * @throws RuntimeException If the log can't be exported. 50 | */ 51 | protected function export(): void 52 | { 53 | $formattedMessages = $this->getFormattedMessages(); 54 | $table = $this->db->getQuoter()->quoteTableName($this->table); 55 | 56 | try { 57 | $command = $this->db->createCommand(); 58 | 59 | foreach ($this->getMessages() as $key => $message) { 60 | /** @psalm-var mixed $logTime */ 61 | $logTime = $message->context('time'); 62 | $columns = [ 63 | 'level' => $message->level(), 64 | 'category' => $message->context('category', ''), 65 | 'log_time' => $logTime, 66 | 'message' => $formattedMessages[$key], 67 | ]; 68 | 69 | if ($logTime === null) { 70 | unset($columns['log_time']); 71 | } 72 | 73 | $command->insert($table, $columns)->execute(); 74 | } 75 | } catch (Throwable $e) { 76 | throw new RuntimeException($e->getMessage(), (int) $e->getCode(), $e); 77 | } 78 | } 79 | } 80 | --------------------------------------------------------------------------------