:gem: Simple MySQLi Abstraction Layer + Doctrine/DBAL support

Overview

Build Status FOSSA Status Coverage Status Codacy Badge Latest Stable Version Total Downloads License Donate to this project using Paypal Donate to this project using Patreon

💎 Simple MySQLi Class

This is a simple MySQL Abstraction Layer compatible with PHP 7+ that provides a simple and secure interaction with your database using mysqli_* functions at its core. This is perfect for small scale applications such as cron jobs, facebook canvas campaigns or micro frameworks or sites.

You can also use the 💍 "Simple Active Record"-class, it's based on this db class and add some OOP syntax. But please inform you about "Active Record" vs "Data Mapper" before you use it.

Get "Simple MySQLi"

You can download it from here, or require it using composer.

  {
      "require": {
        "voku/simple-mysqli": "8.*"
      }
  }

Install via "composer require"

  composer require voku/simple-mysqli

Starting the driver

  use voku\db\DB;

  require_once 'composer/autoload.php';

  $db = DB::getInstance('yourDbHost', 'yourDbUser', 'yourDbPassword', 'yourDbName');
  
  // example
  // $db = DB::getInstance('localhost', 'root', '', 'test');

Multiton && Singleton

You can use DB::getInstance() without any parameters and you will get your (as "singleton") first initialized connection. Or you can change the parameter and you will create an new "multiton"-instance which works like an singleton, but you need to use the same parameters again, otherwise (without the same parameter) you will get an new instance.

Doctrine/DBAL as parent driver

  use voku\db\DB;

  require_once 'composer/autoload.php';
  
  $connectionParams = [
      'dbname'   => 'yourDbName',
      'user'     => 'yourDbUser',
      'password' => 'yourDbPassword',
      'host'     => 'yourDbHost',
      'driver'   => 'mysqli', // 'pdo_mysql' || 'mysqli'
      'charset'  => 'utf8mb4',
  ];
  $config = new \Doctrine\DBAL\Configuration();
  $doctrineConnection = \Doctrine\DBAL\DriverManager::getConnection(
      $connectionParams,
      $config
  );
  $doctrineConnection->connect();

  $db = DB::getInstanceDoctrineHelper($doctrineConnection);

Using the "DB"-Class

There are numerous ways of using this library, here are some examples of the most common methods.

Selecting and retrieving data from a table

  use voku\db\DB;
  
  $db = DB::getInstance();
  
  $result = $db->query("SELECT * FROM users");
  $users  = $result->fetchAll();

But you can also use a method for select-queries:

  $db->select(string $table, array $where); // generate an SELECT query

Example: SELECT

  $where = [
      'page_type ='         => 'article',
      'page_type NOT LIKE'  => '%öäü123',
      'page_id >='          => 2,
  ];
  $articles = $db->select('page', $where);
  
  echo 'There are ' . count($articles) . ' article(s):' . PHP_EOL;
  
  foreach ($articles as $article) {
      echo 'Type: ' . $article['page_type'] . PHP_EOL;
      echo 'ID: ' . $article['page_id'] . PHP_EOL;
  }

Here is a list of connectors for the "WHERE"-array: 'NOT', 'IS', 'IS NOT', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'LIKE', 'NOT LIKE', '>', '<', '>=', '<=', '<>', '+', '-'

INFO: use an array as $value for "[NOT] IN" and "[NOT] BETWEEN"

INFO: use + / - in the value not in the key of the $data

Example: UPDATE with "page_template = page_template + 1"

  $where = [
      'page_type LIKE'     => '%foo',
      'page_type NOT LIKE' => 'bar',
  ];
  $data = [
      'page_template' => ['page_template +' => 1],
      'page_type'     => 'lall',
  ];
  $resultSelect = $db->update('page', $data, $where);

Example: SELECT with "NOT IN"

  $where = [
      'page_type NOT IN' => [
          'foo',
          'bar'
      ],
      'page_id >'        => 2,
  ];
  $resultSelect = $db->select('page', $where);

Example: SELECT with Cache

  $resultSelect = $db->execSQL("SELECT * FROM users", true, 3600);

The result (via $result->fetchAllArray()) is only cached for 3600s when the query was a SELECT statement, otherwise you get the default result from the $db->query() function.

Inserting data on a table

to manipulate tables you have the most important methods wrapped, they all work the same way: parsing arrays of key/value pairs and forming a safe query

the methods are:

  $db->insert( string $table, array $data );                // generate an INSERT query
  $db->replace( string $table, array $data );               // generate an REPLACE query
  $db->update( string $table, array $data, array $where );  // generate an UPDATE query
  $db->delete( string $table, array $where );               // generate a DELETE query

All methods will return the resulting mysqli_insert_id() or true/false depending on context. The correct approach if to always check if they executed as success is always returned

Example: DELETE

  $deleteArray = ['user_id' => 9];
  $ok = $db->delete('users', $deleteArray);
  if ($ok) {
    echo "user deleted!";
  } else {
    echo "can't delete user!";
  }

note: all parameter values are sanitized before execution, you don't have to escape values beforehand.

Example: INSERT

  $insertArray = [
    'name'   => "John",
    'email'  => "[email protected]",
    'group'  => 1,
    'active' => true,
  ];
  $newUserId = $db->insert('users', $insertArray);
  if ($newUserId) {
    echo "new user inserted with the id $new_user_id";
  }

Example: REPLACE

  $replaceArray = [
      'name'   => 'lars',
      'email'  => '[email protected]',
      'group'  => 0
  ];
  $tmpId = $db->replace('users', $replaceArray);

Binding parameters on queries

Binding parameters is a good way of preventing mysql injections as the parameters are sanitized before execution.

  $sql = "SELECT * FROM users 
    WHERE id_user = :id_user
    AND active = :active
    LIMIT 1
  ";
  $result = $db->query($sql, ['id_user' => 11, 'active' => 1]);
  if ($result) {
    $user = $result->fetchArray();
    print_r($user);
  } else {
    echo "user not found";
  }

Transactions

Use begin(), commit(), and rollback() to manage transactions:

$db->beginTransaction();

$db->query(
    'UPDATE `users` SET `foo` = :foo WHERE id = :id',
    ['foo' => 100, 'id' => 1]
);
$db->query(
    'UPDATE `users_noop` SET `foo` = :foo WHERE id = :id',
    ['foo' => 100, 'id' => 2]
);

$db->endTransaction();

Any SQL errors between begin() and commit() will yield a RuntimeException.

You can also use the DB->transact() method. The following is equivalent to the above:

$db->transact(function($db) {
    $db->query(
        'UPDATE `users` SET `foo` = :foo WHERE id = :id',
        ['foo' => 100, 'id' => 1]
    );
    $db->query(
        'UPDATE `users_noop` SET `foo` = :foo WHERE id = :id',
        ['foo' => 100, 'id' => 2]
    );
});

Using the "Result"-Class

After executing a SELECT query you receive a Result object that will help you manipulate the resultant data. there are different ways of accessing this data, check the examples bellow:

Fetching all data

  $result = $db->query("SELECT * FROM users");
  $allUsers = $result->fetchAll();

Fetching all data works as Result::RESULT_TYPE_* the fetchAll() and fetch() method will return the default based on the $_default_result_type config. Other methods are:

  $row = $result->fetch();        // fetch an single result row as defined by the config (array, object or Arrayy)
  $row = $result->fetchArray();   // fetch an single result row as array
  $row = $result->fetchArrayy();  // fetch an single result row as Arrayy object
  $row = $result->fetchObject();  // fetch an single result row as object
  $row = $result->fetchYield();   // fetch an single result row as Generator
  
  $data = $result->fetchAll();        // fetch all result data as defined by the config (array, object or Arrayy)
  $data = $result->fetchAllArray();   // fetch all result data as array
  $data = $result->fetchAllArrayy();  // fetch all result data as Array object
  $data = $result->fetchAllObject();  // fetch all result data as object
  $data = $result->fetchAllYield();   // fetch all result data as Generator
  
  $data = $result->fetchColumn(string $column, bool $skipNullValues);    // fetch a single column as string
  $data = $result->fetchAllColumn(string $column, bool $skipNullValues); // fetch a single column as an 1-dimension array
  
  $data = $result->fetchArrayPair(string $key, string $value);           // fetch data as a key/value pair array

Fetching database-table-fields

Returns rows of field information in a result set:

$fields = $result->fetchFields();

Pass true as argument if you want each field information returned as an associative array instead of an object. The default is to return each as an object, exactly like the mysqli_fetch_fields function.

Fetching + Callable

Fetches a row or a single column within a row:

$data = $result->fetch($row_number, $column);

This method forms the basis of all fetch_ methods. All forms of fetch_ advances the internal row pointer to the next row. null will be returned when there are no more rows to be fetched.

Fetching + Transpose

Returns all rows at once, transposed as an array of arrays:

$plan_details = $plans->fetchTranspose();

Transposing a result set of X rows each with Y columns will result in an array of Y rows each with X columns.

Pass a column name as argument to return each column as an associative array with keys taken from values of the provided column. If not provided, the keys will be numeric starting from zero.

e.g.:

$transposedExample = [
  'title' => [
    1 => 'Title #1',
    2 => 'Title #2',
    3 => 'Title #3',
  ],
);

Fetching + Pairs

Returns all rows at once as key-value pairs using the column in the first argument as the key:

$countries = $result->fetchPairs('id');

Pass a column name as the second argument to only return a single column as the value in each pair:

$countries = $result->fetchPairs('id', 'name');

/*
[
  1 => 'Title #1',
  2 => 'Title #2',
  3 => 'Title #3',
]
*/

Fetching + Groups

Returns all rows at once as a grouped array:

$students_grouped_by_gender = $result->fetchGroups('gender');

Pass a column name as the second argument to only return single columns as the values in each groups:

$student_names_grouped_by_gender = $result->fetchGroups('gender', 'name');

Fetching + first

Returns the first row element from the result:

$first = $result->first();

Pass a column name as argument to return a single column from the first row:

$name = $result->first('name');

Fetching + last

Returns the last row element from the result:

$last = $result->last();

Pass a column name as argument to return a single column from the last row:

$name = $result->last('name');

Fetching + slice

Returns a slice of rows from the result:

$slice = $result->slice(1, 10);

The above will return 10 rows skipping the first one. The first parameter is the zero-based offset; the second parameter is the number of elements; the third parameter is a boolean value to indicate whether to preserve the keys or not (optional and defaults to false). This methods essentially behaves the same as PHP's built-in array_slice() function.

Fetching + map

Sets a mapper callback function that's used inside the Result->fetchCallable() method:

$result->map(function($row) {
    return (object) $row;
});
$object = $result->fetchCallable(0);

The above example will map one row (0) from the result into a object. Set the mapper callback function to null to disable it.

Fetching + aliases

  $db->get()                  // alias for $db->fetch();
  $db->getAll()               // alias for $db->fetchAll();
  $db->getObject()            // alias for $db->fetchAllObject();
  $db->getArray()             // alias for $db->fetchAllArray();
  $db->getArrayy()            // alias for $db->fetchAllArrayy();
  $db->getYield()             // alias for $db->fetchAllYield();
  $db->getColumn($key)        // alias for $db->fetchColumn($key);

Fetching + Iterations

To iterate a result-set you can use any fetch() method listed above.

  $result = $db->select('users');

  // using while
  while ($row = $result->fetch()) {
    echo $row->name;
    echo $row->email;
  }

  // using foreach (via "fetchAllObject()")
  foreach($result->fetchAllObject() as $row) {
    echo $row->name;
    echo $row->email;
  }
  
  // using foreach (via "Result"-object)
  foreach($result as $row) {
    echo $row->name;
    echo $row->email;
  }
  
  // using foreach (via "Generator"-object)
  foreach($result->fetchAllYield() as $row) {
    echo $row->name;
    echo $row->email;
  }
  
  // INFO: "while + fetch()" and "fetchAllYield()" will use less memory that "foreach + "fetchAllObject()", because we will fetch each result entry seperatly

Executing Multi Queries

To execute multiple queries you can use the $db->multi_query() method. You can use multiple queries separated by ";".

Return-Types:

  • "Result"-Array by "SELECT"-queries
  • "bool" by only "INSERT"-queries
  • "bool" by only (affected_rows) by "UPDATE / DELETE"-queries
  • "bool" by only by e.g. "DROP"-queries

e.g.:

$sql = "
    INSERT INTO foo
      SET
        page_template = 'lall1',
        page_type = 'test1';
    INSERT INTO lall
      SET
        page_template = 'lall2',
        page_type = 'test2';
    INSERT INTO bar
      SET
        page_template = 'lall3',
        page_type = 'test3';
";
$result = $this->db->multi_query($sql); // true

$sql = "
    SELECT * FROM foo;
    SELECT * FROM lall;
    SELECT * FROM bar;
";
$result = $this->db->multi_query($sql); // Result[]
foreach ($result as $resultForEach) {
    $tmpArray = $resultForEach->fetchArray();
    ...
}

Using the "Prepare"-Class

Prepare statements have the advantage that they are built together in the MySQL-Server, so the performance is better.

But the debugging is harder and logging is impossible (via PHP), so we added a wrapper for "bind_param" called "bind_param_debug". With this wrapper we pre-build the sql-query via php (only for debugging / logging). Now you can e.g. echo the query.

INFO: You can still use "bind_param" instead of "bind_param_debug", e.g. if you need better performance.

INSERT-Prepare-Query (example)

  use voku\db\DB;
  
  $db = DB::getInstance();
  
  // ------------- 
  // prepare the queries
  
  $query = 'INSERT INTO users
    SET 
      name = ?, 
      email = ?
  ';
  
  $prepare = $db->prepare($query);
  
  $name = '';
  $email = '';
  
  $prepare->bind_param_debug('ss', $name, $email);
  
  // -------------
  // execute query no. 1
  
  // INFO: "$template" and "$type" are references, since we use "bind_param" or "bind_param_debug" 
  $name = 'name_1_中';
  $email = '[email protected]';
  
  $prepare->execute();
  
  // DEBUG
  echo $prepare->get_sql_with_bound_parameters();
  
  // -------------
  // execute query no. 2
  
  // INFO: "$template" and "$type" are references, since we use "bind_param" or "bind_param_debug"  
  $name = 'Lars';
  $email = '[email protected]';
  
  $prepare->execute();
  
  // DEBUG
  echo $prepare->get_sql_with_bound_parameters();

SELECT-Prepare-Query (example)

  use voku\db\DB;
  
  $db = DB::getInstance();
  
  // -------------
  // insert some dummy-data, first
  
  $data = [
      'page_template' => 'tpl_test_new123123',
      'page_type'     => 'ö\'ä"ü',
  ];

  // will return the auto-increment value of the new row
  $resultInsert[1] = $db->insert($this->tableName, $data);
  $resultInsert[2] = $db->insert($this->tableName, $data);

  // ------------- 
  // prepare the queries

  $sql = 'SELECT * FROM ' . $this->tableName . ' 
    WHERE page_id = ?
  ';

  $prepare = $this->db->prepare($sql);
  $page_id = 0;
  $prepare->bind_param_debug('i', $page_id);

  // ------------- 
  // execute query no. 1

  $page_id = $resultInsert[1];
  $result = $prepare->execute();
  $data = $result->fetchArray();

  // $data['page_template'] === 'tpl_test_new123123'
  // $data['page_id'] === $page_id

  // ------------- 
  // execute query no. 2

  $page_id = $resultInsert[2];
  $result = $prepare->execute();
  $data = $result->fetchArray();

  // $data['page_id'] === $page_id
  // $data['page_template'] === 'tpl_test_new123123'

Logging and Errors

You can hook into the "DB"-Class, so you can use your personal "Logger"-Class. But you have to cover the methods:

$this->trace(string $text, string $name) { ... }
$this->debug(string $text, string $name) { ... }
$this->info(string $text, string $name) { ... }
$this->warn(string $text, string $name) { ... } 
$this->error(string $text, string $name) { ... }
$this->fatal(string $text, string $name) { ... }

You can also disable the logging of every sql-query, with the "getInstance()"-parameter "logger_level" from "DB"-Class. If you set "logger_level" to something other than "TRACE" or "DEBUG", the "DB"-Class will log only errors anymore.

DB::getInstance(
    getConfig('db', 'hostname'),        // hostname
    getConfig('db', 'username'),        // username
    getConfig('db', 'password'),        // password
    getConfig('db', 'database'),        // database
    getConfig('db', 'port'),            // port
    getConfig('db', 'charset'),         // charset
    true,                               // exit_on_error
    true,                               // echo_on_error
    'cms\Logger',                       // logger_class_name
    getConfig('logger', 'level'),       // logger_level | 'TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'
    getConfig('session', 'db')          // session_to_db
);

Showing the query log: The log comes with the SQL executed, the execution time and the result row count.

  print_r($db->log());

To debug mysql errors, use $db->errors() to fetch all errors (returns false if there are no errors) or $db->lastError() for information about the last error.

  if ($db->errors()) {
    echo $db->lastError();
  }

But the easiest way for debugging is to configure "DB"-Class via "DB::getInstance()" to show errors and exit on error (see the example above). Now you can see SQL-errors in your browser if you are working on "localhost" or you can implement your own "checkForDev()" via a simple function, you don't need to extend the "Debug"-Class. If you will receive error-messages via e-mail, you can implement your own "mailToAdmin()"-function instead of extending the "Debug"-Class.

Changelog

See CHANGELOG.md.

Support

For support and donations please visit Github | Issues | PayPal | Patreon.

For status updates and release announcements please visit Releases | Twitter | Patreon.

For professional support please contact me.

Thanks

  • Thanks to GitHub (Microsoft) for hosting the code and a good infrastructure including Issues-Managment, etc.
  • Thanks to IntelliJ as they make the best IDEs for PHP and they gave me an open source license for PhpStorm!
  • Thanks to Travis CI for being the most awesome, easiest continous integration tool out there!
  • Thanks to StyleCI for the simple but powerfull code style check.
  • Thanks to PHPStan && Psalm for relly great Static analysis tools and for discover bugs in the code!

License

FOSSA Status

Comments
  • Update phpunit/phpunit requirement from ~6.0 to ~6.0 || ~7.0

    Update phpunit/phpunit requirement from ~6.0 to ~6.0 || ~7.0

    Updates the requirements on phpunit/phpunit to permit the latest version.

    Changelog

    Sourced from phpunit/phpunit's changelog.

    7.5.1 - 2018-12-12

    Fixed

    • Fixed #3441: Call to undefined method DataProviderTestSuite::usesDataProvider()

    [7.5.0] - 2018-12-07

    Added

    • Implemented #3340: Added assertEqualsCanonicalizing(), assertEqualsIgnoringCase(), assertEqualsWithDelta(), assertNotEqualsCanonicalizing(), assertNotEqualsIgnoringCase(), and assertNotEqualsWithDelta() as alternatives to using assertEquals() and assertNotEquals() with the $delta, $canonicalize, or $ignoreCase parameters
    • Implemented #3368: Added assertIsArray(), assertIsBool(), assertIsFloat(), assertIsInt(), assertIsNumeric(), assertIsObject(), assertIsResource(), assertIsString(), assertIsScalar(), assertIsCallable(), assertIsIterable(), assertIsNotArray(), assertIsNotBool(), assertIsNotFloat(), assertIsNotInt(), assertIsNotNumeric(), assertIsNotObject(), assertIsNotResource(), assertIsNotString(), assertIsNotScalar(), assertIsNotCallable(), assertIsNotIterable() as alternatives to assertInternalType() and assertNotInternalType()
    • Implemented #3391: Added a TestHook that fires after each test, regardless of result
    • Implemented #3417: Refinements related to test suite sorting and TestDox result printer
    • Implemented #3422: Added assertStringContainsString(), assertStringContainsStringIgnoringCase(), assertStringNotContainsString(), and assertStringNotContainsStringIgnoringCase()

    Deprecated

    • The methods assertInternalType() and assertNotInternalType() are now deprecated. There is no behavioral change in this version of PHPUnit. Using these methods will trigger a deprecation warning in PHPUnit 8 and in PHPUnit 9 these methods will be removed.
    • The methods assertAttributeContains(), assertAttributeNotContains(), assertAttributeContainsOnly(), assertAttributeNotContainsOnly(), assertAttributeCount(), assertAttributeNotCount(), assertAttributeEquals(), assertAttributeNotEquals(), assertAttributeEmpty(), assertAttributeNotEmpty(), assertAttributeGreaterThan(), assertAttributeGreaterThanOrEqual(), assertAttributeLessThan(), assertAttributeLessThanOrEqual(), assertAttributeSame(), assertAttributeNotSame(), assertAttributeInstanceOf(), assertAttributeNotInstanceOf(), assertAttributeInternalType(), assertAttributeNotInternalType(), attributeEqualTo(), readAttribute(), getStaticAttribute(), and getObjectAttribute() are now deprecated. There is no behavioral change in this version of PHPUnit. Using these methods will trigger a deprecation warning in PHPUnit 8 and in PHPUnit 9 these methods will be removed.
    • The optional parameters $delta, $maxDepth, $canonicalize, and $ignoreCase of assertEquals() and assertNotEquals() are now deprecated. There is no behavioral change in this version of PHPUnit. Using these parameters will trigger a deprecation warning in PHPUnit 8 and in PHPUnit 9 these parameters will be removed.
    • The annotations [**expectedException**](https://github.com/expectedException), [**expectedExceptionCode**](https://github.com/expectedExceptionCode), [**expectedExceptionMessage**](https://github.com/expectedExceptionMessage), and [**expectedExceptionMessageRegExp**](https://github.com/expectedExceptionMessageRegExp) are now deprecated. There is no behavioral change in this version of PHPUnit. Using these annotations will trigger a deprecation warning in PHPUnit 8 and in PHPUnit 9 these annotations will be removed.
    • Using the methods assertContains() and assertNotContains() on string haystacks is now deprecated. There is no behavioral change in this version of PHPUnit. Using these methods on string haystacks will trigger a deprecation warning in PHPUnit 8 and in PHPUnit 9 these methods cannot be used on on string haystacks anymore.
    • The optional parameters $ignoreCase, $checkForObjectIdentity, and $checkForNonObjectIdentity of assertContains() and assertNotContains() are now deprecated. There is no behavioral change in this version of PHPUnit. Using these parameters will trigger a deprecation warning in PHPUnit 8 and in PHPUnit 9 these parameters will be removed.

    Fixed

    • Fixed #3428: TestSuite setup failures are not logged correctly
    • Fixed #3429: Inefficient loop in getHookMethods()
    • Fixed #3437: JUnit logger skips PHPT tests

    [7.5.0]: https://github.com/sebastianbergmann/phpunit/compare/7.4.5...7.5.0

    Commits

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Note: This repo was added to Dependabot recently, so you'll receive a maximum of 5 PRs for your first few update runs. Once an update run creates fewer than 5 PRs we'll remove that limit.

    You can always request more updates by clicking Bump now in your Dependabot dashboard.

    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot ignore this [patch|minor|major] version will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language
    • @dependabot badge me will comment on this PR with code to add a "Dependabot enabled" badge to your readme

    Additionally, you can set the following in your Dependabot dashboard:

    • Update frequency (including time of day and day of week)
    • Automerge options (never/patch/minor, and dev/runtime dependencies)
    • Pull request limits (per update run and/or open at any time)
    • Out-of-range updates (receive only lockfile updates, if desired)
    • Security updates (receive only security updates, if desired)

    Finally, you can contact us by mentioning @dependabot.


    This change is Reviewable

    dependencies 
    opened by dependabot-preview[bot] 7
  • "between" clause not working

    What is this feature about (expected vs actual behaviour)?

    I want to use BETWEEN on WHERE clause but I'm getting unexpected results. It's inserting parenthesis. Documentation doesn't give further explanations...

    How can I reproduce it?

    print_r($db->select('orc_lancamentos', ['id BETWEEN' => [100, 200]]));
    

    Does it take minutes, hours or days to fix?

    minutes

    Any additional information?

    RESULTANT QUERY:

    SELECT * FROM `orc_lancamentos` WHERE (  `id` BETWEEN (100 AND 200) 
    )
    
    opened by shuantsu 4
  • Is there a way to execute an SQL file/multiple queries at once ?

    Is there a way to execute an SQL file/multiple queries at once ?

    What is this feature about (expected vs actual behaviour)?

    Execute multiple updates/inserts queries inline or from a file (file_get_contents)

    How can I reproduce it?

    $db->query("INSERT INTO ......; INSERT INTO .....;");

    Does it take minutes, hours or days to fix?

    I think minutes. Just make ->query(..) execute as a block or add a function ->queries(...)

    Any additional information?

    wait for response 
    opened by redasakhi 4
  • Update phpunit/phpunit requirement from ~6.0 || ~7.0 to ~6.0 || ~7.0 || ~8.0

    Update phpunit/phpunit requirement from ~6.0 || ~7.0 to ~6.0 || ~7.0 || ~8.0

    Updates the requirements on phpunit/phpunit to permit the latest version.

    Changelog

    Sourced from phpunit/phpunit's changelog.

    8.0.1 - 2019-02-03

    Fixed

    • Fixed #3509: Process Isolation does not work with phpunit.phar

    [8.0.0] - 2019-02-01

    Changed

    • Implemented #3060: Cleanup PHPUnit\Framework\Constraint\Constraint
    • Implemented #3133: Enable dependency resolution by default
    • Implemented #3236: Define which parts of PHPUnit are covered by the backward compatibility promise
    • Implemented #3244: Enable result cache by default
    • Implemented #3288: The void_return fixer of php-cs-fixer is now in effect
    • Implemented #3439: Improve colorization of TestDox output
    • Implemented #3444: Consider data provider that provides data with duplicate keys to be invalid
    • Implemented #3467: Code location hints for [**requires**](https://github.com/requires) annotations as well as --SKIPIF--, --EXPECT--, --EXPECTF--, --EXPECTREGEX--, and --{SECTION}_EXTERNAL-- sections of PHPT tests
    • Implemented #3481: Improved --help output

    Deprecated

    • Implemented #3332: Deprecate annotation(s) for expecting exceptions
    • Implemented #3338: Deprecate assertions (and helper methods) that operate on (non-public) attributes
    • Implemented #3341: Deprecate optional parameters of assertEquals() and assertNotEquals()
    • Implemented #3369: Deprecate assertInternalType() and assertNotInternalType()
    • Implemented #3388: Deprecate the TestListener interface
    • Implemented #3425: Deprecate optional parameters of assertContains() and assertNotContains() as well as using these methods with string haystacks
    • Implemented #3494: Deprecate assertArraySubset()

    Removed

    • Implemented #2762: Drop support for PHP 7.1
    • Implemented #3123: Remove PHPUnit_Framework_MockObject_MockObject

    [8.0.0]: https://github.com/sebastianbergmann/phpunit/compare/7.5...8.0.0

    Commits

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot ignore this [patch|minor|major] version will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language
    • @dependabot badge me will comment on this PR with code to add a "Dependabot enabled" badge to your readme

    Additionally, you can set the following in your Dependabot dashboard:

    • Update frequency (including time of day and day of week)
    • Automerge options (never/patch/minor, and dev/runtime dependencies)
    • Pull request limits (per update run and/or open at any time)
    • Out-of-range updates (receive only lockfile updates, if desired)
    • Security updates (receive only security updates, if desired)

    Finally, you can contact us by mentioning @dependabot.


    This change is Reviewable

    dependencies 
    opened by dependabot-preview[bot] 4
  • PHP 8 and open_basedir related changes

    PHP 8 and open_basedir related changes

    • function get_magic_quotes_gpc() was removed in PHP v8
    • is_readable always throws an notice if used in conjunction with open_basedir

    This change is Reviewable

    opened by etlam 3
  • Add license scan report and status

    Add license scan report and status

    Your FOSSA integration was successful! Attached in this PR is a badge and license report to track scan status in your README.

    Below are docs for integrating FOSSA license checks into your CI:


    This change is Reviewable

    opened by fossabot 3
  • Upgrade to GitHub-native Dependabot

    Upgrade to GitHub-native Dependabot

    Dependabot Preview will be shut down on August 3rd, 2021. In order to keep getting Dependabot updates, please merge this PR and migrate to GitHub-native Dependabot before then.

    Dependabot has been fully integrated into GitHub, so you no longer have to install and manage a separate app. This pull request migrates your configuration from Dependabot.com to a config file, using the new syntax. When merged, we'll swap out dependabot-preview (me) for a new dependabot app, and you'll be all set!

    With this change, you'll now use the Dependabot page in GitHub, rather than the Dependabot dashboard, to monitor your version updates, and you'll configure Dependabot through the new config file rather than a UI.

    If you've got any questions or feedback for us, please let us know by creating an issue in the dependabot/dependabot-core repository.

    Learn more about migrating to GitHub-native Dependabot

    Please note that regular @dependabot commands do not work on this pull request.


    This change is Reviewable

    dependencies 
    opened by dependabot-preview[bot] 2
  • DB and Result classes are tied to a single implementation when using DBAL

    DB and Result classes are tied to a single implementation when using DBAL

    What is this feature about (expected vs actual behaviour)?

    DB class is tied to a specific \Doctrine\DBAL\Statement implementation when using DBAL as a parent connection.

    This makes it impossible to use with libraries like https://github.com/facile-it/doctrine-mysql-come-back impossible to use since they are wrapping DBAL connection, statement and some other classes with it's own implementation.

    For example if you look at src/voku/db/DB.php:L1891 you will see that it's checking if result is an instance of \Doctrine\DBAL\Statement. When using library above you get different implementation of Doctrine\DBAL\Driver\Statement interface.

    Does it take minutes, hours or days to fix?

    Not sure how big is the scope of this change would be but I am interested in writing up a PR for this if you are open to this change.

    enhancement 
    opened by iamthefox 2
  • Update voku/arrayy requirement from ~6.0 to ~6.0 || ~7.0

    Update voku/arrayy requirement from ~6.0 to ~6.0 || ~7.0

    Updates the requirements on voku/arrayy to permit the latest version.

    Changelog

    Sourced from voku/arrayy's changelog.

    7.0.0 (2019-12-13)

    • normalize $closure (value => key instead of key => value) for "forAll()"
    • normalize $closure (value => key instead of key => value) for "partition()"
    • rename "forAll()" into "validate()"
    • use "iterator_count()" if possible
    • add "nth()"
    • add "toPermutation()"

    6.1.1

    • fix phpstan (0.12) generic support

    6.1.0

    • use phpstan (0.12) generic support
    • split "InstanceCollection" into "InstancesCollection" && "InstanceCollection"

    6.0.0

    • instance of "InvalidArgumentException" we now use "TypeError" for type errors
    • add "Arrayy->checkPropertiesMismatch"
    • add pre-defined typified collections (TypeInterface)
    • merge type check from Arrayy & Collection
    • add "TypeCheckInterface"
    • fix type checks

    5.15.0

    • fix serialization of "Arrayy" + "Property" (Property !== instance of ReflectionProperty anymore)
    • fix for php 7.4 (ArrayObject use __serialize + __unserialize)

    5.14.2 (2019-10-06)

    • fix "Arrayy->keys()" -> use strict and non-strict comparision

    5.14.1 (2019-09-16)

    • optimize "array_last"-polyfill (php < 7.3)

    5.14.0 (2019-09-13)

    • add "Arrayy->diffKey" + "Arrayy->diffKeyAndValue"
    ... (truncated)
    Commits
    • 6f26bb5 [*]: update the changelog
    • 403adb9 Merge pull request #35 from voku/analysis-NA639E
    • f91736c Apply fixes from StyleCI
    • 5491510 [+]: refactoring and normalize the api + add tests
    • 095ad56 [*]: update the changelog
    • 980d95e [+]: try to use phpstan generics v3.2
    • e240c7f [*]: update the changelog
    • 848c0af [+]: try to use phpstan generics v3.1
    • c4c656f [+]: try to use phpstan generics v3
    • d91a6c4 [+]: try to use phpstan generics v2
    • Additional commits viewable in compare view

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language
    • @dependabot badge me will comment on this PR with code to add a "Dependabot enabled" badge to your readme

    Additionally, you can set the following in your Dependabot dashboard:

    • Update frequency (including time of day and day of week)
    • Pull request limits (per update run and/or open at any time)
    • Automerge options (never/patch/minor, and dev/runtime dependencies)
    • Out-of-range updates (receive only lockfile updates, if desired)
    • Security updates (receive only security updates, if desired)

    This change is Reviewable

    dependencies 
    opened by dependabot-preview[bot] 2
  • Fatal error in Helper when using PHP PHP 8.0.8

    Fatal error in Helper when using PHP PHP 8.0.8

    What is this feature about (expected vs actual behaviour)?

    \mysqli_get_server_version($mysqli_link) is causing Fatal error because mysqli_get_server_version() expects 0 arguments

    How can I reproduce it?

    just run it with PHP 8.X

    Does it take minutes, hours or days to fix?

    minutes instead of \mysqli_get_server_version($mysqli_link) should be only \mysqli_get_server_version()

    Any additional information?

    Fatal error: Uncaught ArgumentCountError: mysqli_get_client_version() expects exactly 0 arguments, 1 given in /vendor/voku/simple-mysqli/src/voku/db/Helper.php

    opened by maranemil 1
  • Select IN causing issues.

    Select IN causing issues.

    What is this feature about (expected vs actual behaviour)?

    Replacing "IN" in "instrument_id".

    How can I reproduce it?

    $select = $db->select('instruments', ['instrument_id IN' => [13]]);
    

    The above will generate the below

    SELECT * FROM `instruments` WHERE ( `strument_id` IN (13))
    

    What I expected was:

    SELECT * FROM `instruments` WHERE ( `instrument_id` IN (13))
    

    Any additional information?

    Issue begins on DB.php line 458, I think it needs to find the last occurence of IN as opposed to replacing the first.

    bug 
    opened by michaelmarkie 1
  • Configure WhiteSource Bolt for GitHub

    Configure WhiteSource Bolt for GitHub

    Welcome to WhiteSource Bolt for GitHub! This is an onboarding PR to help you understand and configure settings before WhiteSource starts scanning your repository for security vulnerabilities.

    :vertical_traffic_light: WhiteSource Bolt for GitHub will start scanning your repository only once you merge this Pull Request. To disable WhiteSource Bolt for GitHub, simply close this Pull Request.


    What to Expect

    This PR contains a '.whitesource' configuration file which can be customized to your needs. If no changes were applied to this file, WhiteSource Bolt for GitHub will use the default configuration.

    Before merging this PR, Make sure the Issues tab is enabled. Once you merge this PR, WhiteSource Bolt for GitHub will scan your repository and create a GitHub Issue for every vulnerability detected in your repository.

    If you do not want a GitHub Issue to be created for each detected vulnerability, you can edit the '.whitesource' file and set the 'minSeverityLevel' parameter to 'NONE'.


    :question: Got questions? Check out WhiteSource Bolt for GitHub docs. If you need any further assistance then you can also request help here.


    This change is Reviewable

    opened by mend-bolt-for-github[bot] 3
Owner
Lars Moelleken
Webdeveloper & Sysadmin | egrep '#php|#js|#html|#css|#sass'
Lars Moelleken
Doctrine Database Abstraction Layer

Doctrine DBAL 4.0-dev 3.0 2.13 N/A N/A Powerful database abstraction layer with many features for database schema introspection, schema management and

Doctrine 8.9k Dec 28, 2022
🔌 A Doctrine DBAL Driver implementation on top of Swoole Coroutine PostgreSQL extension

Swoole Coroutine PostgreSQL Doctrine DBAL Driver A Doctrine\DBAL\Driver implementation on top of Swoole\Coroutine\PostgreSQL. Getting started Install

Leo Cavalcante 19 Nov 25, 2022
Orm is a simple database abstraction layer that supports postgresql.

Orm What is it Orm is a simple database abstraction layer that supports postgresql. Welcome to join us or star us for encouragement. Requires php 8.1

null 2 Sep 28, 2022
Connect and work with MySQL/MariaDB database through MySQLi in PHP. This is an introductory project, If you need a simple and straightforward example that takes you straight to the point, you can check out these examples.

First MySQLi PHP Connect and work with MySQL/MariaDB database through MySQLi in PHP. The above exercises are designed for students. This is an introdu

Max Base 4 Feb 22, 2022
Database Abstraction Layer, Schema Introspection, Schema Generation, Query Builders

Cycle DBAL Secure, multiple SQL dialects (MySQL, PostgreSQL, SQLite, SQLServer), schema introspection, schema declaration, smart identifier wrappers,

Cycle ORM 30 Oct 18, 2022
Поддержка очередей Redis (и на RabbitMq, и на Filesystem, и через DBAL) в Битриксе

Модуль для Битрикса, организующий работу с очередями через Redis (и не только) Поддерживаемый транспорт: Redis RabbitMq Filesystem DBAL Установка comp

Fedy 4 Aug 20, 2021
ORM layer that creates models, config and database on the fly

RedBeanPHP 5 RedBeanPHP is an easy to use ORM tool for PHP. Automatically creates tables and columns as you go No configuration, just fire and forget

Gabor de Mooij 2.2k Jan 9, 2023
Laravel 5 - Repositories to abstract the database layer

Laravel 5 Repositories Laravel 5 Repositories is used to abstract the data layer, making our application more flexible to maintain. See versions: 1.0.

Anderson Andrade 4k Jan 6, 2023
A Redis based, fully automated and scalable database cache layer for Laravel

Lada Cache A Redis based, fully automated and scalable database cache layer for Laravel Contributors wanted! Have a look at the open issues and send m

Matt 501 Dec 30, 2022
Doctrine Object Relational Mapper (ORM)

3.0.x 2.9.x 2.8.x Doctrine 2 is an object-relational mapper (ORM) for PHP 7.1+ that provides transparent persistence for PHP objects. It sits on top o

Doctrine 9.5k Jan 2, 2023
A drop-in Doctrine ORM 2 implementation for Laravel 5+ and Lumen

Laravel Doctrine ORM A drop-in Doctrine ORM 2 implementation for Laravel 5+ $scientist = new Scientist( 'Albert', 'Einstein' ); $scientist->a

Laravel Doctrine 777 Dec 17, 2022
Psalm Stubs for doctrine/mongodb-odm library

doctrine-mongodb-psalm-plugin A Doctrine plugin for Psalm (requires Psalm v4). Installation: $ composer require --dev runtothefather/doctrine-mongodb-

Evgeny 6 Jun 15, 2022
Provides integration for Doctrine with various Symfony components.

Doctrine Bridge The Doctrine bridge provides integration for Doctrine with various Symfony components. Resources Contributing Report issues and send P

Symfony 3k Dec 23, 2022
Doctrine PHP mapping driver

WORK IN PROGRESS! Doctrine PHP mapping driver Alternative mapping driver that allows to write mappings in PHP. Documentation Associations examples TOD

Andrey Klimenko 3 Aug 15, 2021
Doctrine extension to persist spatial data objects.

doctrine-Spatial Doctrine-spatial is a doctrine extension. It implements spatial types and functions. As exemple, this extension can help you to know

LongitudeOne 36 Jan 7, 2023
Monadic Doctrine repositories helper classes and services.

Doctrine Repository Monadic Helper Description This project provides the necessary classes and services to use Doctrine repositories in a more functio

(infinite) loophp 10 Aug 29, 2022
PostgreSQL enhancements for Doctrine

PostgreSQL enhancements for Doctrine. Provides support for advanced data types (json, jssnb, arrays), text search, array operators and jsonb specific functions.

Martin Georgiev 258 Dec 31, 2022
Support for many missing PostgreSQL specific features

Laravel supports many different databases and therefore has to limit itself to the lowest common denominator of all databases. PostgreSQL, however, of

Tobias Petry 359 Jan 3, 2023
MySQL Load Data Infile Support For Laravel

Laravel Load File ?? A package to help with loading files into MySQL tables. This uses MySQL's LOAD DATA statement to load text files quickly into you

Ellis Green 64 Dec 30, 2022