{"id":22702495,"url":"https://github.com/vielhuber/dbhelper","last_synced_at":"2025-04-13T08:40:46.077Z","repository":{"id":48007543,"uuid":"61498265","full_name":"vielhuber/dbhelper","owner":"vielhuber","description":"🍗 Small php wrapper for mysql/postgres/sqlite databases. 🍗","archived":false,"fork":false,"pushed_at":"2025-02-14T15:09:15.000Z","size":185,"stargazers_count":23,"open_issues_count":0,"forks_count":10,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-04T22:36:43.286Z","etag":null,"topics":["mysql","php","postgresql","sql","sqlite"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vielhuber.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-06-19T20:10:31.000Z","updated_at":"2025-02-14T15:09:17.000Z","dependencies_parsed_at":"2024-12-26T13:10:55.590Z","dependency_job_id":"3f3ed182-c99b-4e7e-b871-e0419cb671ed","html_url":"https://github.com/vielhuber/dbhelper","commit_stats":{"total_commits":165,"total_committers":1,"mean_commits":165.0,"dds":0.0,"last_synced_commit":"b019ce34e29346f720632f3100d762bf2d30bf0c"},"previous_names":[],"tags_count":125,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vielhuber%2Fdbhelper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vielhuber%2Fdbhelper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vielhuber%2Fdbhelper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vielhuber%2Fdbhelper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vielhuber","download_url":"https://codeload.github.com/vielhuber/dbhelper/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248686058,"owners_count":21145413,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mysql","php","postgresql","sql","sqlite"],"created_at":"2024-12-10T07:13:43.322Z","updated_at":"2025-04-13T08:40:46.054Z","avatar_url":"https://github.com/vielhuber.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![build status](https://github.com/vielhuber/dbhelper/actions/workflows/ci.yml/badge.svg)](https://github.com/vielhuber/dbhelper/actions)\n\n# 🍗 dbhelper 🍗\n\ndbhelper is a small php wrapper for mysql/postgres/sqlite databases.\n\n## installation\n\ninstall once with composer:\n\n```\ncomposer require vielhuber/dbhelper\n```\n\nthen add this to your project:\n\n```php\nrequire __DIR__ . '/vendor/autoload.php';\nuse vielhuber\\dbhelper\\dbhelper;\n$db = new dbhelper();\n```\n\n## usage\n\n```php\n/* connect to database */\n$db-\u003econnect('pdo', 'mysql', '127.0.0.1', 'username', 'password', 'database', 3306);\n$db-\u003econnect('pdo', 'postgres', '127.0.0.1', 'username', 'password', 'database', 5432);\n$db-\u003econnect('pdo', 'sqlite', 'database.db');\n$db-\u003econnect('pdo', 'sqlite', 'database.db', null, null, null, null, 120); // specify a manual timeout of 120 seconds\n$db-\u003econnect('pdo', 'mysql', '127.0.0.1', 'username', 'password', null, 3306); // database must not be available\n\n/* disconnect from database */\n$db-\u003edisconnect();\n\n/* insert/update/delete */\n$id = $db-\u003einsert('tablename', ['col1' =\u003e 'foo']);\n$db-\u003eupdate('tablename', ['col1' =\u003e 'bar'], ['id' =\u003e $id]);\n$db-\u003edelete('tablename', ['id' =\u003e $id]);\n\n/* select */\n$db-\u003efetch_all('SELECT * FROM tablename WHERE name = ? AND number \u003e ?', 'foo', 42);\n$db-\u003efetch_row('SELECT * FROM tablename WHERE ID = ?', 1);\n$db-\u003efetch_col('SELECT col FROM tablename WHERE ID \u003e ?', 1);\n$db-\u003efetch_var('SELECT col FROM tablename WHERE ID = ?', 1);\n\n/* count */\n$db-\u003ecount('tablename') // 42\n$db-\u003ecount('tablename', ['col1' =\u003e 'foo']) // 7\n\n/* automatic flattened arguments */\n$db-\u003efetch_all('SELECT * FROM tablename WHERE ID = ?', [1], 2, [3], [4,[5,6]]);\n// gets transformed to\n$db-\u003efetch_all('SELECT * FROM tablename WHERE ID = ?', 1, 2, 3, 4, 5, 6);\n\n/* automatic in-expansion */\n$db-\u003efetch_all('SELECT * FROM tablename WHERE col1 = ? AND col2 IN (?)', 1, [2,3,4]);\n\n/* support for null values */\n$db-\u003equery('UPDATE tablename SET col1 = ? WHERE col2 = ? AND col3 != ?', null, null, null);\n// gets transformed to\n$db-\u003equery('UPDATE tablename SET col1 = NULL WHERE col2 IS NULL AND col3 IS NOT NULL');\n\n/* clean up */\n$db-\u003eclear(); // delete all tables (without dropping the whole database)\n$db-\u003eclear('tablename'); // delete all rows in a table\n\n/* delete table */\n$db-\u003edelete_table('tablename');\n\n/* create table */\n$db-\u003ecreate_table('tablename', [\n    'id' =\u003e 'SERIAL PRIMARY KEY', // use INTEGER instead of SERIAL on sqlite to get auto ids\n    'col1' =\u003e 'varchar(255)',\n    'col2' =\u003e 'varchar(255)',\n    'col3' =\u003e 'varchar(255)'\n]);\n\n/* create if not exists and connect to database */\n$db-\u003econnect_with_create('pdo', 'mysql', '127.0.0.1', 'username', 'password', 'database', 3306);\n    // this is a shorthand for\n    $db-\u003econnect('pdo', 'mysql', '127.0.0.1', 'username', 'password', null, 3306);\n    $db-\u003ecreate_database('database');\n    $db-\u003edisconnect();\n    $db-\u003econnect('pdo', 'mysql', '127.0.0.1', 'username', 'password', 'database', 3306);\n\n/* delete database */\n$db-\u003edisconnect_with_delete();\n    // this is a shorthand for\n    $db-\u003edisconnect();\n    $db-\u003econnect('pdo', 'mysql', '127.0.0.1', 'username', 'password', null, 3306);\n    $db-\u003edelete_database('database');\n    $db-\u003edisconnect();\n\n/* raw queries */\n$db-\u003equery('INSERT INTO tablename(row1, row2) VALUES(?, ?, ?)', 1, 2, 3);\n$db-\u003equery('UPDATE tablename SET row1 = ? WHERE ID = ?', 1, 2);\n$db-\u003equery('DELETE FROM tablename WHERE ID = ?', 1);\n\n/* quickly debug raw queries */\n$db-\u003edebug('DELETE FROM tablename WHERE row1 = ?', null); // DELETE FROM tablename WHERE row1 IS NULL\n\n/* last insert id */\n$db-\u003einsert('tablename', ['col1' =\u003e 'foo']);\n$db-\u003elast_insert_id();\n\n/* some more little helpers */\n$db-\u003eget_tables() // ['tablename', ...]\n$db-\u003ehas_table('tablename') // true\n$db-\u003eget_columns('tablename') // ['col1', 'col2', ...]\n$db-\u003ehas_column('tablename', 'col1') // true\n$db-\u003eget_datatype('tablename', 'col1') // varchar\n$db-\u003eget_primary_key('tablename') // id\n$db-\u003euuid() // generate uuid (v4) from inside the database\n$db-\u003eget_foreign_keys('users') // [['address_id' =\u003e ['addresses','id'], ...]\n$db-\u003eis_foreign_key('users', 'address_id') // true\n$db-\u003eget_foreign_tables_out('users') // [['addresses' =\u003e [['address_id','id']], ...]\n$db-\u003eget_foreign_tables_in('addresses') // [['users' =\u003e [['address_id','id']], ...]\n\n/* handle duplicates */\n$db-\u003eget_duplicates() // ['count' =\u003e ['tbl1' =\u003e 3, 'tbl2' =\u003e 17], 'data' =\u003e ['tbl1' =\u003e [...], 'tbl2' =\u003e [...]]\n$db-\u003edelete_duplicates('tablename') // delete duplicates based on all columns except the primary key\n$db-\u003edelete_duplicates('tablename', ['common_col1','common_col1','common_col1']) // based on specific columns\n$db-\u003edelete_duplicates('tablename', ['common_col1','common_col1','common_col1'], false) // null values are considered equal by default; you can disable this untypical behaviour for sql with \"false\"\n$db-\u003edelete_duplicates('tablename', ['common_col1','common_col1','common_col1'], true, ['id' =\u003e 'asc']) // keep row with lowest primary key \"id\" (normally this is 'id' =\u003e 'desc')\n$db-\u003edelete_duplicates('tablename', ['common_col1','common_col1','common_col1'], true, ['id' =\u003e 'asc'], false) // case insensitive match (normally this is case sensitive)\n\n/* globally trim values */\n$db-\u003etrim_values() // [['table' =\u003e 'tbl1', 'column' =\u003e 'col1', 'id' =\u003e 1, 'before' =\u003e ' foo', 'after' =\u003e 'foo'], ...]\n$db-\u003etrim_values(false) // by default trim_values does a dry run (no updates)\n$db-\u003etrim_values(true) // do real updates\n$db-\u003etrim_values(false, ['table1', 'table2' =\u003e ['col1', 'col2']]) // ignore tables and columns\n\n/* batch functions (they create only one query) */\n$db-\u003einsert('tablename', [\n    ['id' =\u003e 1, 'name' =\u003e 'foo1'],\n    ['id' =\u003e 2, 'name' =\u003e 'foo2'],\n    ['id' =\u003e 3, 'name' =\u003e 'foo3']\n]);\n$db-\u003edelete('tablename', [\n    ['id' =\u003e 1],\n    ['id' =\u003e 7],\n    ['id' =\u003e 42]\n]);\n$db-\u003eupdate('tablename', [\n    [['col1' =\u003e 'var1', 'col2' =\u003e 1], ['id' =\u003e 1, 'key' =\u003e '1']],\n    [['col1' =\u003e 'var2', 'col2' =\u003e 2], ['id' =\u003e 2, 'key' =\u003e '2']],\n    [['col1' =\u003e 'var3', 'col2' =\u003e 3], ['id' =\u003e 3, 'key' =\u003e '3']]\n]);\n/*\nthis generates the following query:\nUPDATE tablename SET\ncol1 = CASE WHEN (id = 1 AND key = '1') THEN 'var1' WHEN (id = 2 AND key = '2') THEN 'var2' WHEN (id = 3 AND key = '3') THEN 'var3' END,\ncol2 = CASE WHEN (id = 1 AND key = '1') THEN 1 WHEN (id = 2 AND key = '2') THEN 2 WHEN (id = 3 AND key = '3') THEN 3 END\nWHERE id IN (1,2,3) AND key IN ('1','2','3');\n*/\n```\n\n### logging\n\ndbhelper can support setting up a mature logging system on mysql/postgres databases.\n\n```php\n$db = new dbhelper([\n    'logging_table' =\u003e 'logs',\n    'exclude' =\u003e [\n        'tables' =\u003e ['table1'],\n        'columns' =\u003e ['table2' =\u003e ['col1', 'col2', 'col3']]\n    ],\n    'delete_older' =\u003e 12, // months\n    'updated_by' =\u003e get_current_user_id()\n]);\n$db-\u003econnect('...');\n$db-\u003esetup_logging();\n```\n\n`setup_logging()` does four things:\n\n-   it creates a logging table (if not exists)\n-   it appends a single column `updated_by` to every table in the database (if not exists)\n-   it creates triggers for all insert/update/delete events (if not exists)\n-   it deletes old logging entries based on the `delete_older` option\n\nyou should run this method after a schema change (e.g. in your migrations) and you can also run it on a daily basis via cron. it is recommened to exclude blob/bytea columns.\n\nthe logging table has the following schema:\n\n-   `id`: unique identifier of that single change\n-   `log_event`: insert/update/delete\n-   `log_table`: name of the table of the modified row\n-   `log_key`: key of the modified row\n-   `log_column`: column of the modified row\n-   `log_value`: value of the modified row\n-   `log_uuid`: unique identifier of that row change\n-   `updated_by`: who did make that change\n-   `updated_at`: date and time of the event\n\nwe now have to adjust our queries. `updated_by` must be populated by the web application on all insert/update queries and our logging table must be manually populated before delete queries:\n\n```php\n$db-\u003einsert('tablename', ['col1' =\u003e 'foo', 'updated_by' =\u003e get_current_user_id()]);\n\n$db-\u003eupdate('tablename', ['col1' =\u003e 'foo', 'updated_by' =\u003e get_current_user_id()], ['id' =\u003e 42]);\n\n$db-\u003einsert('logs', [\n    'log_event' =\u003e 'delete',\n    'log_table' =\u003e 'tablename',\n    'log_key' =\u003e 42,\n    'log_uuid' =\u003e $db-\u003euuid(),\n    'updated_by' =\u003e get_current_user_id()\n]);\n$db-\u003edelete('tablename', ['id' =\u003e 42]);\n```\n\ninstead of all this we can let dbhelper magically do the heavy lifting on every insert/update/delete for us:\n\n```php\n$db-\u003eenable_auto_inject();\n```\n\ndbhelper then automatically injects the `updated_by` column on all insert/update statements and inserts a log entry before every delete query (all queries are handled, even those who are sent with `$db-\u003equery`).\n\nimportant note: if we manipulate data outside of our web application, the triggers also work, except with accurate values in `updated_by`. this is especially true for delete statements (they also work without the manual insert query upfront).\n\ncall the following helper functions, if you (temporarily) need to disable logging by triggers:\n\n```php\n$db-\u003edisable_logging();\n$db-\u003equery('DELETE * FROM mega_big_table');\n$db-\u003eenable_logging();\n```\n\nthat's it – happy logging.\n\n### wordpress support\n\nthis also works for wordpress (using wpdb, prepared statements and stripslashes_deep under the hood):\n\n```php\n$db-\u003econnect('wordpress');\n$db-\u003efetch_var('SELECT col FROM tablename WHERE ID = ?', 1);\n```\n\n### locking in sqlite\n\nsqlite is nice but database locking can be tricky.\\\ndbhelper provides a default timeout of `60` seconds, which prevents most database locks.\\\nyou can manually define a timeout in the `connect()` function.\\\ncheckout the following sqlite lock tests:\n\n-   `php tests/lock/run.php 1`: runs into database locking\n-   `php tests/lock/run.php 120`: does not run into database locking\n\nalso consider enabling [wal](https://sqlite.org/wal.html) via `$db-\u003equery('PRAGMA journal_mode=WAL;');`.\n\n### return values\n\nas return values after fetching results dbhelper usually returns associative arrays.\\\nif you use it with wordpress, objects are returned.\\\ndbhelper throws exceptions on all occured errors.\\\non an `insert` operation, the primary key (id) is returned.\\\non any `delete`, `update` or even `query` operation, the number of affected rows are returned.\n\n### static version\n\nhere is also a static version with static function calls (this makes sense, if you use a single instance of dbhelper):\n\n```php\n$db = new dbhelper();\nrequire_once $_SERVER['DOCUMENT_ROOT'] . '/vendor/vielhuber/dbhelper/src/static.php';\ndb_connect('pdo', 'mysql', '127.0.0.1', 'username', 'password', 'database', 3306);\ndb_fetch_var('SELECT col FROM tablename WHERE ID = ?', 1);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvielhuber%2Fdbhelper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvielhuber%2Fdbhelper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvielhuber%2Fdbhelper/lists"}