[Solar-svn] Revision 2773

pmjones at solarphp.com pmjones at solarphp.com
Sun Sep 23 15:24:13 CDT 2007


branch: Solar_Model_*: major revamp of all content model classes in line with recent Model/Record/Collection classes



Added: branches/orm/Solar/Model/Areas/Collection.php
===================================================================
--- branches/orm/Solar/Model/Areas/Collection.php	                        (rev 0)
+++ branches/orm/Solar/Model/Areas/Collection.php	2007-09-23 20:24:13 UTC (rev 2773)
@@ -0,0 +1,2 @@
+<?php
+class Solar_Model_Areas_Collection extends Solar_Model_Collection {}
\ No newline at end of file

Added: branches/orm/Solar/Model/Areas/Record.php
===================================================================
--- branches/orm/Solar/Model/Areas/Record.php	                        (rev 0)
+++ branches/orm/Solar/Model/Areas/Record.php	2007-09-23 20:24:13 UTC (rev 2773)
@@ -0,0 +1,2 @@
+<?php
+class Solar_Model_Areas_Record extends Solar_Model_Record {}
\ No newline at end of file

Modified: branches/orm/Solar/Model/Areas.php
===================================================================
--- branches/orm/Solar/Model/Areas.php	2007-09-23 20:19:52 UTC (rev 2772)
+++ branches/orm/Solar/Model/Areas.php	2007-09-23 20:24:13 UTC (rev 2773)
@@ -36,7 +36,7 @@
             'prefs' => 'clob',
         );
         
-        $this->_indexes = array(
+        $this->_index = array(
             'created',
             'updated',
             'name' => 'unique',

Added: branches/orm/Solar/Model/Collection.php
===================================================================
--- branches/orm/Solar/Model/Collection.php	                        (rev 0)
+++ branches/orm/Solar/Model/Collection.php	2007-09-23 20:24:13 UTC (rev 2773)
@@ -0,0 +1,2 @@
+<?php
+class Solar_Model_Collection extends Solar_Sql_Model_Collection {}
\ No newline at end of file

Modified: branches/orm/Solar/Model/Nodes/Bookmarks/Locale/en_US.php
===================================================================
--- branches/orm/Solar/Model/Nodes/Bookmarks/Locale/en_US.php	2007-09-23 20:19:52 UTC (rev 2772)
+++ branches/orm/Solar/Model/Nodes/Bookmarks/Locale/en_US.php	2007-09-23 20:24:13 UTC (rev 2773)
@@ -1,7 +1,8 @@
 <?php
 return array(
-    'LABEL_URI' => 'Location',
-    'LABEL_SUBJ' => 'Title',
-    'LABEL_SUMM' => 'Description',
-    'LABEL_POS'  => 'Rank',
+    'LABEL_URI'            => 'Location',
+    'LABEL_SUBJ'           => 'Title',
+    'LABEL_SUMM'           => 'Description',
+    'LABEL_POS'            => 'Rank',
+    'LABEL_TAGS_AS_STRING' => 'Tags',
 );
\ No newline at end of file

Modified: branches/orm/Solar/Model/Nodes/Bookmarks/Record.php
===================================================================
--- branches/orm/Solar/Model/Nodes/Bookmarks/Record.php	2007-09-23 20:19:52 UTC (rev 2772)
+++ branches/orm/Solar/Model/Nodes/Bookmarks/Record.php	2007-09-23 20:24:13 UTC (rev 2773)
@@ -21,12 +21,19 @@
                     'cols'  => 48,
                 ),
             ),
+            'tags_as_string' => array(
+                'type' => 'text',
+                'attribs' => array(
+                    'size' => 48,
+                ),
+            ),
             'pos'  => array(
                 'attribs' => array(
                     'size' => 3,
                 ),
             ),
         );
+        
         return parent::form($cols);
     }
 }
\ No newline at end of file

Modified: branches/orm/Solar/Model/Nodes/Bookmarks.php
===================================================================
--- branches/orm/Solar/Model/Nodes/Bookmarks.php	2007-09-23 20:19:52 UTC (rev 2772)
+++ branches/orm/Solar/Model/Nodes/Bookmarks.php	2007-09-23 20:24:13 UTC (rev 2773)
@@ -4,5 +4,6 @@
     {
         parent::_setup();
         $this->_addFilter('uri', 'validateNotBlank');
+        $this->_addFilter('tags_as_string', 'validateNotBlank');
     }
 }

Modified: branches/orm/Solar/Model/Nodes/Record.php
===================================================================
--- branches/orm/Solar/Model/Nodes/Record.php	2007-09-23 20:19:52 UTC (rev 2772)
+++ branches/orm/Solar/Model/Nodes/Record.php	2007-09-23 20:24:13 UTC (rev 2773)
@@ -1,2 +1,130 @@
 <?php
-class Solar_Model_Nodes_Record extends Solar_Model_Record {}
\ No newline at end of file
+class Solar_Model_Nodes_Record extends Solar_Model_Record {
+    
+    public function __getTagsAsString()
+    {
+        // if exactly null, populate for the first time.
+        if ($this->_data['tags_as_string'] === null) {
+            $text = '';
+            foreach ($this->tags as $tag) {
+                $text .= "{$tag->name} ";
+            }
+            $this->_data['tags_as_string'] = rtrim($text);
+        }
+        
+        return $this->_data['tags_as_string'];
+    }
+    
+    public function __setTagsAsString($val)
+    {
+        $val = preg_replace('/[ ]{2,}/', ' ', $val);
+        $this->_data['tags_as_string'] = trim($val);
+        $new = explode(' ', $this->_data['tags_as_string']);
+        $new = array_unique($new);
+        
+        // build a new tag collection
+        $model = $this->tags->getModel();
+        $coll = $model->newCollection();
+        foreach ($new as $name) {
+            $record = $model->fetchNew();
+            $record->name = $name;
+            $coll[] = $record;
+        }
+        
+        // reset the tags collection
+        $this->tags = $coll;
+    }
+    
+    // work with related values before they get saved.
+    // relateds:  areas, nodes, taggings, tags
+    public function _postSave()
+    {
+        // -------------------------------------------------------------
+        // 
+        // make sure that each tag actually exists; insert a new tag
+        // record for each new one.
+        // 
+        
+        // hold on to the tags model
+        $tags_model = $this->tags->getModel();
+        
+        // get the list of tags on the record
+        $tag_names = $this->tags->getNames();
+        if ($tag_names) {
+            // make sure each tag actually exists as a record.  tag names
+            // that do not exist will not be in this array.
+            $params = array(
+                'where' => array(
+                    'tags.name IN (?)' => $tag_names,
+                ),
+            );
+            $existing_tags = $tags_model->fetchAll($params);
+        } else {
+            $existing_tags = $tags_model->newCollection(null);
+        }
+        
+        // loop through the tags
+        foreach ($this->tags as $key => $tag) {
+            
+            // does this tag already exist?
+            foreach ($existing_tags as $existing) {
+                if ($tag->name == $existing->name) {
+                    // replace with the existing tag record.
+                    // this lets us "connect" user-entered tag names
+                    // with existing records. capture both the tag from
+                    // the loop and reset the collection value.
+                    $tag = $existing;
+                    $this->tags[$key] = $existing;
+                    break;
+                }
+            }
+            
+            // if status is still 'new' then save it
+            if ($tag->getStatus() == 'new') {
+                $tag->save();
+            }
+            
+            // look for a tagging on this tag
+            $found = false;
+            foreach ($this->taggings as $tagging) {
+                // must match node ID and tag ID
+                $match = $tagging->node_id == $this->id &&
+                         $tagging->tag_id  == $tag->id;
+                if ($match) {
+                    $found = true;
+                    break;
+                }
+            }
+            
+            // did we find a tagging for the tag?
+            if (! $found) {
+                // no, create one ...
+                $tagging = $this->taggings->getModel()->fetchNew();
+                $tagging->node_id = $this->id;
+                $tagging->tag_id  = $tag->id;
+                
+                // ... and add to the collection
+                $this->taggings[] = $tagging;
+            }
+        }
+        
+        // remove taggings that don't exist any more
+        foreach ($this->taggings as $key => $tagging) {
+            $found = false;
+            foreach ($this->tags as $tag) {
+                $match = $tagging->node_id == $this->id &&
+                         $tagging->tag_id  == $tag->id;
+                if ($match) {
+                    $found = true;
+                    break;
+                }
+            }
+            
+            // does the tagging match a tag?
+            if (! $found) {
+                // no, remove from the taggings
+                $tagging->delete();
+            }
+        }
+    }
+}
\ No newline at end of file

Modified: branches/orm/Solar/Model/Nodes.php
===================================================================
--- branches/orm/Solar/Model/Nodes.php	2007-09-23 20:19:52 UTC (rev 2772)
+++ branches/orm/Solar/Model/Nodes.php	2007-09-23 20:24:13 UTC (rev 2773)
@@ -82,7 +82,7 @@
             'prefs' => 'clob',
         );
         
-        $this->_indexes = array(
+        $this->_index = array(
             'created',
             'updated',
             'area_id',
@@ -103,6 +103,7 @@
          * Special columns
          */
         $this->_serialize_cols[] = 'prefs';
+        $this->_calculate_cols[] = 'tags_as_string';
         
         /**
          * Filters
@@ -122,6 +123,7 @@
         $this->_addFilter('editor_ipaddr', 'validateIpv4');
         $this->_addFilter('locale', 'validateLocaleCode');
         $this->_addFilter('mime', 'validateMimeType');
+        $this->_addFilter('tags_as_string', 'validateSepWords');
         
         /**
          * Relationships.
@@ -143,5 +145,94 @@
             'through_key'   => 'tag_id',
         ));
     }
+    
+    public function fetchAllByTags($tag_list, $params = null)
+    {
+        // no tags? fetch all to pre-empt errors related to "IN()" not
+        // having a list to work with.
+        $tag_list = $this->_fixTagList($tag_list);
+        if (! $tag_list) {
+            return $this->fetchAll($params);
+        }
+        
+        // fetch
+        $select = $this->_newSelectByTags($tag_list, $params);
+        return $this->_fetchAll($select, $params);
+    }
+    
+    protected function _fixTagList($tag_list)
+    {
+        // convert to array
+        if (! is_array($tag_list)) {
+            $tag_list = preg_split('/\s+/', trim((string) $tag_list));
+        }
+        
+        // no duplicates allowed
+        $tag_list = array_unique($tag_list);
+        
+        // if the string tag-list is empty, the preg-split leaves one empty
+        // element in the array.
+        if ($tag_list[0] == '') {
+            $tag_list = array();
+        }
+        
+        // done!
+        return $tag_list;
+    }
+    
+    protected function _newSelectByTags($tag_list, $params)
+    {
+        // setup
+        $params = $this->_fixSelectParams($params);
+        $select = $this->newSelect($params['eager']);
+        
+        // catalog entries for joining
+        $taggings = $this->_related['taggings'];
+        $tags     = $this->_related['tags'];
+        
+        // primary key on the nodes table as an alias; e.g., "nodes.id"
+        $native_primary = "{$this->_model_name}.{$this->_primary_col}";
+        
+        // http://forge.mysql.com/wiki/TagSchema
+        // build the select differently from other fetchAll() statements
+        $select->distinct($params['distinct'])
+               ->from("{$this->_table_name} AS {$this->_model_name}", $params['cols'])
+               // join taggings on nodes
+               ->join(
+                   "{$taggings['foreign_table']} AS {$taggings['foreign_alias']}",
+                   "{$taggings['foreign_alias']}.node_id = $native_primary"
+               )
+               // join tags on taggings
+               ->join(
+                   "{$tags['foreign_table']} AS {$tags['foreign_alias']}",
+                   "{$tags['foreign_alias']}.id = {$taggings['foreign_alias']}.tag_id"
+               )
+               // select for the listed tags
+               ->where("{$tags['foreign_alias']}.name IN (?)", $tag_list)
+               // user-provided WHERE
+               ->multiWhere($params['where'])
+               // group by nodes.id to collapse multiple nodes (1 for each tag)
+               ->group($native_primary)
+               // make sure the tag-count matches
+               ->having("COUNT($native_primary) = ?", count($tag_list))
+               // user-provided ORDER, paging, etc
+               ->order($params['order'])
+               ->setPaging($params['paging'])
+               ->limitPage($params['page'])
+               ->bind($params['bind']);
+        
+        // done!
+        return $select;
+    }
+    
+    public function countPagesByTags($tag_list, $params = null)
+    {
+        $tag_list = $this->_fixTagList($tag_list);
+        if (! $tag_list) {
+            return $this->countPages($params);
+        }
+        
+        $select = $this->_newSelectByTags($tag_list, $params);
+        return $select->countPages('bookmarks.id');
+    }
 }
-

Added: branches/orm/Solar/Model/Tags/Collection.php
===================================================================
--- branches/orm/Solar/Model/Tags/Collection.php	                        (rev 0)
+++ branches/orm/Solar/Model/Tags/Collection.php	2007-09-23 20:24:13 UTC (rev 2773)
@@ -0,0 +1,12 @@
+<?php
+class Solar_Model_Tags_Collection extends Solar_Model_Collection {
+    
+    public function getNames()
+    {
+        $list = array();
+        foreach ($this as $tag) {
+            $list[] = $tag->name;
+        }
+        return $list;
+    }
+}
\ No newline at end of file

Added: branches/orm/Solar/Model/Tags/Record.php
===================================================================
--- branches/orm/Solar/Model/Tags/Record.php	                        (rev 0)
+++ branches/orm/Solar/Model/Tags/Record.php	2007-09-23 20:24:13 UTC (rev 2773)
@@ -0,0 +1,2 @@
+<?php
+class Solar_Model_Tags_Record extends Solar_Model_Record {}
\ No newline at end of file

Modified: branches/orm/Solar/Model/Tags.php
===================================================================
--- branches/orm/Solar/Model/Tags.php	2007-09-23 20:19:52 UTC (rev 2772)
+++ branches/orm/Solar/Model/Tags.php	2007-09-23 20:24:13 UTC (rev 2773)
@@ -25,7 +25,7 @@
             ),
         );
         
-        $this->_indexes = array(
+        $this->_index = array(
             'name' => 'unique',
         );
         
@@ -47,4 +47,102 @@
             'through'       => 'taggings',
         ));
     }
+    
+    public function fetchAllWithCount($params)
+    {
+        $select = $this->_newSelectWithCount($params);
+        return $this->_fetchAll($select, $params);
+    }
+    
+    public function fetchAllByOwnerHandle($owner_handle, $params = null)
+    {
+        $owner_handle = trim($owner_handle);
+        if (! $owner_handle) {
+            return $this->fetchAll($params);
+        }
+        
+        // setup
+        $params = $this->_fixSelectParams($params);
+        $select = $this->newSelect($params['eager']);
+        
+        // catalog entries for joining
+        $taggings = $this->_related['taggings'];
+        $nodes    = $this->_related['nodes'];
+        
+        // primary key on this table alias; e.g., tags.id
+        $native_primary = "{$this->_model_name}.{$this->_primary_col}";
+        
+        // add a tag-count column
+        $params['cols'][] = "COUNT($native_primary) AS count";
+        
+        // build the select
+        $select->distinct($params['distinct'])
+               ->from("{$this->_table_name} AS {$this->_model_name}", $params['cols'])
+               // join taggings on tags
+               ->join(
+                   "{$taggings['foreign_table']} AS {$taggings['foreign_alias']}",
+                   "{$taggings['foreign_alias']}.tag_id = $native_primary"
+               )
+               // join nodes on taggings
+               ->join(
+                   "{$nodes['foreign_table']} AS {$nodes['foreign_alias']}",
+                   "{$nodes['foreign_alias']}.id = {$taggings['foreign_alias']}.node_id"
+               )
+               // select for the owner_handle
+               ->where("{$nodes['foreign_alias']}.owner_handle = ?", $owner_handle)
+               // group on primary key for counts
+               ->group($native_primary)
+               // user-provided ORDER, paging, etc
+               ->multiWhere($params['where'])
+               ->order($params['order'])
+               ->setPaging($params['paging'])
+               ->limitPage($params['page'])
+               ->bind($params['bind']);
+        
+        // fetch
+        $select = $this->_newSelectWithCount($params);
+        $select->where('nodes.owner_handle = ?', $owner_handle);
+        return $this->_fetchAll($select, $params);
+    }
+    
+    protected function _newSelectWithCount($params)
+    {
+        // setup
+        $params = $this->_fixSelectParams($params);
+        $select = $this->newSelect($params['eager']);
+        
+        // catalog entries for joining
+        $taggings = $this->_related['taggings'];
+        $nodes    = $this->_related['nodes'];
+        
+        // primary key on this table alias; e.g., tags.id
+        $native_primary = "{$this->_model_name}.{$this->_primary_col}";
+        
+        // add a tag-count column
+        $params['cols'][] = "COUNT($native_primary) AS count";
+        
+        // build the select
+        $select->distinct($params['distinct'])
+               ->from("{$this->_table_name} AS {$this->_model_name}", $params['cols'])
+               // join taggings on tags
+               ->join(
+                   "{$taggings['foreign_table']} AS {$taggings['foreign_alias']}",
+                   "{$taggings['foreign_alias']}.tag_id = $native_primary"
+               )
+               // join nodes on taggings
+               ->join(
+                   "{$nodes['foreign_table']} AS {$nodes['foreign_alias']}",
+                   "{$nodes['foreign_alias']}.id = {$taggings['foreign_alias']}.node_id"
+               )
+               // group on primary key for counts
+               ->group($native_primary)
+               // user-provided ORDER, paging, etc
+               ->multiWhere($params['where'])
+               ->order($params['order'])
+               ->setPaging($params['paging'])
+               ->limitPage($params['page'])
+               ->bind($params['bind']);
+        
+        return $select;
+    }
 }




More information about the Solar-svn mailing list