From 51609351f2c4b5082b7e6f0744cd3811c325303f Mon Sep 17 00:00:00 2001
From: emkael ';
+ * $qp = qp(QueryPath::HTML_STUB, 'body') // Open a stub HTML doc and select
Title 0 | + *Body 0 | + *Footer 0 | + *
Title 1 | + *Body 1 | + *Footer 1 | + *
Title 2 | + *Body 2 | + *Footer 2 | + *
Title 3 | + *Body 3 | + *Footer 3 | + *
Title 4 | + *Body 4 | + *Footer 4 | + *
Body 1
+ * Footer 1 + * + * @endcode + * + * Notice the body section in particular. This is where the data has been + * inserted. + * + * Sometimes you want to do something a lot simpler, like give QueryPath a + * template and have it navigate a query, inserting the data into a template, and + * then inserting the template into the document. This can be done simply with + * the {@link queryInto()} function. + * + * Here's an example from another unit test: + * + * @code + * '; + * $sql = 'SELECT * FROM qpdb_test'; + * $args = array(); + * $qp = qp(QueryPath::HTML_STUB, 'body') + * ->append('
+ * 'myColumn');
+ * qp()->query('SELECT :something FROM foo', $args)->doneWithQuery();
+ * ?>
+ *
+ *
+ * The above would execute the given query, substituting myColumn in place of
+ * :something before executing the query The {@link doneWithQuery()} method
+ * indicates that we are not going to use the results for anything. This method
+ * discards the results.
+ *
+ * A more typical use of the query() function would involve inserting data
+ * using {@link appendColumn()}, {@link prependColumn()}, {@link columnBefore()},
+ * or {@link columnAfter()}. See the main documentation for {@link QPDB} to view
+ * a more realistic example.
+ *
+ * @param string $sql
+ * The query to be executed.
+ * @param array $args
+ * An associative array of substitutions to make.
+ * @throws PDOException
+ * Throws an exception if the query cannot be executed.
+ */
+ public function query($sql, $args = array()) {
+ $this->stmt = $this->db->prepare($sql);
+ $this->stmt->execute($args);
+ return $this->qp;
+ }
+
+ /**
+ * Query and append the results.
+ *
+ * Run a query and inject the results directly into the
+ * elements in the QueryPath object.
+ *
+ * If the third argument is empty, the data will be inserted directly into
+ * the QueryPath elements unaltered. However, if a template is provided in
+ * the third parameter, the query data will be merged into that template
+ * and then be added to each QueryPath element.
+ *
+ * The template will be merged once for each row, even if no row data is
+ * appended into the template.
+ *
+ * A template is simply a piece of markup labeled for insertion of
+ * data. See {@link QPTPL} and {@link QPTPL.php} for more information.
+ *
+ * Since this does not use a stanard {@link query()}, there is no need
+ * to call {@link doneWithQuery()} after this method.
+ *
+ * @param string $sql
+ * The SQL query to execute. In this context, the query is typically a
+ * SELECT statement.
+ * @param array $args
+ * An array of arguments to be substituted into the query. See {@link query()}
+ * for details.
+ * @param mixed $template
+ * A template into which query results will be merged prior to being appended
+ * into the QueryPath. For details on the template, see {@link QPTPL::tpl()}.
+ * @see QPTPL.php
+ * @see QPTPL::tpl()
+ * @see query()
+ */
+ public function queryInto($sql, $args = array(), $template = NULL) {
+ $stmt = $this->db->prepare($sql);
+ $stmt->setFetchMode(PDO::FETCH_ASSOC);
+ $stmt->execute($args);
+
+ // If no template, put all values in together.
+ if (empty($template)) {
+ foreach ($stmt as $row) foreach ($row as $datum) $this->qp->append($datum);
+ }
+ // Otherwise, we run the results through a template, and then append.
+ else {
+ foreach ($stmt as $row) $this->qp->tpl($template, $row);
+ }
+
+ $stmt->closeCursor();
+ return $this->qp;
+ }
+
+ /**
+ * Free up resources when a query is no longer used.
+ *
+ * This function should always be called when the database
+ * results for a query are no longer needed. This frees up the
+ * database cursor, discards the data, and resets resources for future
+ * use.
+ *
+ * If this method is not called, some PDO database drivers will not allow
+ * subsequent queries, while others will keep tables in a locked state where
+ * writes will not be allowed.
+ *
+ * @return QueryPath
+ * The QueryPath object.
+ */
+ public function doneWithQuery() {
+ if (isset($this->stmt) && $this->stmt instanceof PDOStatement) {
+ // Some drivers choke if results haven't been iterated.
+ //while($this->stmt->fetch()) {}
+ $this->stmt->closeCursor();
+ }
+
+ unset($this->stmt);
+ $this->row = NULL;
+ $this->cycleRows = FALSE;
+ return $this->qp;
+ }
+
+ /**
+ * Execute a SQL query, but expect no value.
+ *
+ * If your SQL query will have parameters, you are encouraged to
+ * use {@link query()}, which includes built-in SQL Injection
+ * protection.
+ *
+ * @param string $sql
+ * A SQL statement.
+ * @throws PDOException
+ * An exception will be thrown if a query cannot be executed.
+ */
+ public function exec($sql) {
+ $this->db->exec($sql);
+ return $this->qp;
+ }
+
+ /**
+ * Advance the query results row cursor.
+ *
+ * In a result set where more than one row was returned, this will
+ * move the pointer to the next row in the set.
+ *
+ * The PDO library does not have a consistent way of determining how many
+ * rows a result set has. The suggested technique is to first execute a
+ * COUNT() SQL query and get the data from that.
+ *
+ * The {@link withEachRow()} method will begin at the next row after the
+ * currently selected one.
+ *
+ * @return QueryPath
+ * The QueryPath object.
+ */
+ public function nextRow() {
+ $this->row = $this->stmt->fetch(PDO::FETCH_ASSOC);
+ return $this->qp;
+ }
+
+ /**
+ * Set the object to use each row, instead of only one row.
+ *
+ * This is used primarily to instruct QPDB to iterate through all of the
+ * rows when appending, prepending, inserting before, or inserting after.
+ *
+ * @return QueryPath
+ * The QueryPath object.
+ * @see appendColumn()
+ * @see prependColumn()
+ * @see columnBefore()
+ * @see columnAfter()
+ */
+ public function withEachRow() {
+ $this->cycleRows = TRUE;
+ return $this->qp;
+ }
+
+ /**
+ * This is the implementation behind the append/prepend and before/after methods.
+ *
+ * @param mixed $columnName
+ * The name of the column whose data should be added to the currently selected
+ * elements. This can be either a string or an array of strings.
+ * @param string $qpFunc
+ * The name of the QueryPath function that should be executed to insert data
+ * into the object.
+ * @param string $wrap
+ * The HTML/XML markup that will be used to wrap around the column data before
+ * the data is inserted into the QueryPath object.
+ */
+ protected function addData($columnName, $qpFunc = 'append', $wrap = NULL) {
+ $columns = is_array($columnName) ? $columnName : array($columnName);
+ $hasWrap = !empty($wrap);
+ if ($this->cycleRows) {
+ while (($row = $this->stmt->fetch(PDO::FETCH_ASSOC)) !== FALSE) {
+ foreach ($columns as $col) {
+ if (isset($row[$col])) {
+ $data = $row[$col];
+ if ($hasWrap)
+ $data = qp()->append($wrap)->deepest()->append($data)->top();
+ $this->qp->$qpFunc($data);
+ }
+ }
+ }
+ $this->cycleRows = FALSE;
+ $this->doneWithQuery();
+ }
+ else {
+ if ($this->row !== FALSE) {
+ foreach ($columns as $col) {
+ if (isset($this->row[$col])) {
+ $data = $this->row[$col];
+ if ($hasWrap)
+ $data = qp()->append($wrap)->deepest()->append($data)->top();
+ $this->qp->$qpFunc($data);
+ }
+ }
+ }
+ }
+ return $this->qp;
+ }
+
+ /**
+ * Get back the raw PDOStatement object after a {@link query()}.
+ *
+ * @return PDOStatement
+ * Return the PDO statement object. If this is called and no statement
+ * has been executed (or the statement has already been cleaned up),
+ * this will return NULL.
+ */
+ public function getStatement() {
+ return $this->stmt;
+ }
+
+ /**
+ * Get the last insert ID.
+ *
+ * This will only return a meaningful result when used after an INSERT.
+ *
+ * @return mixed
+ * Return the ID from the last insert. The value and behavior of this
+ * is database-dependent. See the official PDO driver documentation for
+ * the database you are using.
+ * @since 1.3
+ */
+ public function getLastInsertID() {
+ $con = self::$con;
+ return $con->lastInsertId();
+ }
+
+ /**
+ * Append the data in the given column(s) to the QueryPath.
+ *
+ * This appends data to every item in the current QueryPath. The data will
+ * be retrieved from the database result, using $columnName as the key.
+ *
+ * @param mixed $columnName
+ * Either a string or an array of strings. The value(s) here should match
+ * one or more column headers from the current SQL {@link query}'s results.
+ * @param string $wrap
+ * IF this is supplied, then the value or values retrieved from the database
+ * will be wrapped in this HTML/XML before being inserted into the QueryPath.
+ * @see QueryPath::wrap()
+ * @see QueryPath::append()
+ */
+ public function appendColumn($columnName, $wrap = NULL) {
+ return $this->addData($columnName, 'append', $wrap);
+ }
+
+ /**
+ * Prepend the data from the given column into the QueryPath.
+ *
+ * This takes the data from the given column(s) and inserts it into each
+ * element currently found in the QueryPath.
+ * @param mixed $columnName
+ * Either a string or an array of strings. The value(s) here should match
+ * one or more column headers from the current SQL {@link query}'s results.
+ * @param string $wrap
+ * IF this is supplied, then the value or values retrieved from the database
+ * will be wrapped in this HTML/XML before being inserted into the QueryPath.
+ * @see QueryPath::wrap()
+ * @see QueryPath::prepend()
+ */
+ public function prependColumn($columnName, $wrap = NULL) {
+ return $this->addData($columnName, 'prepend', $wrap);
+ }
+
+ /**
+ * Insert the data from the given column before each element in the QueryPath.
+ *
+ * This inserts the data before each element in the currently matched QueryPath.
+ *
+ * @param mixed $columnName
+ * Either a string or an array of strings. The value(s) here should match
+ * one or more column headers from the current SQL {@link query}'s results.
+ * @param string $wrap
+ * IF this is supplied, then the value or values retrieved from the database
+ * will be wrapped in this HTML/XML before being inserted into the QueryPath.
+ * @see QueryPath::wrap()
+ * @see QueryPath::before()
+ * @see prependColumn()
+ */
+ public function columnBefore($columnName, $wrap = NULL) {
+ return $this->addData($columnName, 'before', $wrap);
+ }
+
+ /**
+ * Insert data from the given column(s) after each element in the QueryPath.
+ *
+ * This inserts data from the given columns after each element in the QueryPath
+ * object. IF HTML/XML is given in the $wrap parameter, then the column data
+ * will be wrapped in that markup before being inserted into the QueryPath.
+ *
+ * @param mixed $columnName
+ * Either a string or an array of strings. The value(s) here should match
+ * one or more column headers from the current SQL {@link query}'s results.
+ * @param string $wrap
+ * IF this is supplied, then the value or values retrieved from the database
+ * will be wrapped in this HTML/XML before being inserted into the QueryPath.
+ * @see QueryPath::wrap()
+ * @see QueryPath::after()
+ * @see appendColumn()
+ */
+ public function columnAfter($columnName, $wrap = NULL) {
+ return $this->addData($columnName, 'after', $wrap);
+ }
+
+}
+
+// The define allows another class to extend this.
+if (!defined('QPDB_OVERRIDE'))
+ QueryPathExtensionRegistry::extend('QPDB');
\ No newline at end of file
--
cgit v1.2.3
+ * ->append('
') + * ->queryInto('SELECT * FROM qpdb_test WHERE 1', array(), $template) + * ->doneWithQuery() + * ->writeHTML(); + * ?> + * @endcode + * + * Note that in this case, the QueryPath object doesn't need to call a method to + * activate the database. There is no call to {@link dbInit()}. Instead, it checks + * the base class to find the shared database. + * + * (Note that if you were to add a dbInit() call to the above, it would create + * a new database connection.) + * + * The result of both of these examples will be identical. + * The output looks something like this: + * + * @code + * + * + *
+ * + *
+ * + *