Author: bshaffer
Date: 2010-05-04 16:09:07 +0200 (Tue, 04 May 2010)
New Revision: 29346

Added:
   plugins/csDoctrineActAsSortablePlugin/branches/1.2/
   plugins/csDoctrineActAsSortablePlugin/branches/1.2/Readme.txt
   plugins/csDoctrineActAsSortablePlugin/branches/1.2/lib/
   plugins/csDoctrineActAsSortablePlugin/branches/1.2/lib/listener/
   plugins/csDoctrineActAsSortablePlugin/branches/1.2/lib/listener/Sortable.php
   plugins/csDoctrineActAsSortablePlugin/branches/1.2/lib/template/
   plugins/csDoctrineActAsSortablePlugin/branches/1.2/lib/template/Sortable.php
   plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/
   plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/css/
   plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/css/sortable.css
   plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/images/
   plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/images/sortable/
   plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/images/sortable/icons/
   
plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/images/sortable/icons/demote.png
   
plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/images/sortable/icons/promote.png
Log:
creating 1.2 branch

Added: plugins/csDoctrineActAsSortablePlugin/branches/1.2/Readme.txt
===================================================================
--- plugins/csDoctrineActAsSortablePlugin/branches/1.2/Readme.txt               
                (rev 0)
+++ plugins/csDoctrineActAsSortablePlugin/branches/1.2/Readme.txt       
2010-05-04 14:09:07 UTC (rev 29346)
@@ -0,0 +1,88 @@
+Documentation for CSDoctrineActAsSortablePlugin
+(created by Travis Black @ CentreSource )
+
+ ======================
+ = GETTING THE PLUGIN =
+ ======================
+ActAsSortable is a behavior for Doctrine which can add a sort order and 
ordering functions to any model in your database, even if it is in a 
one-to-many relationship.
+
+In order to add the plugin, you can do an SVN checkout. I highly suggest using 
svn-externals when adding to your own project. 
+
+svn co 
http://svn.centresource.com/symfony_plugins/trunk/csDoctrineActAsSortablePlugin 
plugins/
+
+
+
+ =================================================================
+ = APPLYING THE PLUGIN AND SORTABLE FUNCTIONALITY TO YOUR SCHEMA =
+ =================================================================
+This will add the behavior models and listener to your project. In order to 
implement this behavior on a model, you will just do "actAs: [Sortable]" in 
your schema.yml file. ie:
+
+Movie:
+       actAs: [Sortable, Timestampable]
+       
+
+Adding this behavior will add a position column to your database. Each record 
added to your database will automatically get the lowest possible position. 
Each time a record is deleted, all of the other records are repositioned 
accordingly.
+
+ActAsSortable also takes an option that will allow you to specify a 
combination of fields to apply a sort order to, rather than applying it to a 
full set of records. (ie)
+
+Movie:
+       actAs:
+               Sortable:
+                       uniqueBy: [genre_id]
+                       
+The above schema will make it so that each genre of movies is sorted 
independently. ie:
+
+genre1['movie1'][]
+
+This also gives your movie and movie table objects access to a number of 
sorting methods.
+
+Some common uses of these methods would be:
+
+
+--Retrieving all records from a database in sorted order:
+
+$movies = Doctrine::getTable('Movie')->findAllSorted();
+
+
+--Retrieving all records from a database with a parent model in mind.
+
+$movies = Doctrine::getTable('Movie')->findAllSortedWithParent($genre_id, 
'genre_id', $sort_order);
+
+option 1 is the value of the foreign key.
+option 2 is the column name of the foreign key.
+option 3 is the sort order ASC or DESC.
+
+
+--Promoting a record to a higher position
+
+$movie->promote();
+
+
+--Demoting a record to a lower position
+
+$movie->demote();
+
+
+--Moving a record to a position by position number
+
+$movie->moveToPosition($position);
+
+option 1 must be an integer representing the position in which you want your 
record to be placed.
+
+
+--Moving a record to the first position
+
+$movie->moveToFirst();
+
+
+
+--Moving a record to the last position
+
+$movie->moveToLast();
+
+
+
+
+--Using the Symfony/Prototype sortable_element function to update the sort 
order
+
+Doctrine->getTable('Movie')->sort($sortOrderArray);

Added: 
plugins/csDoctrineActAsSortablePlugin/branches/1.2/lib/listener/Sortable.php
===================================================================
--- 
plugins/csDoctrineActAsSortablePlugin/branches/1.2/lib/listener/Sortable.php    
                            (rev 0)
+++ 
plugins/csDoctrineActAsSortablePlugin/branches/1.2/lib/listener/Sortable.php    
    2010-05-04 14:09:07 UTC (rev 29346)
@@ -0,0 +1,78 @@
+<?php
+
+// 
+//  Sortable.php
+//  csDoctrineActAsSortablePlugin
+//  
+//  Created by Travis Black on 2008-12-22.
+//  Copyright 2008 Centre{source}. All rights reserved.
+// 
+
+class Doctrine_Template_Listener_Sortable extends Doctrine_Record_Listener
+{
+  /**
+   * Array of sortable options
+   */  
+  protected $_options = array();
+
+
+  /**
+   * Constructor for Sortable Template
+   *
+   * @param array $options 
+   * @return void
+   * @author Travis Black
+   */  
+  public function __construct(array $options)
+  {
+    $this->_options = $options;
+  }
+
+
+  /**
+   * Set the position value automatically when a new sortable object is created
+   *
+   * @param Doctrine_Event $event
+   * @return void
+   * @author Travis Black
+   */
+  public function preInsert(Doctrine_Event $event)
+  {
+    $object = $event->getInvoker();
+    $object->position = $object->getFinalPosition()+1;
+  }
+
+       public function preSave(Doctrine_Event $event)
+       {
+               $object = $event->getInvoker();
+               if(!$object->position)
+               {
+                       $object->position = $object->getFinalPosition()+1;
+               }
+       }
+  /**
+   * When a sortable object is deleted, promote all objects positioned lower 
than itself
+   *
+   * @param string $Doctrine_Event 
+   * @return void
+   * @author Travis Black
+   */  
+  public function postDelete(Doctrine_Event $event)
+  {
+    $object = $event->getInvoker();
+    $position = $object->position;
+
+    $q = Doctrine_Query::create()
+                       ->update(get_class($object))
+                       ->set('position', 'position - ?', '1')
+                       ->where('position > ' . $position)
+                       ->orderBy($this->_options['name']);
+
+    foreach ($this->_options['uniqueBy'] as $field)
+    {
+      $q->addWhere($field . ' = ?', $object[$field]);
+    }
+
+    $q->execute();
+  }  
+}

Added: 
plugins/csDoctrineActAsSortablePlugin/branches/1.2/lib/template/Sortable.php
===================================================================
--- 
plugins/csDoctrineActAsSortablePlugin/branches/1.2/lib/template/Sortable.php    
                            (rev 0)
+++ 
plugins/csDoctrineActAsSortablePlugin/branches/1.2/lib/template/Sortable.php    
    2010-05-04 14:09:07 UTC (rev 29346)
@@ -0,0 +1,417 @@
+<?php
+
+// 
+//  Sortable.php
+//  csDoctrineActAsSortablePlugin
+//  
+//  Created by Travis Black on 2008-12-22.
+//  Copyright 2008 Centre{source}. All rights reserved.
+// 
+
+class Doctrine_Template_Sortable extends Doctrine_Template
+{    
+  /**
+   * Array of sortable options
+   */  
+  protected $_options = array('name'        =>  'position',
+                              'alias'       =>  null,
+                              'type'        =>  'integer',
+                              'length'      =>  8,
+                              'unique'      =>  true,
+                              'options'     =>  array(),
+                              'fields'      =>  array(),
+                              'uniqueBy'    =>  array(),
+                              'uniqueIndex' =>  true,
+                              'canUpdate'   =>  false,
+                              'indexName'   =>  'sortable'
+  );
+
+
+  /**
+   * Constructor for Sortable Template
+   *
+   * @param array $options 
+   * @return void
+   * @author Travis Black
+   */
+  public function __construct(array $options = array())
+  {
+    $this->_options = Doctrine_Lib::arrayDeepMerge($this->_options, $options);
+  }
+
+
+  public function setup()
+  {
+  }
+
+
+  /**
+   * Set table definition for sortable behavior
+   * (borrowed from Sluggabl in Doctrine core)
+   *
+   * @return void
+   * @author Travis Black
+   */
+  public function setTableDefinition()
+  {
+    $name = $this->_options['name'];
+
+    if ($this->_options['alias'])
+    {
+      $name .= ' as ' . $this->_options['alias'];
+    }
+
+    $this->hasColumn($name, $this->_options['type'], 
$this->_options['length'], $this->_options['options']);
+
+    if ($this->_options['uniqueIndex'] == true && ! 
empty($this->_options['uniqueBy']))
+    {
+      $indexFields = array($this->_options['name']);
+      $indexFields = array_merge($indexFields, $this->_options['uniqueBy']);
+
+      $this->index($this->_options['indexName'], array('fields' => 
$indexFields,
+                                                       'type'   => 'unique'));
+    }
+    elseif ($this->_options['unique'])
+    {
+      $indexFields = array($this->_options['name']);
+      $this->index($this->_options['indexName'], array('fields' => 
$indexFields,
+                                                       'type'   => 'unique'));
+    }
+
+    $this->addListener(new 
Doctrine_Template_Listener_Sortable($this->_options));
+  }
+
+
+  public function getRelatedClassesArray()
+  {
+    $relations = array();
+
+    foreach ($this->getInvoker()->getTable()->getRelations() as $rel)
+    {
+      $componentName = $rel->getTable()->getComponentName();
+      $relations[] = $componentName;
+    }
+
+    return $relations;
+  }
+
+
+  public function getParentRelations()
+  {
+    $parents = array();
+
+    foreach ($this->getInvoker()->getTable()->getRelations() as $rel)
+    {
+      if ($rel->isOwningSide())
+      {
+        $parents[] = $rel;
+      }
+    }
+    
+    return $parents;
+  }
+
+
+  /**
+   * Demotes a sortable object to a lower position
+   *
+   * @return void
+   * @author Travis Black
+   */
+  public function demote()
+  { 
+    $object = $this->getInvoker();       
+    $position = $object->position;
+    
+    if ($object->position < $object->getFinalPosition())
+    {
+      $object->moveToPosition($position + 1);
+    }
+  }
+
+
+  /**
+   * Promotes a sortable object to a lower position
+   *
+   * @return void
+   * @author Travis Black
+   */
+  public function promote()
+  {
+    $object = $this->getInvoker();       
+    $position = $object->position;
+    
+    if ($object->position > 1)
+    {
+      $object->moveToPosition($position - 1);
+    }
+  }
+
+
+  public function promoteByIdTableProxy()
+  {
+  }
+  
+  public function promoteByTableProxy()
+  {
+  }
+
+
+  /**
+   * Sets a sortable object to the first position
+   *
+   * @return void
+   * @author Travis Black
+   */
+  public function moveToFirst()
+  {
+    $object = $this->getInvoker();       
+    $object->moveToPosition(1);
+  }
+
+
+  /**
+   * Sets a sortable object to the last position
+   *
+   * @return void
+   * @author Travis Black
+   */
+  public function moveToLast()
+  {
+    $object = $this->getInvoker();       
+    $object->moveToPosition($object->getFinalPosition());
+  }
+
+
+  /**
+   * Moves a sortable object to a designate position
+   *
+   * @param string $newPosition
+   * @return void
+   * @author Travis Black
+   */
+  public function moveToPosition($newPosition)
+  {
+    if (!is_int($newPosition))
+    {
+      throw new Doctrine_Exception('moveToPosition requires an Integer as the 
new position. Entered ' . $newPosition);
+    }
+
+    $object = $this->getInvoker();       
+    $position = $object->position;
+
+    // Position is required to be unique. Blanks it out before it moves others 
up/down.
+    if(!$object->setPosition(null)){
+      throw new Doctrine_Exception('Failed to set the position to null on your 
'.get_class($object));
+    }
+               $object->save();
+
+    // if(!$object->save()){
+    //   throw new Doctrine_Exception('Failed to save your 
'.get_class($object).' with a blank position.');
+    // }    
+    if ($position > $newPosition)
+    {
+      $q = Doctrine_Query::create()
+                         ->update(get_class($object))
+                         ->set('position', 'position + 1')
+                         ->where('position < ' . $position)
+                         ->andWhere('position >= ' . $newPosition)
+                         ->orderBy('position DESC');
+                
+      foreach ($this->_options['uniqueBy'] as $field)
+      {
+        $q->addWhere($field.' = ?', $object[$field]);
+      }
+          
+      $q->execute();              
+    }
+    elseif ($position < $newPosition)
+    {
+
+      $q = Doctrine_Query::create()
+                         ->update(get_class($object))
+                         ->set('position', 'position - 1')
+                         ->where('position > ?', $position)
+                         ->andWhere('position <= ' . $newPosition);
+
+      foreach($this->_options['uniqueBy'] as $field)
+      {
+        $q->addWhere($field . ' = ?', $object[$field]);
+      }
+
+
+                       $q->execute();
+    }
+    
+    if(!$object->setPosition($newPosition)){
+      throw new Doctrine_Exception('Failed to set the position on your 
'.get_class($object));
+    }
+               $object->save();
+  }
+
+
+  /**
+   * Send an array from the sortable_element tag and it will 
+   * update the sort order to match
+   *
+   * @param string $order
+   * @return void
+   * @author Travis Black
+   */
+  public function sortTableProxy($order)
+  {
+    /*
+      TODO 
+        - Make this a transaction.
+        - Add proper error messages.
+    */
+
+    $class = get_class($this->getInvoker()); 
+
+    foreach ($order as $position => $id) 
+    {
+      $newObject = Doctrine::getTable($class)->findOneById($id);
+
+      if ($newObject->position != $position + 1)
+      {
+        $newObject->moveToPosition($position + 1);
+      }
+    }
+  }
+
+
+  /**
+   * Finds all sortable objects and sorts them based on position attribute
+   * Ascending or Descending based on parameter
+   *
+   * @param string $order
+   * @return $query
+   * @author Travis Black
+   */
+  public function findAllSortedTableProxy($order = 'ASC')
+  {
+    $order = $this->formatAndCheckOrder($order);
+
+    $class = get_class($this->getInvoker()); 
+    $query = Doctrine_Query::create()
+                           ->from($class . ' od')
+                           ->orderBy('od.position ' . $order);
+
+    return $query->execute();
+  }
+
+
+  /**
+   * Finds and returns records sorted where the parent (fk) in a specified
+   * one to many relationship has the value specified
+   *
+   * @param string $parent_value
+   * @param string $parent_column_value
+   * @param string $order
+   * @return $query
+   * @author Travis Black
+   */
+  public function findAllSortedWithParentTableProxy($parent_value, 
$parent_column_name = null, $order = 'ASC')
+  {
+    $order = $this->formatAndCheckOrder($order);
+    
+    $object = $this->getInvoker();
+    $class  = get_class($object);
+    
+    if (!$parent_column_name)
+    {
+      $parents = get_class($object->getParent());
+
+      if (count($parents) > 1)
+      {
+        throw new Doctrine_Exception('No parent column name specified and 
object has mutliple parents');
+      }
+      elseif (count($parents) < 1)
+      {
+        throw new Doctrine_Exception('No parent column name specified and 
object has no parents');
+      }
+      else
+      {
+        $parent_column_name = $parents[0]->getType();
+        exit((string) $parent_column_name);
+        exit(print_r($parents[0]->toArray()));
+      }
+    }
+    
+    $query = Doctrine_Query::create()
+                           ->from($class . ' od')
+                           ->where('od.' . $parent_column_name . ' = ?', 
$parent_value)
+                           ->orderBy('position ' . $order);
+
+    return $query->execute();
+  }
+
+
+  /**
+   * Formats the ORDER for insertion in to query, else throws exception
+   *
+   * @param string $order
+   * @return $order
+   * @author Travis Black
+   */
+  public function formatAndCheckOrder($order)
+  {
+    $order = strtolower($order);
+
+    if ($order == 'ascending' || $order == 'asc')
+    {
+      $order = 'ASC';
+    }
+    elseif ($order == 'descending' || $order == 'desc')
+    {
+      $order = 'DESC';
+    }
+    else
+    {
+      throw new Doctrine_Exception('Order parameter value must be "asc" or 
"desc"');
+    }
+    
+    return $order;
+  }
+
+
+  /**
+   * Get the final position of a model
+   *
+   * @return $position
+   * @author Travis Black
+   */
+  public function getFinalPosition()
+  {
+    $object = $this->getInvoker();       
+    
+    $q = Doctrine_Query::create()
+                       ->select('position')
+                       ->from(get_class($object) . ' st')
+                       ->orderBy('position desc')
+                       ->limit(1);
+
+   foreach($this->_options['uniqueBy'] as $field)
+   {
+     if(is_object($object[$field])){
+       $q->addWhere($field . ' = ?', $object[$field]['id']); 
+     }
+     else{
+       $q->addWhere($field . ' = ?', $object[$field]);
+     }
+   }
+
+    try
+    {
+      $last = $q->execute();
+      $position = $last[0]->position;
+    }
+    catch (Exception $e)
+    {
+      //return 0;
+      exit ($q->getSql());
+    }
+
+    return $position;
+  }
+}

Added: plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/css/sortable.css
===================================================================
--- plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/css/sortable.css     
                        (rev 0)
+++ plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/css/sortable.css     
2010-05-04 14:09:07 UTC (rev 29346)
@@ -0,0 +1,16 @@
+#sf_admin_container ul li.sf_admin_action_promote a 
+{
+       background-image:none;
+}
+#sf_admin_container ul li.sf_admin_action_demote a 
+{
+       background-image:none;
+}
+#sf_admin_container ul li.sf_admin_action_promote 
+{
+       background:transparent url(../images/sortable/icons/promote.png) 
no-repeat scroll 0 0;
+}
+#sf_admin_container ul li.sf_admin_action_demote 
+{
+       background:transparent url(../images/sortable/icons/demote.png) 
no-repeat scroll 0 0;
+}
\ No newline at end of file

Added: 
plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/images/sortable/icons/demote.png
===================================================================
(Binary files differ)


Property changes on: 
plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/images/sortable/icons/demote.png
___________________________________________________________________
Added: svn:executable
   + 
Added: svn:mime-type
   + application/octet-stream

Added: 
plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/images/sortable/icons/promote.png
===================================================================
(Binary files differ)


Property changes on: 
plugins/csDoctrineActAsSortablePlugin/branches/1.2/web/images/sortable/icons/promote.png
___________________________________________________________________
Added: svn:executable
   + 
Added: svn:mime-type
   + application/octet-stream

-- 
You received this message because you are subscribed to the Google Groups 
"symfony SVN" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/symfony-svn?hl=en.

Reply via email to