[Solar-svn] Revision 2887
pmjones at solarphp.com
pmjones at solarphp.com
Thu Oct 18 08:14:52 CDT 2007
updated todo notes and "hold" classes
Deleted: hold/Html.php
===================================================================
--- hold/Html.php 2007-10-18 13:07:06 UTC (rev 2886)
+++ hold/Html.php 2007-10-18 13:14:52 UTC (rev 2887)
@@ -1,138 +0,0 @@
-<?php
-Solar::loadClass('Solar_Markdown_Rule');
-class Solar_Markdown_Rule_Html extends Solar_Markdown_Rule {
-
- /**
- *
- * Replaces block-level HTML with hash references.
- *
- * Stores the blocks for later replacement.
- *
- * @param string $text A portion of the Markdown source.
- *
- * @return string The source with hash refs instead of HTML blocks.
- *
- */
- public function parse($text)
- {
- $less_than_tab = $this->_tab_width - 1;
-
- // Hashify HTML blocks:
- // We only want to do this for block-level HTML tags, such as
- // headers, lists, and tables. That's because we still want to
- // wrap <p>s around "paragraphs" that are wrapped in
- // non-block-level tags, such as anchors, phrase emphasis, and
- // spans. The list of tags we're looking for is hard-coded:
- $block_tags_a = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|'.
- 'script|noscript|form|fieldset|iframe|math|ins|del';
- $block_tags_b = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|'.
- 'script|noscript|form|fieldset|iframe|math';
-
- // First, look for nested blocks, e.g.:
- // <div>
- // <div>
- // tags for inner block must be indented.
- // </div>
- // </div>
- //
- // The outermost tags must start at the left margin for this to match, and
- // the inner nested divs must be indented.
- // We need to do this before the next, more liberal match, because the next
- // match will start at the first `<div>` and stop at the first `</div>`.
- $text = preg_replace_callback(
- "{
- ( # save in $1
- ^ # start of line (with /m)
- <($block_tags_a) # start tag = $2
- \\b # word break
- (.*\\n)*? # any number of lines, minimally matching
- </\\2> # the matching end tag
- [ \\t]* # trailing spaces/tabs
- (?=\\n+|\\Z) # followed by a newline or end of document
- )
- }xm",
- array($this, '_parse'),
- $text
- );
-
- // Now match more liberally, simply from `\n<tag>` to `</tag>\n`
- $text = preg_replace_callback(
- "{
- ( # save in $1
- ^ # start of line (with /m)
- <($block_tags_b) # start tag = $2
- \\b # word break
- (.*\\n)*? # any number of lines, minimally matching
- .*</\\2> # the matching end tag
- [ \\t]* # trailing spaces/tabs
- (?=\\n+|\\Z) # followed by a newline or end of document
- )
- }xm",
- array($this, '_parse'),
- $text
- );
-
- // Special case just for <hr />. It was easier to make a special case than
- // to make the other regex more complicated.
- $text = preg_replace_callback(
- '{
- (?:
- (?<=\n\n) # Starting after a blank line
- | # or
- \A\n? # the beginning of the doc
- )
- ( # save in $1
- [ ]{0,'.$less_than_tab.'}
- <(hr) # start tag = $2
- \b # word break
- ([^<>])*? #
- /?> # the matching end tag
- [ \t]*
- (?=\n{2,}|\Z) # followed by a blank line or end of document
- )
- }x',
- array($this, '_parse'),
- $text
- );
-
- // Special case for standalone HTML comments:
- $text = preg_replace_callback(
- '{
- (?:
- (?<=\n\n) # Starting after a blank line
- | # or
- \A\n? # the beginning of the doc
- )
- ( # save in $1
- [ ]{0,'.$less_than_tab.'}
- (?s:
- <!
- (--.*?--\s*)+
- >
- )
- [ \t]*
- (?=\n{2,}|\Z) # followed by a blank line or end of document
- )
- }x',
- array($this, '_parse'),
- $text
- );
-
- return $text;
- }
-
- /**
- *
- * Support callback for hashing HTML blocks.
- *
- * @param array $matches Matches from preg_replace_callback().
- *
- * @return string The replacement text.
- *
- */
- protected function _parse($matches)
- {
- return "\n\n" . $this->_tokenize($matches[1]) . "\n\n";
- }
-}
-?>
\ No newline at end of file
Deleted: hold/LinkDefined.php
===================================================================
--- hold/LinkDefined.php 2007-10-18 13:07:06 UTC (rev 2886)
+++ hold/LinkDefined.php 2007-10-18 13:14:52 UTC (rev 2887)
@@ -1,48 +0,0 @@
-<?php
-Solar::loadClass('Solar_Markdown_Rule');
-class Solar_Markdown_Rule_LinkDefined extends Solar_Markdown_Rule {
-
- protected $_links = array();
-
- // finds link definitions in the text
- public function filter($text)
- {
- $less_than_tab = $this->_tab_width - 1;
-
- $text = preg_replace_callback(
- '{
- ^[ ]{0,'.$less_than_tab.'}\[(.+)\]: # id = $1
- [ \t]*
- \n? # maybe *one* newline
- [ \t]*
- <?(\S+?)>? # url = $2
- [ \t]*
- \n? # maybe one newline
- [ \t]*
- (?:
- (?<=\s) # lookbehind for whitespace
- ["(]
- (.+?) # title = $3
- [")]
- [ \t]*
- )? # title is optional
- (?:\n+|\Z)
- }xm',
- array($this, '_filter'),
- $text
- );
- return $text;
- }
-
- // removes link definitions from the text and saves for later
- protected function _filter($matches)
- {
- $id = strtolower($matches[1]);
- $this->_links[$id] = array(
- 'href' => $matches[2],
- 'title' => (empty($matches[3]) ? '' : $matches[3]),
- );
- // no return, we strip it from the text
- }
-}
-?>
\ No newline at end of file
Copied: hold/Solar_Sql_Adapter_Mssql.php (from rev 2853, trunk/Solar/Sql/Adapter/Mssql.php)
===================================================================
--- hold/Solar_Sql_Adapter_Mssql.php (rev 0)
+++ hold/Solar_Sql_Adapter_Mssql.php 2007-10-18 13:14:52 UTC (rev 2887)
@@ -0,0 +1,441 @@
+<?php
+/**
+ *
+ * Class for connecting to Microsoft SQL databases.
+ *
+ * @category Solar
+ *
+ * @package Solar_Sql
+ *
+ * @author Paul M. Jones <pmjones at solarphp.com>
+ *
+ * @author Stefan Bogdan <stefan_bogdan_daniel at yahoo.com>
+ *
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ *
+ * @version $Id$
+ *
+ */
+
+/**
+ *
+ * Class for connecting to Microsoft SQL databases.
+ *
+ * @category Solar
+ *
+ * @package Solar_Sql
+ *
+ * @todo Transaction support
+ *
+ * @todo Better date/time creation
+ *
+ * @todo Build tests
+ *
+ */
+class Solar_Sql_Adapter_Mssql extends Solar_Sql_Adapter {
+
+ /**
+ *
+ * Map of Solar generic column types to RDBMS native declarations.
+ *
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_da-db_7msw.asp
+ *
+ * @var array
+ *
+ */
+ protected $_native = array(
+ 'bool' => 'BIT',
+ 'char' => 'CHAR',
+ 'varchar' => 'VARCHAR',
+ 'smallint' => 'SMALLINT',
+ 'int' => 'INTEGER',
+ 'bigint' => 'BIGINT',
+ 'numeric' => 'DECIMAL',
+ 'float' => 'FLOAT',
+ 'clob' => 'TEXT',
+ 'date' => 'CHAR(10)',
+ 'time' => 'CHAR(8)',
+ 'timestamp' => 'DATETIME'
+ );
+
+ /**
+ *
+ * The PDO adapter type.
+ *
+ * Default is 'dblib', but on Windows systems it is 'mssql'.
+ *
+ * @var string
+ *
+ */
+ protected $_pdo_type = 'dblib';
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param array $config User-provided configuration values.
+ *
+ */
+ public function __construct($config = null)
+ {
+ parent::__construct($config);
+
+ // if we're on windows, use the 'mssql' PDO type
+ if (substr(PHP_OS, 0, 3) == 'WIN') {
+ $this->_pdo_type = 'mssql';
+ }
+ }
+
+ /**
+ *
+ * Creates a PDO-style DSN.
+ *
+ * For example, "mysql:host=127.0.0.1;dbname=test"
+ *
+ * @return string A PDO-style DSN.
+ *
+ */
+ protected function _dsn()
+ {
+ // the default build process
+ if ($this->_pdo_type != 'mssql') {
+ return parent::_dsn();
+ }
+
+ // special build process for 'mssql' pdo type on Windows
+ $dsn = array();
+
+ // the host
+ if (! empty($this->_config['host'])) {
+ $tmp = 'host=' . $this->_config['host'];
+ // the port
+ if (! empty($this->_config['port'])) {
+ $tmp = $tmp . ',' . $this->_config['port'];
+ }
+ $dsn[] = $tmp;
+ }
+
+ // database name
+ if (! empty($this->_config['name'])) {
+ $dsn[] = 'dbname=' . $this->_config['name'];
+ }
+
+ // done!
+ return $this->_pdo_type . ':' . implode(';', $dsn);
+ }
+
+ /**
+ *
+ * Modifies a SELECT statement in place to add a LIMIT clause.
+ *
+ * <http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html>
+ *
+ * @param string &$stmt The SELECT statement.
+ *
+ * @param array &$parts The orignal SELECT component parts, in case the
+ * adapter needs them.
+ *
+ * @return void
+ *
+ */
+ protected function _modSelect(&$stmt, &$parts)
+ {
+ // determine count
+ $count = ! empty($parts['limit']['count'])
+ ? (int) $parts['limit']['count']
+ : 0;
+
+ // determine offset
+ $offset = ! empty($parts['limit']['offset'])
+ ? (int) $parts['limit']['offset']
+ : 0;
+
+ // add limits?
+ if ($count) {
+
+ // is there an offset?
+ if (! $offset) {
+ // no, so it's a simple TOP request
+ if ($parts['distinct']) {
+ $top = "SELECT DISTINCT TOP $count";
+ $pos = 15; // SELECT DISTINCT
+ } else {
+ $top = "SELECT TOP $count";
+ $pos = 6; // SELECT
+ }
+
+ // replace with the TOP clause, and done!
+ return $top . substr($stmt, $pos);
+ }
+
+ // the total of the count **and** the offset, combined.
+ // this will be used in the "internal" portion of the
+ // hacked-up statement.
+ $total = $count + $offset;
+
+ // build the "real" order for the external portion.
+ $order = implode(',', $parts['order']);
+
+ // build a "reverse" order for the internal portion.
+ $reverse = $order;
+ $reverse = str_ireplace(" ASC", " \xFF", $reverse);
+ $reverse = str_ireplace(" DESC", " ASC", $reverse);
+ $reverse = str_ireplace(" \xFF", " DESC", $reverse);
+
+ // create a main statement that replaces the SELECT with a
+ // SELECT TOP
+ if ($parts['distinct']) {
+ $top = "SELECT DISTINCT TOP $total";
+ $pos = 15; // SELECT DISTINCT
+ } else {
+ $top = "SELECT TOP $total";
+ $pos = 6; // SELECT
+ }
+ $main = "\n$top" . substr($stmt, $pos) . "\n";
+
+ // build the hacked-up statement.
+ // do we really need the "as" aliases here?
+ $stmt = "SELECT * FROM (";
+ $stmt .= "SELECT TOP $count * FROM ($main) AS solar_limit_rev ORDER BY $reverse";
+ $stmt .= ") AS solar_limit ORDER BY $order";
+ }
+ }
+
+ /**
+ *
+ * Returns a list of all tables in the database.
+ *
+ * @return array All table names in the database.
+ *
+ */
+ protected function _fetchTableList()
+ {
+ $cmd = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name";
+ $result = $this->query($cmd);
+ $list = $result->fetchAll(PDO::FETCH_COLUMN, 0);
+ return $list;
+ }
+
+ /**
+ *
+ * Returns an array describing the columns in a table.
+ *
+ * @param string $table The table name to fetch columns for.
+ *
+ * @return array An array of table columns.
+ *
+ */
+ protected function _fetchTableCols($table)
+ {
+ $cmd = "
+ SELECT
+ C.COLUMN_NAME AS name,
+ C.DATA_TYPE AS type,
+ C.IS_NULLABLE AS allow_nulls,
+ C.NUMERIC_PRECISION AS size,
+ C.NUMERIC_SCALE AS scope,
+ (SELECT 't'
+ FROM
+ information_schema.key_column_usage AS k,
+ information_schema.table_constraints AS tc
+ WHERE
+ tc.constraint_name = k.constraint_name
+ AND tc.constraint_type = 'PRIMARY KEY'
+ AND k.table_name = :table
+ AND k.column_name = c.COLUMN_NAME
+ ) AS primary_key,
+ c.COLUMN_DEFAULT,
+ COLUMNPROPERTY( OBJECT_ID('tabela'), C.COLUMN_NAME, 'IsIdentity') AS autoinc
+ FROM INFORMATION_SCHEMA.Tables T
+ JOIN INFORMATION_SCHEMA.Columns AS C ON T.TABLE_NAME = C.TABLE_NAME
+ WHERE
+ T.TABLE_NAME NOT LIKE 'sys%'
+ AND T.TABLE_NAME = :table
+ ";
+
+ // where the description will be stored
+ $descr = array();
+
+ // loop through the result rows; each describes a column.
+ $cols = $this->fetchAll($cmd, array('table' => $table));
+ foreach ($cols as $val) {
+ $name = $val['name'];
+ list($type, $size, $scope) = $this->_getTypeSizeScope($val['type']);
+ $descr[$name] = array(
+ 'name' => $name,
+ 'type' => $type,
+ 'size' => $val['size'],
+ 'scope' => $val['scope'],
+ 'default' => $this->_getDefault($val['column_default']),
+ 'require' => (bool) ($val['allow_nulls'] == 'NO'),
+ 'primary' => (bool) ($val['primary_key'] == 't'),
+ 'autoinc' => (bool) ($val['autoinc'] == 1),
+ );
+ }
+
+ // done
+ return $descr;
+ }
+
+ /**
+ *
+ * Drops an index.
+ *
+ * @param string $table The table of the index.
+ *
+ * @param string $name The full index name.
+ *
+ * @return void
+ *
+ */
+ protected function _dropIndex($table, $name)
+ {
+ // http://www.w3schools.com/sql/sql_drop.asp
+ $this->query("DROP INDEX {$table}.{$name}");
+ }
+
+ /**
+ *
+ * Get the last auto-incremented insert ID from the database.
+ *
+ * @param string $table The table name on which the auto-increment occurred.
+ *
+ * @param string $col The name of the auto-increment column.
+ *
+ * @return int The last auto-increment ID value inserted to the database.
+ *
+ */
+ public function lastInsertId($table = null, $col = null)
+ {
+ $this->_connect();
+ return $this->fetchValue('SELECT @@IDENTITY AS id');
+ }
+
+ /**
+ *
+ * Creates a sequence, optionally starting at a certain number.
+ *
+ * @param string $name The sequence name to create.
+ *
+ * @param int $start The first sequence number to return.
+ *
+ * @return void
+ *
+ */
+ protected function _createSequence($name, $start = 1)
+ {
+ $start = (int) $start;
+ $this->query(
+ "CREATE TABLE $name (id INT NOT NULL " .
+ "IDENTITY($start,1) PRIMARY KEY CLUSTERED)"
+ );
+ }
+
+ /**
+ *
+ * Drops a sequence.
+ *
+ * @param string $name The sequence name to drop.
+ *
+ * @return void
+ *
+ */
+ protected function _dropSequence($name)
+ {
+ $this->query("DROP TABLE $name");
+ }
+
+ /**
+ *
+ * Gets a sequence number; creates the sequence if it does not exist.
+ *
+ * @param string $name The sequence name.
+ *
+ * @return int The next sequence number.
+ *
+ */
+ protected function _nextSequence($name)
+ {
+ $cmd = "INSERT INTO $name DEFAULT VALUES";
+
+ // first, try to increment the sequence number, assuming
+ // the table exists.
+ try {
+ $this->query($cmd);
+ } catch (Exception $e) {
+ // error when updating the sequence.
+ // assume we need to create it, then
+ // try to increment again.
+ $this->_createSequence($name);
+ $this->query($cmd);
+ }
+
+ // get the sequence number
+ $stmt = $this->query("SELECT @@IDENTITY FROM $name");
+ $id = $stmt->fetchColumn(0);
+
+ // now that we have a new sequence number, delete any earlier rows
+ // to keep the table small. should this be a trigger instead?
+ $this->query("DELETE FROM $name WHERE id < $id");
+
+ // return the sequence number
+ return $id;
+ }
+
+ /**
+ *
+ * Given a native column SQL default value, finds a PHP literal value.
+ *
+ * SQL NULLs are converted to PHP nulls. Non-literal values (such as
+ * keywords and functions) are also returned as null.
+ *
+ * @param string $default The column default SQL value.
+ *
+ * @return scalar A literal PHP value.
+ *
+ */
+ protected function _getDefault($default)
+ {
+ $default = str_replace(
+ array('(', ')'),
+ '',
+ $default
+ );
+
+ // numeric literal?
+ if (is_numeric($default)) {
+ return $default;
+ }
+
+ if ($default == NULL) {
+ return null;
+ }
+
+ return $default;
+ }
+
+ /**
+ *
+ * Given a column definition, modifies the auto-increment and primary-key
+ * clauses in place.
+ *
+ * @param string &$coldef The column definition as it is now.
+ *
+ * @param bool $autoinc Whether or not this is an auto-increment column.
+ *
+ * @param bool $primary Whether or not this is a primary-key column.
+ *
+ * @return void
+ *
+ */
+ protected function _modAutoincPrimary(&$coldef, $autoinc, $primary)
+ {
+ if ($autoinc) {
+ $coldef .= " IDENTITY";
+ }
+
+ if ($primary) {
+ $coldef .= " PRIMARY KEY";
+ }
+ }
+}
Modified: todo/todo.txt
===================================================================
--- todo/todo.txt 2007-10-18 13:07:06 UTC (rev 2886)
+++ todo/todo.txt 2007-10-18 13:14:52 UTC (rev 2887)
@@ -1,42 +1,43 @@
In General
==========
+
+Docs/Website
+============
+
* Write up a graphic of request lifetime (per Clay)
* Write up notes on when to use config keys for dependency injection, and when
to use method-based injection (e.g., Page::setFrontController()).
-* Re-convert back to Solar_Test
-
-* Solar_Test should be isolated to its own PHP env: re-build the test system
- to invoke a new PHP executable for each test method, which will clear any
- statics, etc.
-
* Link to #solarphp on the Solar site; might need a "Community" page instead
of a Mailing-List page.
+* From Kilbride: "btw, for your online manual at solarphp.com/manual.. once I
+ get into a section I can't go back to the contents through the interface
+ there. May want to add a 'top' link or something through out it so you can.
+ It's been bugging me all day."
+
+* Write up templates for SQL relations so that others can see what the
+ queries are.
+
+
+Possible Structural Changes
+===========================
+
* Put Solar.php arch-class file *inside* the Solar dir, so you can svn
external better. This is against all the standards, but I think for this
one special case it might be explainable.
+* Change from Solar to Solar_Framework? That sucks for typing, but makes the
+ SVN change more in line with PEAR standards.
+
* Remove spl_autoload registrations from the arch-class file, to make it
*just* the class definition? or put the spl defs inside Solar::start() ?
-* Is SOLAR_IGNORE_PARAM an unnecessaray micro-optimization?
+* Re-convert back to Solar_Test
-* From Kilbride: "btw, for your online manual at solarphp.com/manual.. once I
- get into a section I can't go back to the contents through the interface
- there. May want to add a 'top' link or something through out it so you can.
- It's been bugging me all day."
-* For `solar make-model`, add docblock tags on methods.
-
-* For version 1.0.0alpha1, remove MS-SQL. Put MS-SQL and Oracle in a later
- release.
-
-* Write up templates for SQL relations so that others can see what the
- queries are.
-
By Class
========
@@ -60,14 +61,12 @@
/var/www/dev.mashery.com/site/trunk/pear/php/Solar/Class/Stack.php on
line 165
+* Solar_Cli_MakeModel
+
+ * Add docblock tags on methods.
+
* Solar_Controller_Command
- * Change print()/println() to out/outln() ? write/writeln()?
-
- * Change from "echo" to using fwrite() against stdout
-
- * Add err() method using fwrite() against stderr
-
* Add read()/readln() method methods for input? What are good names for
stdin streams?
@@ -107,9 +106,7 @@
[09:30am] moraes: $body = str_replace("\r\n", "\n",
$this->_mail->fetchContent());* Solar_Markdown
-
- * Add setReplyTo() method
-
+
* Solar_Markdown
* Check against newest Markdown code
@@ -126,21 +123,27 @@
* way to pass charset and collation in SQL adapters
- * Fix MS-SQL adapter class
- * ... and write tests for it
- * then add Stefan Bogdan as contrib
-
* Add/update tests for new SQL pieces (e.g. lastInsertId)
* Make the SQL adapter query() auto-value-binding work with array values?
* Add Oracle adapter
+ * Fix MS-SQL adapter class
+ * ... and write tests for it
+ * then add Stefan Bogdan as contrib
+
* Solar_Sql_Model
* Move fetchRelatedArray(), fetchRelatedObject(), and countPagesRelated()
to Solar_Sql_Model_Related
+* Solar_Test
+
+ * Should be isolated to its own PHP env: re-build the test system to
+ invoke a new PHP executable for each test method, which will clear any
+ statics, etc.
+
* Solar_View_Helper
* hCard helper? <http://microformats.org/wiki/hcard>
@@ -175,7 +178,5 @@
* add feedback messages as well?
- * add JS calls to Form helper ?
-
* add IDs to Form helper for the form tag itself?
More information about the Solar-svn
mailing list