Commit 0f0ca575 authored by Alexander Butenko's avatar Alexander Butenko Committed by GitHub

Merge pull request #494 from Noneatme/master

Added methods for importing data (CSV, XML) and table locking
parents adbede91 dbc51997
#Mac OS X files
.DS_Store
#Vim trash
*.swp
\ No newline at end of file
......@@ -88,7 +88,19 @@ class MysqliDb
* @var array
*/
protected $_groupBy = array();
/**
* Dynamic type list for tempromary locking tables.
* @var array
*/
protected $_tableLocks = array();
/**
* Variable which holds the current table lock method.
* @var string
*/
protected $_tableLockMethod = "READ";
/**
* Dynamic array that holds a combination of where condition/table data value types and parameter references
* @var array
......@@ -381,6 +393,28 @@ class MysqliDb
return $this;
}
/**
* Pushes a unprepared statement to the mysqli stack.
* WARNING: Use with caution.
* This method does not escape strings by default so make sure you'll never use it in production.
*
* @author Jonas Barascu
* @param [[Type]] $query [[Description]]
*/
private function queryUnprepared($query)
{
// Execute query
$stmt = $this->mysqli()->query($query);
// Failed?
if(!$stmt){
throw new Exception("Unprepared Query Failed, ERRNO: ".$this->mysqli()->errno." (".$this->mysqli()->error.")");
};
// return stmt for future use
return $stmt;
}
/**
* Execute raw SQL query.
*
......@@ -864,6 +898,123 @@ class MysqliDb
return $this;
}
/**
* This is a basic method which allows you to import raw .CSV data into a table
* Please check out http://dev.mysql.com/doc/refman/5.7/en/load-data.html for a valid .csv file.
* @author Jonas Barascu (Noneatme)
* @param string $importTable The database table where the data will be imported into.
* @param string $importFile The file to be imported. Please use double backslashes \\ and make sure you
* @param string $importSettings An Array defining the import settings as described in the README.md
* @return boolean
*/
public function loadData($importTable, $importFile, $importSettings = null)
{
// We have to check if the file exists
if(!file_exists($importFile)) {
// Throw an exception
throw new Exception("importCSV -> importFile ".$importFile." does not exists!");
return;
}
// Define the default values
// We will merge it later
$settings = Array("fieldChar" => ';', "lineChar" => PHP_EOL, "linesToIgnore" => 1);
// Check the import settings
if(gettype($importSettings) == "array") {
// Merge the default array with the custom one
$settings = array_merge($settings, $importSettings);
}
// Add the prefix to the import table
$table = self::$prefix . $importTable;
// Add 1 more slash to every slash so maria will interpret it as a path
$importFile = str_replace("\\", "\\\\", $importFile);
// Build SQL Syntax
$sqlSyntax = sprintf('LOAD DATA INFILE \'%s\' INTO TABLE %s',
$importFile, $table);
// FIELDS
$sqlSyntax .= sprintf(' FIELDS TERMINATED BY \'%s\'', $settings["fieldChar"]);
if(isset($settings["fieldEnclosure"])) {
$sqlSyntax .= sprintf(' ENCLOSED BY \'%s\'', $settings["fieldEnclosure"]);
}
// LINES
$sqlSyntax .= sprintf(' LINES TERMINATED BY \'%s\'', $settings["lineChar"]);
if(isset($settings["lineStarting"])) {
$sqlSyntax .= sprintf(' STARTING BY \'%s\'', $settings["lineStarting"]);
}
// IGNORE LINES
$sqlSyntax .= sprintf(' IGNORE %d LINES', $settings["linesToIgnore"]);
// Exceute the query unprepared because LOAD DATA only works with unprepared statements.
$result = $this->queryUnprepared($sqlSyntax);
// Are there rows modified?
// Let the user know if the import failed / succeeded
return (bool) $result;
}
/**
* This method is usefull for importing XML files into a specific table.
* Check out the LOAD XML syntax for your MySQL server.
*
* @author Jonas Barascu
* @param string $importTable The table in which the data will be imported to.
* @param string $importFile The file which contains the .XML data.
* @param string $importSettings An Array defining the import settings as described in the README.md
*
* @return boolean Returns true if the import succeeded, false if it failed.
*/
public function loadXml($importTable, $importFile, $importSettings = null)
{
// We have to check if the file exists
if(!file_exists($importFile)) {
// Does not exists
throw new Exception("loadXml: Import file does not exists");
return;
}
// Create default values
$settings = Array("linesToIgnore" => 0);
// Check the import settings
if(gettype($importSettings) == "array") {
$settings = array_merge($settings, $importSettings);
}
// Add the prefix to the import table
$table = self::$prefix . $importTable;
// Add 1 more slash to every slash so maria will interpret it as a path
$importFile = str_replace("\\", "\\\\", $importFile);
// Build SQL Syntax
$sqlSyntax = sprintf('LOAD XML INFILE \'%s\' INTO TABLE %s',
$importFile, $table);
// FIELDS
if(isset($settings["rowTag"])) {
$sqlSyntax .= sprintf(' ROWS IDENTIFIED BY \'%s\'', $settings["rowTag"]);
}
// IGNORE LINES
$sqlSyntax .= sprintf(' IGNORE %d LINES', $settings["linesToIgnore"]);
// Exceute the query unprepared because LOAD XML only works with unprepared statements.
$result = $this->queryUnprepared($sqlSyntax);
// Are there rows modified?
// Let the user know if the import failed / succeeded
return (bool) $result;
}
/**
* This method allows you to specify multiple (method chaining optional) ORDER BY statements for SQL queries.
......@@ -921,7 +1072,123 @@ class MysqliDb
$this->_groupBy[] = $groupByField;
return $this;
}
/**
* This method sets the current table lock method.
*
* @author Jonas Barascu
* @param string $method The table lock method. Can be READ or WRITE.
*
* @throws Exception
* @return MysqliDb
*/
public function setLockMethod($method)
{
// Switch the uppercase string
switch(strtoupper($method)) {
// Is it READ or WRITE?
case "READ" || "WRITE":
// Succeed
$this->_tableLockMethod = $method;
break;
default:
// Else throw an exception
throw new Exception("Bad lock type: Can be either READ or WRITE");
break;
}
return $this;
}
/**
* Locks a table for R/W action.
*
* @author Jonas Barascu
* @param string $table The table to be locked. Can be a table or a view.
*
* @throws Exception
* @return MysqliDb if succeeeded;
*/
public function lock($table)
{
// Main Query
$this->_query = "LOCK TABLES";
// Is the table an array?
if(gettype($table) == "array") {
// Loop trough it and attach it to the query
foreach($table as $key => $value) {
if(gettype($value) == "string") {
if($key > 0) {
$this->_query .= ",";
}
$this->_query .= " ".self::$prefix.$value." ".$this->_tableLockMethod;
}
}
}
else{
// Build the table prefix
$table = self::$prefix . $table;
// Build the query
$this->_query = "LOCK TABLES ".$table." ".$this->_tableLockMethod;
}
// Exceute the query unprepared because LOCK only works with unprepared statements.
$result = $this->queryUnprepared($this->_query);
// Reset the query
$this->reset();
// Are there rows modified?
if($result) {
// Return true
// We can't return ourself because if one table gets locked, all other ones get unlocked!
return true;
}
// Something went wrong
else {
throw new Exception("Locking of table ".$table." failed");
}
// Return the success value
return false;
}
/**
* Unlocks all tables in a database.
* Also commits transactions.
*
* @author Jonas Barascu
* @return MysqliDb
*/
public function unlock()
{
// Build the query
$this->_query = "UNLOCK TABLES";
// Exceute the query unprepared because UNLOCK and LOCK only works with unprepared statements.
$result = $this->queryUnprepared($this->_query);
// Reset the query
$this->reset();
// Are there rows modified?
if($result) {
// return self
return $this;
}
// Something went wrong
else {
throw new Exception("Unlocking of tables failed");
}
// Return self
return $this;
}
/**
* This methods returns the ID of the last inserted item
*
......@@ -2017,4 +2284,4 @@ class MysqliDb
}
}
// END class
// END class
\ No newline at end of file
MysqliDb -- Simple MySQLi wrapper and object mapper with prepared statements
<hr>
### Table of Contents
**[Initialization](#initialization)**
**[Objects mapping](#objects-mapping)**
**[Insert Query](#insert-query)**
**[Update Query](#update-query)**
**[Select Query](#select-query)**
**[Delete Query](#delete-query)**
**[Insert Data](#insert-data)**
**[Insert XML](#insert-xml)**
**[Running raw SQL queries](#running-raw-sql-queries)**
**[Query Keywords](#query-keywords)**
**[Where Conditions](#where--having-methods)**
......@@ -19,7 +22,8 @@ MysqliDb -- Simple MySQLi wrapper and object mapper with prepared statements
**[Has method](#has-method)**
**[Helper Methods](#helper-methods)**
**[Transaction Helpers](#transaction-helpers)**
**[Error Helpers](#error-helpers)**
**[Error Helpers](#error-helpers)**
**[Table Locking](#table-locking)**
## Support Me
......@@ -212,6 +216,55 @@ foreach ($logins as $login)
echo $login;
```
###Insert Data
You can also load .CSV or .XML data into a specific table.
To insert .csv data, use the following syntax:
```php
$path_to_file = "/home/john/file.csv";
$db->loadData("users", $path_to_file);
```
This will load a .csv file called **file.csv** in the folder **/home/john/** (john's home directory.)
You can also attach an optional array of options.
Valid options are:
```php
Array(
"fieldChar" => ';', // Char which separates the data
"lineChar" => '\r\n', // Char which separates the lines
"linesToIgnore" => 1 // Amount of lines to ignore at the beginning of the import
);
```
Attach them using
```php
$options = Array("fieldChar" => ';', "lineChar" => '\r\n', "linesToIgnore" => 1);
$db->loadData("users", "/home/john/file.csv", $options);
```
###Insert XML
To load XML data into a table, you can use the method **loadXML**.
The syntax is smillar to the loadData syntax.
```php
$path_to_file = "/home/john/file.xml";
$db->loadXML("users", $path_to_file);
```
You can also add optional parameters.
Valid parameters:
```php
Array(
"linesToIgnore" => 0, // Amount of lines / rows to ignore at the beginning of the import
"rowTag" => "<user>" // The tag which marks the beginning of an entry
)
```
Usage:
```php
$options = Array("linesToIgnore" => 0, "rowTag" => "<user>"):
$path_to_file = "/home/john/file.xml";
$db->loadXML("users", $path_to_file, $options);
```
###Pagination
Use paginate() instead of get() to fetch paginated result
```php
......@@ -648,6 +701,7 @@ if (!$db->insert ('myTable', $insertData)) {
}
```
### Error helpers
After you executed a query you have options to check if there was an error. You can get the MySQL error string or the error code for the last executed query.
```php
......@@ -686,3 +740,25 @@ print_r ($db->trace);
)
```
##Table Locking
To lock tables, you can use the **lock** method together with **setLockMethod**.
The following example will lock the table **users** for **write** access.
```php
$db->setLockMethod("WRITE")->lock("users");
```
Calling another **->lock()** will remove the first lock.
You can also use
```php
$db->unlock();
```
to unlock the previous locked tables.
To lock multiple tables, you can use an array.
Example:
```php
$db->setLockMethod("READ")->lock(array("users", "log"));
```
This will lock the tables **users** and **log** for **READ** access only.
Make sure you use **unlock()* afterwards or your tables will remain locked!
id;username;name
3;simon;Simon Jarred
4;martin;Martin Fuel
5;example;Example Name 1
6;example2;Example Name 2
7;example3;Example Name 4
\ No newline at end of file
<list>
<user id="1" username="Kapek" name="Sainnouine" />
<user id="2" username="Sajon" name="Rondela" />
<user id="3">
<username>Likame</username>
<name>Datataa</name>
</user>
</list>
<?php
// TEST HAS BEEN DONE USING PHP 7.0
// Basic Stuff
error_reporting (E_ALL|E_STRICT);
require_once ("../../MysqliDb.php");
require_once ("../../dbObject.php");
// Create database context
$db = new MysqliDb ('localdev', 'noneatme', '12345', 'db_test');
// Import CSV
echo "Testing: File Not Found", PHP_EOL;
// File not Found
goto test_filenotfound;
// File Not Found Test
test_filenotfound:
try
{
// It should throw an exception
$db->loadData("users", "datanew.csv");
}
catch(Exception $e)
{
echo "Test 1 Succeeded!", PHP_EOL;
// goto newtest
goto test_import1;
}
test_import1:
{
try
{
// Import the CSV
$db->loadData("users", // Table
"D:\\DEV\\git\\PHP-MySQLi-Database-Class\\tests\\dataimport\\data.csv",
Array("fieldEnclosure" => '', "lineStarting" => ''));
echo "Test 2 Succeeded!", PHP_EOL;
goto test_import2;
}
catch(Exception $e)
{
echo($e);
}
}
test_import2:
{
try
{
$db->setLockMethod("WRITE")->lock(array("users", "log"));
$db->loadXML("users",
"D:\\DEV\\git\\PHP-MySQLi-Database-Class\\tests\\dataimport\\data.xml");
echo "Test 3 Succeeded!", PHP_EOL;
$db->unlock();
}
catch(Exception $e)
{
echo($e);
}
}
\ No newline at end of file
-- phpMyAdmin SQL Dump
-- version 4.5.1
-- http://www.phpmyadmin.net
--
-- Host: 127.0.0.1
-- Erstellungszeit: 27. Jun 2016 um 14:21
-- Server-Version: 10.1.13-MariaDB
-- PHP-Version: 5.6.20
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Datenbank: `db_test`
--
-- --------------------------------------------------------
--
-- Tabellenstruktur für Tabelle `users`
--
CREATE TABLE `users` (
`id` int(11) NOT NULL,
`username` varchar(32) NOT NULL,
`name` varchar(32) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Daten für Tabelle `users`
--
INSERT INTO `users` (`id`, `username`, `name`) VALUES
(1, 'test_1', 'John Doe'),
(2, 'test_2', 'Test User');
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment