Example #1
0
	/**
	 * Performs a batch of changes wrapped in a database transaction.
	 * The batch `$task` can be an array of items to insert at once,
	 * or a closure function that executes a series of tasks and
	 * performs whatever logic necessary. If any insert fails, or if
	 * the function returns false, the transaction will be rolled
	 * back, otherwise it will be committed. For databases that support
	 * it, records will be inserted using a single SQL insert statement
	 * for greater efficiency.
	 */
	public static function batch ($tasks) {
		DB::execute ('begin');
		if ($tasks instanceof Closure) {
			if ($tasks () === false) {
				self::$batch_error = DB::error ();
				DB::execute ('rollback');
				return false;
			}
		} elseif (is_array ($tasks)) {
			// Check the driver type, because SQLite doesn't support
			// multiple row inserts
			$db = DB::get_connection (1);
			if (! $db) {
				self::$batch_error = 'No database connection';
				return false;
			}

			if ($db->getAttribute (PDO::ATTR_DRIVER_NAME) === 'sqlite') {
				$class = get_called_class ();
				foreach ($tasks as $task) {
					$o = new $class ($task);
					if (! $o->put ()) {
						self::$batch_error = $o->error;
						DB::execute ('rollback');
						return false;
					}
				}
				return DB::execute ('commit');
			}

			// Build the multi-row insert statement
			$class = get_called_class ();
			$o = new $class;
			$sql = 'insert into `' . $o->table . '` (';
			$data = array ();

			// Figure out how many placeholders are needed per record
			$ins = array ();
			$len = count ($tasks[0]);
			for ($i = 0; $i < $len; $i++) {
				$ins[] = '?';
			}

			// Add fields to statement
			$sql .= join (', ', Model::backticks (array_keys ($tasks[0]))) . ') values ';
			$sep = '';

			// Add each record to the statement
			foreach ($tasks as $task) {
				$data = array_merge ($data, array_values ($task));
				$sql .= $sep . '(' . join (', ', $ins) . ')';
				$sep = ', ';
			}

			if (! DB::execute ($sql, $data)) {
				self::$batch_error = DB::error ();
				DB::execute ('rollback');
				return false;
			}
		}
		return DB::execute ('commit');
	}