[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