From ce42d85c0cefea631938282a7cd9a57b3f2b9d52 Mon Sep 17 00:00:00 2001 From: Ibrahim BinAlshikh Date: Wed, 5 Nov 2025 00:10:33 +0300 Subject: [PATCH] docs: Updated Code Examples --- examples/01-basic-connection/example.php | 104 +++-- examples/02-basic-queries/example.php | 342 +++++++++----- examples/05-transactions/example.php | 442 ++++++++++--------- examples/09-multi-result-queries/example.php | 331 ++++++++++++++ examples/README.md | 212 ++++----- 5 files changed, 971 insertions(+), 460 deletions(-) create mode 100644 examples/09-multi-result-queries/example.php diff --git a/examples/01-basic-connection/example.php b/examples/01-basic-connection/example.php index 92bfabd..d72b4dd 100644 --- a/examples/01-basic-connection/example.php +++ b/examples/01-basic-connection/example.php @@ -1,38 +1,66 @@ -getDatabaseType()."\n"; - echo " Host: ".$connection->getHost()."\n"; - echo " Database: ".$connection->getDBName()."\n\n"; - - // Establish database connection - $database = new Database($connection); - echo "✓ Database connection established\n"; - - // Test connection with a simple query - $result = $database->setQuery("SELECT VERSION() as version")->execute(); - - if ($result) { - echo "✓ Connection test successful\n"; - $rows = $result->getRows(); - - if (!empty($rows)) { - echo " MySQL Version: ".$rows[0]['version']."\n"; - } - } -} catch (Exception $e) { - echo "✗ Error: ".$e->getMessage()."\n"; - echo "Note: Make sure MySQL is running and accessible with the provided credentials.\n"; -} - -echo "\n=== Example Complete ===\n"; +getDatabaseType()."\n"; + echo " Host: ".$connection->getHost()."\n"; + echo " Database: ".$connection->getDBName()."\n\n"; + + // Establish database connection + $database = new Database($connection); + echo "✓ Database connection established\n"; + + // Test connection with a simple query using raw() + $result = $database->raw("SELECT VERSION() as version")->execute(); + + if ($result) { + echo "✓ Connection test successful\n"; + $rows = $result->getRows(); + + if (!empty($rows)) { + echo " MySQL Version: ".$rows[0]['version']."\n"; + } + } + + // Additional connection tests using raw() with parameters + echo "\n--- Additional Connection Tests ---\n"; + + // Test current database + $result = $database->raw("SELECT DATABASE() as current_db")->execute(); + if ($result && $result->getRowsCount() > 0) { + echo "✓ Current database: " . $result->getRows()[0]['current_db'] . "\n"; + } + + // Test server status + $result = $database->raw("SHOW STATUS LIKE 'Uptime'")->execute(); + if ($result && $result->getRowsCount() > 0) { + $uptime = $result->getRows()[0]['Value']; + echo "✓ Server uptime: " . $uptime . " seconds\n"; + } + + // Test connection info + $result = $database->raw("SELECT CONNECTION_ID() as connection_id")->execute(); + if ($result && $result->getRowsCount() > 0) { + echo "✓ Connection ID: " . $result->getRows()[0]['connection_id'] . "\n"; + } + + $result = $database->raw("SELECT USER() as user_name")->execute(); + if ($result && $result->getRowsCount() > 0) { + echo "✓ Current User: " . $result->getRows()[0]['user_name'] . "\n"; + } + +} catch (Exception $e) { + echo "✗ Error: ".$e->getMessage()."\n"; + echo "Note: Make sure MySQL is running and accessible with the provided credentials.\n"; +} + +echo "\n=== Example Complete ===\n"; diff --git a/examples/02-basic-queries/example.php b/examples/02-basic-queries/example.php index d184464..08c4ba2 100644 --- a/examples/02-basic-queries/example.php +++ b/examples/02-basic-queries/example.php @@ -1,121 +1,221 @@ -setQuery(" - CREATE TABLE IF NOT EXISTS test_users ( - id INT AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(100) NOT NULL, - email VARCHAR(150) NOT NULL, - age INT - ) - ")->execute(); - echo "✓ Test table created\n\n"; - - // Clear any existing data - $database->setQuery("DELETE FROM test_users")->execute(); - - // INSERT operations - echo "2. INSERT Operations:\n"; - - $database->table('test_users')->insert([ - 'name' => 'Ahmed Hassan', - 'email' => 'ahmed@example.com', - 'age' => 30 - ])->execute(); - echo "✓ Inserted Ahmed Hassan\n"; - - $database->table('test_users')->insert([ - 'name' => 'Fatima Al-Zahra', - 'email' => 'fatima@example.com', - 'age' => 25 - ])->execute(); - echo "✓ Inserted Fatima Al-Zahra\n"; - - $database->table('test_users')->insert([ - 'name' => 'Omar Khalil', - 'email' => 'omar@example.com', - 'age' => 35 - ])->execute(); - echo "✓ Inserted Omar Khalil\n\n"; - - // SELECT operations - echo "3. SELECT Operations:\n"; - - // Select all records - $result = $database->table('test_users')->select()->execute(); - echo "All users:\n"; - - foreach ($result as $user) { - echo " - {$user['name']} ({$user['email']}) - Age: {$user['age']}\n"; - } - echo "\n"; - - // Select with condition - $result = $database->table('test_users') - ->select() - ->where('age', 30, '>') - ->execute(); - echo "Users older than 30:\n"; - - foreach ($result as $user) { - echo " - {$user['name']} - Age: {$user['age']}\n"; - } - echo "\n"; - - // UPDATE operations - echo "4. UPDATE Operations:\n"; - $database->table('test_users') - ->update(['age' => 26]) - ->where('name', 'Fatima Al-Zahra') - ->execute(); - echo "✓ Updated Fatima Al-Zahra's age to 26\n"; - - // Verify update - $result = $database->table('test_users') - ->select() - ->where('name', 'Fatima Al-Zahra') - ->execute(); - - foreach ($result as $user) { - echo " Fatima's new age: {$user['age']}\n"; - } - echo "\n"; - - // DELETE operations - echo "5. DELETE Operations:\n"; - $database->table('test_users') - ->delete() - ->where('name', 'Omar Khalil') - ->execute(); - echo "✓ Deleted Omar Khalil\n"; - - // Show remaining users - $result = $database->table('test_users')->select()->execute(); - echo "Remaining users:\n"; - - foreach ($result as $user) { - echo " - {$user['name']} ({$user['email']}) - Age: {$user['age']}\n"; - } - - // Clean up - echo "\n6. Cleanup:\n"; - $database->setQuery("DROP TABLE test_users")->execute(); - echo "✓ Test table dropped\n"; -} catch (Exception $e) { - echo "✗ Error: ".$e->getMessage()."\n"; -} - -echo "\n=== Example Complete ===\n"; +raw(" + CREATE TABLE IF NOT EXISTS test_users ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(100) NOT NULL, + email VARCHAR(150) NOT NULL, + age INT + ) + ")->execute(); + echo "✓ Test table created\n\n"; + + // Clear any existing data using raw() + $database->raw("DELETE FROM test_users")->execute(); + + // INSERT operations using raw() with parameters + echo "2. INSERT Operations with Parameters:\n"; + + $database->raw("INSERT INTO test_users (name, email, age) VALUES (?, ?, ?)", [ + 'Ahmed Hassan', 'ahmed@example.com', 30 + ])->execute(); + echo "✓ Inserted Ahmed Hassan\n"; + + $database->raw("INSERT INTO test_users (name, email, age) VALUES (?, ?, ?)", [ + 'Fatima Al-Zahra', 'fatima@example.com', 25 + ])->execute(); + echo "✓ Inserted Fatima Al-Zahra\n"; + + $database->raw("INSERT INTO test_users (name, email, age) VALUES (?, ?, ?)", [ + 'Omar Khalil', 'omar@example.com', 35 + ])->execute(); + echo "✓ Inserted Omar Khalil\n\n"; + + // SELECT operations using raw() with parameters + echo "3. SELECT Operations with Parameters:\n"; + + // Select all records + $result = $database->raw("SELECT * FROM test_users")->execute(); + echo "All users:\n"; + + foreach ($result as $user) { + echo " - {$user['name']} ({$user['email']}) - Age: {$user['age']}\n"; + } + echo "\n"; + + // Select with condition using parameters + $result = $database->raw("SELECT * FROM test_users WHERE age > ?", [30])->execute(); + echo "Users older than 30:\n"; + + foreach ($result as $user) { + echo " - {$user['name']} - Age: {$user['age']}\n"; + } + echo "\n"; + + // Multi-parameter query + $result = $database->raw("SELECT * FROM test_users WHERE age BETWEEN ? AND ?", [25, 35])->execute(); + echo "Users between 25 and 35:\n"; + + foreach ($result as $user) { + echo " - {$user['name']} - Age: {$user['age']}\n"; + } + echo "\n"; + + // UPDATE operations using raw() with parameters + echo "4. UPDATE Operations with Parameters:\n"; + $database->raw("UPDATE test_users SET age = ? WHERE name = ?", [26, 'Fatima Al-Zahra'])->execute(); + echo "✓ Updated Fatima Al-Zahra's age to 26\n"; + + // Verify update + $result = $database->raw("SELECT * FROM test_users WHERE name = ?", ['Fatima Al-Zahra'])->execute(); + + foreach ($result as $user) { + echo " Fatima's new age: {$user['age']}\n"; + } + echo "\n"; + + // DELETE operations using raw() with parameters + echo "5. DELETE Operations with Parameters:\n"; + $database->raw("DELETE FROM test_users WHERE name = ?", ['Omar Khalil'])->execute(); + echo "✓ Deleted Omar Khalil\n"; + + // Show remaining users + $result = $database->raw("SELECT * FROM test_users")->execute(); + echo "Remaining users:\n"; + + foreach ($result as $user) { + echo " - {$user['name']} ({$user['email']}) - Age: {$user['age']}\n"; + } + + // Multi-Result Query Example + echo "\n6. Multi-Result Query Example:\n"; + + // Create a stored procedure that returns multiple result sets + $database->raw("DROP PROCEDURE IF EXISTS GetUserStats")->execute(); + $database->raw(" + CREATE PROCEDURE GetUserStats() + BEGIN + SELECT 'User List' as report_type; + SELECT name, age FROM test_users ORDER BY age; + SELECT COUNT(*) as total_users, AVG(age) as avg_age FROM test_users; + END + ")->execute(); + + // Execute the stored procedure + $result = $database->raw("CALL GetUserStats()")->execute(); + + if ($result instanceof MultiResultSet) { + echo "✓ Multi-result query executed successfully!\n"; + echo "Number of result sets: " . $result->count() . "\n"; + + for ($i = 0; $i < $result->count(); $i++) { + $resultSet = $result->getResultSet($i); + echo "\nResult Set " . ($i + 1) . ":\n"; + + foreach ($resultSet as $row) { + echo " "; + foreach ($row as $key => $value) { + echo "$key: $value "; + } + echo "\n"; + } + } + } else { + echo "Single result set returned:\n"; + foreach ($result as $row) { + echo " "; + foreach ($row as $key => $value) { + echo "$key: $value "; + } + echo "\n"; + } + } + + // Another multi-result example with conditional logic + echo "\n7. Complex Multi-Result Example:\n"; + + $database->raw("DROP PROCEDURE IF EXISTS ComplexStats")->execute(); + $database->raw(" + CREATE PROCEDURE ComplexStats() + BEGIN + -- First result: All users + SELECT 'All Users' as section, name, email, age FROM test_users; + + -- Second result: Statistics + SELECT + 'Statistics' as section, + COUNT(*) as total_count, + MIN(age) as min_age, + MAX(age) as max_age, + AVG(age) as avg_age + FROM test_users; + + -- Third result: Age groups + SELECT + 'Age Groups' as section, + CASE + WHEN age < 30 THEN 'Young' + WHEN age >= 30 THEN 'Mature' + END as age_group, + COUNT(*) as count + FROM test_users + GROUP BY age_group; + END + ")->execute(); + + $complexResult = $database->raw("CALL ComplexStats()")->execute(); + + if ($complexResult instanceof MultiResultSet) { + echo "✓ Complex multi-result query executed!\n"; + + // Process each result set with specific handling + for ($i = 0; $i < $complexResult->count(); $i++) { + $rs = $complexResult->getResultSet($i); + if ($rs->getRowsCount() > 0) { + $firstRow = $rs->getRows()[0]; + + if (isset($firstRow['section'])) { + echo "\n--- {$firstRow['section']} ---\n"; + + foreach ($rs as $row) { + if ($row['section'] === 'All Users') { + echo " User: {$row['name']} ({$row['email']}) - Age: {$row['age']}\n"; + } elseif ($row['section'] === 'Statistics') { + echo " Total: {$row['total_count']}, Min Age: {$row['min_age']}, Max Age: {$row['max_age']}, Avg Age: " . round($row['avg_age'], 1) . "\n"; + } elseif ($row['section'] === 'Age Groups') { + echo " {$row['age_group']}: {$row['count']} users\n"; + } + } + } + } + } + } + + // Clean up + echo "\n8. Cleanup:\n"; + $database->raw("DROP PROCEDURE IF EXISTS GetUserStats")->execute(); + $database->raw("DROP PROCEDURE IF EXISTS ComplexStats")->execute(); + $database->raw("DROP TABLE test_users")->execute(); + echo "✓ Test table and procedures dropped\n"; + +} catch (Exception $e) { + echo "✗ Error: ".$e->getMessage()."\n"; + echo "Stack trace:\n" . $e->getTraceAsString() . "\n"; +} + +echo "\n=== Example Complete ===\n"; diff --git a/examples/05-transactions/example.php b/examples/05-transactions/example.php index f8c4604..dc07818 100644 --- a/examples/05-transactions/example.php +++ b/examples/05-transactions/example.php @@ -1,199 +1,243 @@ -setQuery(" - CREATE TABLE IF NOT EXISTS accounts ( - id INT AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(100) NOT NULL, - balance DECIMAL(10,2) NOT NULL DEFAULT 0.00 - ) - ")->execute(); - - $database->setQuery(" - CREATE TABLE IF NOT EXISTS transactions ( - id INT AUTO_INCREMENT PRIMARY KEY, - from_account INT, - to_account INT, - amount DECIMAL(10,2) NOT NULL, - description VARCHAR(255), - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ) - ")->execute(); - - echo "✓ Test tables created\n\n"; - - // Clear existing data - $database->setQuery("DELETE FROM transactions")->execute(); - $database->setQuery("DELETE FROM accounts")->execute(); - - // Insert initial account data - $database->table('accounts')->insert([ - 'name' => 'Amira', - 'balance' => 1000.00 - ])->execute(); - - $database->table('accounts')->insert([ - 'name' => 'Yusuf', - 'balance' => 500.00 - ])->execute(); - - echo "2. Initial Account Balances:\n"; - $result = $database->table('accounts')->select()->execute(); - - foreach ($result as $account) { - echo " {$account['name']}: $".number_format($account['balance'], 2)."\n"; - } - echo "\n"; - - echo "3. Successful Transaction Example:\n"; - - // Successful money transfer transaction - $transferAmount = 200.00; - $fromAccountId = 1; // Amira - $toAccountId = 2; // Yusuf - - $database->transaction(function (Database $db) use ($transferAmount, $fromAccountId, $toAccountId) - { - // Check if sender has sufficient balance - $senderResult = $db->table('accounts') - ->select(['balance']) - ->where('id', $fromAccountId) - ->execute(); - - $senderBalance = $senderResult->getRows()[0]['balance']; - - if ($senderBalance < $transferAmount) { - throw new DatabaseException("Insufficient funds"); - } - - // Deduct from sender - $db->table('accounts') - ->update(['balance' => $senderBalance - $transferAmount]) - ->where('id', $fromAccountId) - ->execute(); - - // Add to receiver - $receiverResult = $db->table('accounts') - ->select(['balance']) - ->where('id', $toAccountId) - ->execute(); - - $receiverBalance = $receiverResult->getRows()[0]['balance']; - - $db->table('accounts') - ->update(['balance' => $receiverBalance + $transferAmount]) - ->where('id', $toAccountId) - ->execute(); - - // Record the transaction - $db->table('transactions')->insert([ - 'from_account' => $fromAccountId, - 'to_account' => $toAccountId, - 'amount' => $transferAmount, - 'description' => 'Money transfer' - ])->execute(); - - echo "✓ Transaction completed successfully\n"; - }); - - echo "Account balances after successful transfer:\n"; - $result = $database->table('accounts')->select()->execute(); - - foreach ($result as $account) { - echo " {$account['name']}: $".number_format($account['balance'], 2)."\n"; - } - echo "\n"; - - echo "4. Failed Transaction Example (Insufficient Funds):\n"; - - // Attempt to transfer more money than available - $largeTransferAmount = 2000.00; - - try { - $database->transaction(function (Database $db) use ($largeTransferAmount, $fromAccountId, $toAccountId) - { - // Check if sender has sufficient balance - $senderResult = $db->table('accounts') - ->select(['balance']) - ->where('id', $fromAccountId) - ->execute(); - - $senderBalance = $senderResult->getRows()[0]['balance']; - - if ($senderBalance < $largeTransferAmount) { - throw new DatabaseException("Insufficient funds for transfer of $".number_format($largeTransferAmount, 2)); - } - - // This code won't be reached due to insufficient funds - $db->table('accounts') - ->update(['balance' => $senderBalance - $largeTransferAmount]) - ->where('id', $fromAccountId) - ->execute(); - }); - } catch (DatabaseException $e) { - echo "✗ Transaction failed: ".$e->getMessage()."\n"; - echo "✓ Transaction was rolled back automatically\n"; - } - - echo "Account balances after failed transaction (should be unchanged):\n"; - $result = $database->table('accounts')->select()->execute(); - - foreach ($result as $account) { - echo " {$account['name']}: $".number_format($account['balance'], 2)."\n"; - } - echo "\n"; - - echo "5. Transaction History:\n"; - $result = $database->setQuery(" - SELECT t.*, - a1.name as from_name, - a2.name as to_name - FROM transactions t - LEFT JOIN accounts a1 ON t.from_account = a1.id - LEFT JOIN accounts a2 ON t.to_account = a2.id - ORDER BY t.created_at - ")->execute(); - - if ($result->getRowsCount() > 0) { - foreach ($result as $transaction) { - echo " Transfer: {$transaction['from_name']} → {$transaction['to_name']}\n"; - echo " Amount: $".number_format($transaction['amount'], 2)."\n"; - echo " Date: {$transaction['created_at']}\n"; - echo " Description: {$transaction['description']}\n\n"; - } - } else { - echo " No transactions recorded\n\n"; - } - - echo "6. Cleanup:\n"; - $database->setQuery("DROP TABLE transactions")->execute(); - $database->setQuery("DROP TABLE accounts")->execute(); - echo "✓ Test tables dropped\n"; -} catch (Exception $e) { - echo "✗ Error: ".$e->getMessage()."\n"; - - // Clean up on error - try { - $database->setQuery("DROP TABLE IF EXISTS transactions")->execute(); - $database->setQuery("DROP TABLE IF EXISTS accounts")->execute(); - } catch (Exception $cleanupError) { - // Ignore cleanup errors - } -} - -echo "\n=== Example Complete ===\n"; +raw(" + CREATE TABLE IF NOT EXISTS accounts ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(100) NOT NULL, + balance DECIMAL(10,2) NOT NULL DEFAULT 0.00 + ) + ")->execute(); + + $database->raw(" + CREATE TABLE IF NOT EXISTS transactions ( + id INT AUTO_INCREMENT PRIMARY KEY, + from_account INT, + to_account INT, + amount DECIMAL(10,2) NOT NULL, + description VARCHAR(255), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + ")->execute(); + + echo "✓ Test tables created\n\n"; + + // Clear existing data using raw() + $database->raw("DELETE FROM transactions")->execute(); + $database->raw("DELETE FROM accounts")->execute(); + + // Insert initial account data using raw() with parameters + $database->raw("INSERT INTO accounts (name, balance) VALUES (?, ?)", [ + 'Amira', 1000.00 + ])->execute(); + + $database->raw("INSERT INTO accounts (name, balance) VALUES (?, ?)", [ + 'Yusuf', 500.00 + ])->execute(); + + echo "2. Initial Account Balances:\n"; + $result = $database->raw("SELECT * FROM accounts")->execute(); + + foreach ($result as $account) { + echo " {$account['name']}: $".number_format($account['balance'], 2)."\n"; + } + echo "\n"; + + echo "3. Successful Transaction Example:\n"; + + // Successful money transfer transaction + $transferAmount = 200.00; + $fromAccountId = 1; // Amira + $toAccountId = 2; // Yusuf + + $database->transaction(function (Database $db) use ($transferAmount, $fromAccountId, $toAccountId) + { + // Check if sender has sufficient balance using raw() with parameters + $senderResult = $db->raw("SELECT balance FROM accounts WHERE id = ?", [$fromAccountId])->execute(); + $senderBalance = $senderResult->getRows()[0]['balance']; + + if ($senderBalance < $transferAmount) { + throw new DatabaseException("Insufficient funds"); + } + + // Deduct from sender using raw() with parameters + $db->raw("UPDATE accounts SET balance = ? WHERE id = ?", [ + $senderBalance - $transferAmount, $fromAccountId + ])->execute(); + + // Get receiver balance using raw() with parameters + $receiverResult = $db->raw("SELECT balance FROM accounts WHERE id = ?", [$toAccountId])->execute(); + $receiverBalance = $receiverResult->getRows()[0]['balance']; + + // Add to receiver using raw() with parameters + $db->raw("UPDATE accounts SET balance = ? WHERE id = ?", [ + $receiverBalance + $transferAmount, $toAccountId + ])->execute(); + + // Record the transaction using raw() with parameters + $db->raw("INSERT INTO transactions (from_account, to_account, amount, description) VALUES (?, ?, ?, ?)", [ + $fromAccountId, $toAccountId, $transferAmount, 'Money transfer' + ])->execute(); + + echo "✓ Transaction completed successfully\n"; + }); + + echo "Account balances after successful transfer:\n"; + $result = $database->raw("SELECT * FROM accounts")->execute(); + + foreach ($result as $account) { + echo " {$account['name']}: $".number_format($account['balance'], 2)."\n"; + } + echo "\n"; + + echo "4. Failed Transaction Example (Insufficient Funds):\n"; + + // Attempt to transfer more money than available + $largeTransferAmount = 2000.00; + + try { + $database->transaction(function (Database $db) use ($largeTransferAmount, $fromAccountId, $toAccountId) + { + // Check if sender has sufficient balance using raw() with parameters + $senderResult = $db->raw("SELECT balance FROM accounts WHERE id = ?", [$fromAccountId])->execute(); + $senderBalance = $senderResult->getRows()[0]['balance']; + + if ($senderBalance < $largeTransferAmount) { + throw new DatabaseException("Insufficient funds for transfer of $".number_format($largeTransferAmount, 2)); + } + + // This code won't be reached due to insufficient funds + $db->raw("UPDATE accounts SET balance = ? WHERE id = ?", [ + $senderBalance - $largeTransferAmount, $fromAccountId + ])->execute(); + }); + } catch (DatabaseException $e) { + echo "✗ Transaction failed: ".$e->getMessage()."\n"; + echo "✓ Transaction was rolled back automatically\n"; + } + + echo "Account balances after failed transaction (should be unchanged):\n"; + $result = $database->raw("SELECT * FROM accounts")->execute(); + + foreach ($result as $account) { + echo " {$account['name']}: $".number_format($account['balance'], 2)."\n"; + } + echo "\n"; + + echo "5. Transaction History:\n"; + $result = $database->raw(" + SELECT t.*, + a1.name as from_name, + a2.name as to_name + FROM transactions t + LEFT JOIN accounts a1 ON t.from_account = a1.id + LEFT JOIN accounts a2 ON t.to_account = a2.id + ORDER BY t.created_at + ")->execute(); + + if ($result->getRowsCount() > 0) { + foreach ($result as $transaction) { + echo " Transfer: {$transaction['from_name']} → {$transaction['to_name']}\n"; + echo " Amount: $".number_format($transaction['amount'], 2)."\n"; + echo " Date: {$transaction['created_at']}\n"; + echo " Description: {$transaction['description']}\n\n"; + } + } else { + echo " No transactions recorded\n\n"; + } + + echo "6. Multi-Result Transaction Analysis:\n"; + + // Create a stored procedure for transaction analysis + $database->raw("DROP PROCEDURE IF EXISTS TransactionAnalysis")->execute(); + $database->raw(" + CREATE PROCEDURE TransactionAnalysis() + BEGIN + -- Account summary + SELECT 'Account Summary' as report_type, name, balance FROM accounts ORDER BY balance DESC; + + -- Transaction summary + SELECT 'Transaction Summary' as report_type, + COUNT(*) as total_transactions, + SUM(amount) as total_amount, + AVG(amount) as avg_amount + FROM transactions; + + -- Recent transactions + SELECT 'Recent Transactions' as report_type, + t.amount, + a1.name as from_name, + a2.name as to_name, + t.created_at + FROM transactions t + LEFT JOIN accounts a1 ON t.from_account = a1.id + LEFT JOIN accounts a2 ON t.to_account = a2.id + ORDER BY t.created_at DESC + LIMIT 5; + END + ")->execute(); + + $analysisResult = $database->raw("CALL TransactionAnalysis()")->execute(); + + if (method_exists($analysisResult, 'count') && $analysisResult->count() > 1) { + echo "✓ Multi-result transaction analysis completed!\n"; + + for ($i = 0; $i < $analysisResult->count(); $i++) { + $rs = $analysisResult->getResultSet($i); + if ($rs->getRowsCount() > 0) { + $firstRow = $rs->getRows()[0]; + + if (isset($firstRow['report_type'])) { + echo "\n--- {$firstRow['report_type']} ---\n"; + + foreach ($rs as $row) { + if ($row['report_type'] === 'Account Summary') { + echo " {$row['name']}: $" . number_format($row['balance'], 2) . "\n"; + } elseif ($row['report_type'] === 'Transaction Summary') { + echo " Total Transactions: {$row['total_transactions']}\n"; + echo " Total Amount: $" . number_format($row['total_amount'], 2) . "\n"; + echo " Average Amount: $" . number_format($row['avg_amount'], 2) . "\n"; + } elseif ($row['report_type'] === 'Recent Transactions') { + echo " {$row['from_name']} → {$row['to_name']}: $" . number_format($row['amount'], 2) . " ({$row['created_at']})\n"; + } + } + } + } + } + } + + echo "\n7. Cleanup:\n"; + $database->raw("DROP PROCEDURE IF EXISTS TransactionAnalysis")->execute(); + $database->raw("DROP TABLE transactions")->execute(); + $database->raw("DROP TABLE accounts")->execute(); + echo "✓ Test tables and procedures dropped\n"; + +} catch (Exception $e) { + echo "✗ Error: ".$e->getMessage()."\n"; + + // Clean up on error + try { + $database->raw("DROP PROCEDURE IF EXISTS TransactionAnalysis")->execute(); + $database->raw("DROP TABLE IF EXISTS transactions")->execute(); + $database->raw("DROP TABLE IF EXISTS accounts")->execute(); + } catch (Exception $cleanupError) { + // Ignore cleanup errors + } +} + +echo "\n=== Example Complete ===\n"; diff --git a/examples/09-multi-result-queries/example.php b/examples/09-multi-result-queries/example.php new file mode 100644 index 0000000..d790c33 --- /dev/null +++ b/examples/09-multi-result-queries/example.php @@ -0,0 +1,331 @@ +raw(" + CREATE TABLE IF NOT EXISTS products ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(100) NOT NULL, + category VARCHAR(50) NOT NULL, + price DECIMAL(10,2) NOT NULL, + stock INT NOT NULL DEFAULT 0 + ) + ")->execute(); + + $database->raw(" + CREATE TABLE IF NOT EXISTS orders ( + id INT AUTO_INCREMENT PRIMARY KEY, + product_id INT, + quantity INT NOT NULL, + order_date DATE NOT NULL, + customer_name VARCHAR(100) NOT NULL + ) + ")->execute(); + + echo "✓ Test tables created\n"; + + // Clear existing data + $database->raw("DELETE FROM orders")->execute(); + $database->raw("DELETE FROM products")->execute(); + + // Insert sample products + $products = [ + ['Laptop', 'Electronics', 999.99, 10], + ['Mouse', 'Electronics', 29.99, 50], + ['Keyboard', 'Electronics', 79.99, 30], + ['Chair', 'Furniture', 199.99, 15], + ['Desk', 'Furniture', 299.99, 8], + ['Book', 'Education', 19.99, 100] + ]; + + foreach ($products as $product) { + $database->raw("INSERT INTO products (name, category, price, stock) VALUES (?, ?, ?, ?)", $product)->execute(); + } + + // Insert sample orders + $orders = [ + [1, 2, '2024-01-15', 'Ahmed Ali'], + [2, 5, '2024-01-16', 'Fatima Hassan'], + [3, 1, '2024-01-17', 'Omar Khalil'], + [1, 1, '2024-01-18', 'Layla Ahmed'], + [4, 3, '2024-01-19', 'Yusuf Ibrahim'] + ]; + + foreach ($orders as $order) { + $database->raw("INSERT INTO orders (product_id, quantity, order_date, customer_name) VALUES (?, ?, ?, ?)", $order)->execute(); + } + + echo "✓ Sample data inserted\n\n"; + + echo "2. Basic Multi-Result Query Example:\n"; + + // Create a stored procedure that returns multiple result sets + $database->raw("DROP PROCEDURE IF EXISTS GetBusinessReport")->execute(); + $database->raw(" + CREATE PROCEDURE GetBusinessReport() + BEGIN + -- Result Set 1: Product inventory + SELECT 'Product Inventory' as report_section, name, category, price, stock + FROM products + ORDER BY category, name; + + -- Result Set 2: Sales summary by category + SELECT 'Sales by Category' as report_section, + p.category, + COUNT(o.id) as total_orders, + SUM(o.quantity) as total_quantity, + SUM(o.quantity * p.price) as total_revenue + FROM products p + LEFT JOIN orders o ON p.id = o.product_id + GROUP BY p.category + ORDER BY total_revenue DESC; + + -- Result Set 3: Recent orders + SELECT 'Recent Orders' as report_section, + o.customer_name, + p.name as product_name, + o.quantity, + o.order_date, + (o.quantity * p.price) as order_total + FROM orders o + JOIN products p ON o.product_id = p.id + ORDER BY o.order_date DESC + LIMIT 10; + END + ")->execute(); + + // Execute the multi-result procedure + $result = $database->raw("CALL GetBusinessReport()")->execute(); + + if ($result instanceof MultiResultSet) { + echo "✓ Multi-result query executed successfully!\n"; + echo "Number of result sets: " . $result->count() . "\n\n"; + + // Process each result set + for ($i = 0; $i < $result->count(); $i++) { + $resultSet = $result->getResultSet($i); + + if ($resultSet->getRowsCount() > 0) { + $firstRow = $resultSet->getRows()[0]; + + if (isset($firstRow['report_section'])) { + echo "--- {$firstRow['report_section']} ---\n"; + + foreach ($resultSet as $row) { + if ($row['report_section'] === 'Product Inventory') { + echo " {$row['category']}: {$row['name']} - $" . number_format($row['price'], 2) . " (Stock: {$row['stock']})\n"; + } elseif ($row['report_section'] === 'Sales by Category') { + echo " {$row['category']}: {$row['total_orders']} orders, {$row['total_quantity']} items, $" . number_format($row['total_revenue'], 2) . " revenue\n"; + } elseif ($row['report_section'] === 'Recent Orders') { + echo " {$row['customer_name']}: {$row['product_name']} x{$row['quantity']} = $" . number_format($row['order_total'], 2) . " ({$row['order_date']})\n"; + } + } + echo "\n"; + } + } + } + } + + echo "3. Advanced Multi-Result with Parameters:\n"; + + // Create a parameterized stored procedure + $database->raw("DROP PROCEDURE IF EXISTS GetCategoryAnalysis")->execute(); + $database->raw(" + CREATE PROCEDURE GetCategoryAnalysis(IN category_filter VARCHAR(50)) + BEGIN + -- Result Set 1: Products in category + SELECT 'Products in Category' as report_section, + name, price, stock + FROM products + WHERE category = category_filter + ORDER BY price DESC; + + -- Result Set 2: Category statistics + SELECT 'Category Statistics' as report_section, + category_filter as category, + COUNT(*) as product_count, + AVG(price) as avg_price, + MIN(price) as min_price, + MAX(price) as max_price, + SUM(stock) as total_stock; + + -- Result Set 3: Orders for this category + SELECT 'Category Orders' as report_section, + o.customer_name, + p.name as product_name, + o.quantity, + o.order_date + FROM orders o + JOIN products p ON o.product_id = p.id + WHERE p.category = category_filter + ORDER BY o.order_date DESC; + END + ")->execute(); + + // Execute with parameter using raw() + $categoryResult = $database->raw("CALL GetCategoryAnalysis(?)", ['Electronics'])->execute(); + + if ($categoryResult instanceof MultiResultSet) { + echo "✓ Parameterized multi-result query executed for 'Electronics'!\n\n"; + + for ($i = 0; $i < $categoryResult->count(); $i++) { + $rs = $categoryResult->getResultSet($i); + + if ($rs->getRowsCount() > 0) { + $firstRow = $rs->getRows()[0]; + + if (isset($firstRow['report_section'])) { + echo "--- {$firstRow['report_section']} ---\n"; + + foreach ($rs as $row) { + if ($row['report_section'] === 'Products in Category') { + echo " {$row['name']}: $" . number_format($row['price'], 2) . " (Stock: {$row['stock']})\n"; + } elseif ($row['report_section'] === 'Category Statistics') { + echo " Category: {$row['category']}\n"; + echo " Product Count: {$row['product_count']}\n"; + echo " Average Price: $" . number_format($row['avg_price'], 2) . "\n"; + echo " Price Range: $" . number_format($row['min_price'], 2) . " - $" . number_format($row['max_price'], 2) . "\n"; + echo " Total Stock: {$row['total_stock']}\n"; + } elseif ($row['report_section'] === 'Category Orders') { + echo " {$row['customer_name']}: {$row['product_name']} x{$row['quantity']} ({$row['order_date']})\n"; + } + } + echo "\n"; + } + } + } + } + + echo "4. Working with Individual Result Sets:\n"; + + // Execute and work with specific result sets + $businessReport = $database->raw("CALL GetBusinessReport()")->execute(); + + if ($businessReport instanceof MultiResultSet) { + // Get specific result sets + $inventoryResults = $businessReport->getResultSet(0); + $salesResults = $businessReport->getResultSet(1); + $ordersResults = $businessReport->getResultSet(2); + + echo "✓ Extracted individual result sets:\n"; + echo " - Inventory results: " . $inventoryResults->getRowsCount() . " products\n"; + echo " - Sales results: " . $salesResults->getRowsCount() . " categories\n"; + echo " - Orders results: " . $ordersResults->getRowsCount() . " orders\n\n"; + + // Process specific result set + echo "Low stock products (< 20 items):\n"; + foreach ($inventoryResults as $product) { + if ($product['stock'] < 20) { + echo " ⚠️ {$product['name']}: {$product['stock']} remaining\n"; + } + } + echo "\n"; + + // Find best selling category + $bestCategory = null; + $bestRevenue = 0; + + foreach ($salesResults as $category) { + if ($category['total_revenue'] > $bestRevenue) { + $bestRevenue = $category['total_revenue']; + $bestCategory = $category['category']; + } + } + + if ($bestCategory) { + echo "🏆 Best performing category: {$bestCategory} ($" . number_format($bestRevenue, 2) . " revenue)\n\n"; + } + } + + echo "5. Multi-Result with Complex Logic:\n"; + + // Create a procedure with conditional logic + $database->raw("DROP PROCEDURE IF EXISTS GetDynamicReport")->execute(); + $database->raw(" + CREATE PROCEDURE GetDynamicReport(IN report_type VARCHAR(20)) + BEGIN + IF report_type = 'summary' THEN + SELECT 'Summary Report' as report_section, + 'Products' as metric, COUNT(*) as value FROM products + UNION ALL + SELECT 'Summary Report' as report_section, + 'Orders' as metric, COUNT(*) as value FROM orders + UNION ALL + SELECT 'Summary Report' as report_section, + 'Categories' as metric, COUNT(DISTINCT category) as value FROM products; + + SELECT 'Revenue by Month' as report_section, + DATE_FORMAT(o.order_date, '%Y-%m') as month, + SUM(o.quantity * p.price) as revenue + FROM orders o + JOIN products p ON o.product_id = p.id + GROUP BY DATE_FORMAT(o.order_date, '%Y-%m') + ORDER BY month; + ELSE + SELECT 'Detailed Report' as report_section, + p.name, p.category, p.price, p.stock, + COALESCE(SUM(o.quantity), 0) as total_sold + FROM products p + LEFT JOIN orders o ON p.id = o.product_id + GROUP BY p.id, p.name, p.category, p.price, p.stock + ORDER BY total_sold DESC; + END IF; + END + ")->execute(); + + // Test with different parameters + echo "Summary Report:\n"; + $summaryResult = $database->raw("CALL GetDynamicReport(?)", ['summary'])->execute(); + + if ($summaryResult instanceof MultiResultSet) { + for ($i = 0; $i < $summaryResult->count(); $i++) { + $rs = $summaryResult->getResultSet($i); + foreach ($rs as $row) { + if (isset($row['metric'])) { + echo " {$row['metric']}: {$row['value']}\n"; + } elseif (isset($row['month'])) { + echo " {$row['month']}: $" . number_format($row['revenue'], 2) . "\n"; + } + } + } + } + + echo "\n6. Cleanup:\n"; + $database->raw("DROP PROCEDURE IF EXISTS GetBusinessReport")->execute(); + $database->raw("DROP PROCEDURE IF EXISTS GetCategoryAnalysis")->execute(); + $database->raw("DROP PROCEDURE IF EXISTS GetDynamicReport")->execute(); + $database->raw("DROP TABLE orders")->execute(); + $database->raw("DROP TABLE products")->execute(); + echo "✓ Test tables and procedures dropped\n"; + +} catch (Exception $e) { + echo "✗ Error: ".$e->getMessage()."\n"; + echo "Stack trace:\n" . $e->getTraceAsString() . "\n"; + + // Clean up on error + try { + $database->raw("DROP PROCEDURE IF EXISTS GetBusinessReport")->execute(); + $database->raw("DROP PROCEDURE IF EXISTS GetCategoryAnalysis")->execute(); + $database->raw("DROP PROCEDURE IF EXISTS GetDynamicReport")->execute(); + $database->raw("DROP TABLE IF EXISTS orders")->execute(); + $database->raw("DROP TABLE IF EXISTS products")->execute(); + } catch (Exception $cleanupError) { + // Ignore cleanup errors + } +} + +echo "\n=== Example Complete ===\n"; diff --git a/examples/README.md b/examples/README.md index 1afbff4..42b74fc 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,102 +1,110 @@ -# WebFiori Database Examples - -This directory contains practical examples demonstrating how to use the WebFiori Database Abstraction Layer. - -## Examples Overview - -1. **[01-basic-connection](01-basic-connection/)** - How to establish database connections -2. **[02-basic-queries](02-basic-queries/)** - CRUD operations (Insert, Select, Update, Delete) -3. **[03-table-blueprints](03-table-blueprints/)** - Creating and managing database table structures -4. **[04-entity-mapping](04-entity-mapping/)** - Working with entity classes and object mapping -5. **[05-transactions](05-transactions/)** - Database transactions for data integrity -6. **[06-migrations](06-migrations/)** - Database schema migrations and versioning -7. **[07-seeders](07-seeders/)** - Database data seeding and population -8. **[08-performance-monitoring](08-performance-monitoring/)** - Query performance tracking and analysis - -## Prerequisites - -- PHP 8.1 or higher -- MySQL or MSSQL database server -- Composer dependencies installed - -## Running Examples - -Each example is self-contained and can be run independently: - -```bash -cd examples/01-basic-connection -php example.php -``` - -## Database Setup - -Most examples assume a MySQL database with the following configuration: -- Host: localhost -- Username: root -- Password: 123456 -- Database: mysql (using system database for examples) - -You can modify the connection parameters in each example as needed. - -## Example Features Demonstrated - -### 01-basic-connection -- Creating `ConnectionInfo` objects -- Establishing database connections -- Testing connections with simple queries - -### 02-basic-queries -- Table creation and management -- INSERT operations with data validation -- SELECT operations with filtering and conditions -- UPDATE operations with WHERE clauses -- DELETE operations with conditions -- Query result handling - -### 03-table-blueprints -- Creating table blueprints with column definitions -- Using different data types (INT, VARCHAR, TEXT, TIMESTAMP) -- Setting column constraints (PRIMARY KEY, NOT NULL, AUTO_INCREMENT) -- Creating foreign key relationships -- Generating and executing CREATE TABLE statements - -### 04-entity-mapping -- Generating entity classes from table blueprints -- Mapping database records to PHP objects -- Working with mapped objects and their methods -- Filtering and manipulating object collections - -### 05-transactions -- Creating database transactions for data integrity -- Handling successful transaction commits -- Automatic rollback on transaction failures -- Error handling within transactions -- Complex multi-table operations - -### 06-migrations -- Creating migration classes extending `AbstractMigration` -- Using `SchemaRunner` for migration management -- Registering migrations with the schema runner -- Applying and rolling back migrations -- Schema change tracking and versioning - -### 07-seeders -- Creating seeder classes extending `AbstractSeeder` -- Using `SchemaRunner` for seeder management -- Registering seeders with the schema runner -- Populating database with sample data -- Environment-specific seeding - -### 08-performance-monitoring -- Configuring performance monitoring settings -- Tracking query execution times and statistics -- Identifying slow queries and performance bottlenecks -- Using `PerformanceAnalyzer` for detailed analysis -- Performance optimization recommendations - -## Notes - -- All examples include proper error handling and cleanup -- Generated files (like entity classes) are automatically cleaned up -- Examples use temporary tables that are dropped after execution -- Each example is thoroughly tested and produces expected output +# WebFiori Database Examples + +This directory contains practical examples demonstrating how to use the WebFiori Database Abstraction Layer. + +## Examples Overview + +1. **[01-basic-connection](01-basic-connection/)** - How to establish database connections +2. **[02-basic-queries](02-basic-queries/)** - CRUD operations (Insert, Select, Update, Delete) +3. **[03-table-blueprints](03-table-blueprints/)** - Creating and managing database table structures +4. **[04-entity-mapping](04-entity-mapping/)** - Working with entity classes and object mapping +5. **[05-transactions](05-transactions/)** - Database transactions for data integrity +6. **[06-migrations](06-migrations/)** - Database schema migrations and versioning +7. **[07-seeders](07-seeders/)** - Database data seeding and population +8. **[08-performance-monitoring](08-performance-monitoring/)** - Query performance tracking and analysis +9. **[09-multi-result-queries](09-multi-result-queries/)** - Multi-result query handling and stored procedures + +## Prerequisites + +- PHP 8.1 or higher +- MySQL or MSSQL database server +- Composer dependencies installed + +## Running Examples + +Each example is self-contained and can be run independently: + +```bash +cd examples/01-basic-connection +php example.php +``` + +## Database Setup + +Most examples assume a MySQL database with the following configuration: +- Host: localhost +- Username: root +- Password: 123456 +- Database: mysql (using system database for examples) + +You can modify the connection parameters in each example as needed. + +## Example Features Demonstrated + +### 01-basic-connection +- Creating `ConnectionInfo` objects +- Establishing database connections +- Testing connections with simple queries + +### 02-basic-queries +- Table creation and management +- INSERT operations with data validation +- SELECT operations with filtering and conditions +- UPDATE operations with WHERE clauses +- DELETE operations with conditions +- Query result handling + +### 03-table-blueprints +- Creating table blueprints with column definitions +- Using different data types (INT, VARCHAR, TEXT, TIMESTAMP) +- Setting column constraints (PRIMARY KEY, NOT NULL, AUTO_INCREMENT) +- Creating foreign key relationships +- Generating and executing CREATE TABLE statements + +### 04-entity-mapping +- Generating entity classes from table blueprints +- Mapping database records to PHP objects +- Working with mapped objects and their methods +- Filtering and manipulating object collections + +### 05-transactions +- Creating database transactions for data integrity +- Handling successful transaction commits +- Automatic rollback on transaction failures +- Error handling within transactions +- Complex multi-table operations + +### 06-migrations +- Creating migration classes extending `AbstractMigration` +- Using `SchemaRunner` for migration management +- Registering migrations with the schema runner +- Applying and rolling back migrations +- Schema change tracking and versioning + +### 07-seeders +- Creating seeder classes extending `AbstractSeeder` +- Using `SchemaRunner` for seeder management +- Registering seeders with the schema runner +- Populating database with sample data +- Environment-specific seeding + +### 08-performance-monitoring +- Configuring performance monitoring settings +- Tracking query execution times and statistics +- Identifying slow queries and performance bottlenecks +- Using `PerformanceAnalyzer` for detailed analysis +- Performance optimization recommendations + +### 09-multi-result-queries +- Executing stored procedures that return multiple result sets +- Working with `MultiResultSet` objects +- Processing individual result sets from multi-result queries +- Parameterized stored procedure calls using `raw()` method +- Complex business reporting with multiple data views + +## Notes + +- All examples include proper error handling and cleanup +- Generated files (like entity classes) are automatically cleaned up +- Examples use temporary tables that are dropped after execution +- Each example is thoroughly tested and produces expected output