Development

Changeset 7387

You must first sign up to be able to contribute.

Changeset 7387

Show
Ignore:
Timestamp:
02/06/08 22:18:40 (10 months ago)
Author:
francois
Message:

sfPropelVersionableBehaviorPlugin Big changes (BC Break):

  • More explicit documentation on installation
  • Added a few unit tests
  • Added a getAllVersions method returning an array of origin objects in a single query
  • [BC Break] Renamed getAllVersions to getAllResourceVersions
  • [BC Break] Renamed getLastVersions to getLastResourceVersion
  • [BC Break] Replaced uuid by a simple composite key class name + id
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • plugins/sfPropelVersionableBehaviorPlugin/trunk/README

    r7371 r7387  
    55== Features == 
    66 
     7 * Revert objects to previous versions easily 
     8 * Track and browse history of modifications on every object 
     9 * Conditional versioning 
    710 * Fully unit tested 
    8  * Revert objects to previous versions easily 
    9  * Conditional versioning 
    1011 
    1112== Installation == 
     
    1415   
    1516    {{{ 
    16 symfony plugin-install http://plugins.symfony-project.com/sfPropelVersionableBehaviorPlugin 
     17#!sh 
     18> php symfony plugin-install http://plugins.symfony-project.com/sfPropelVersionableBehaviorPlugin 
    1719    }}} 
    1820 
     
    2325    }}} 
    2426   
    25   * Add necessary fields to your each of your model tables that you want to make versionable: 
     27  * Add a `version` field to each of the model tables that you want to make versionable: 
    2628   
    2729    {{{ 
    2830#!xml 
    2931<!-- schema.xml --> 
    30 <column name="uuid" type="CHAR" size="36" required="true" /> 
    31 <column name="version" type="INTEGER" size="11" required="true" /> 
     32<column name="version" type="INTEGER" required="true" /> 
    3233or 
    3334<!-- schema.yml --> 
    34 uuid:    { type: char, size: 36, required: true } 
    35 version: { type: integer, size: 11, required: true } 
    36     }}} 
    37  
    38   * Rebuild your database and model (the plugin uses two tables to store object version history) 
     35version: { type: integer, required: true } 
     36    }}} 
     37     
     38    Alternatively, you can choose another name that `version` and declare it in the behavior initialization. Even though, the behavior will still provide a `getVersion` and `setVersion` method for your versionable models. 
     39 
     40  * Rebuild your model and sql, insert the plugin tables to your database, and the new version column to your versionable tables: 
    3941   
    4042    {{{ 
    4143#!sh 
    42 > php symfony propel-build-all 
     44> php symfony propel-build-model 
     45> php symfony propel-build-sql 
     46> mysql -uroot -p mydb < data/sql/plugins.sfPropelVersionableBehaviorPlugin.lib.model.schema.sql 
     47> mysql -uroot -p mydb -e 'ALTER TABLE `Article` ADD `version` INTEGER NOT NULL;' 
    4348    }}} 
    4449   
     
    5358} 
    5459 
    55 $columns_map = array('uuid'     => ArticlePeer::UUID, 
    56                      'version'  => ArticlePeer::VERSION); 
    57  
    58 sfPropelBehavior::add('Article', array('versionable' => array('columns' => $columns_map))); 
     60sfPropelBehavior::add('Article', array('versionable')); 
    5961   }}} 
    6062 
    61    Column map values mean: 
    62      * uuid : Model column holding resource's universally unique identifier (behavior takes care of generating these) 
    63      * version : Model column holding resource's current version number 
     63   If the model uses a version column name diffeent than `version`, declare it here as the 'version' parameter of the behavior initialization: 
     64 
     65   {{{ 
     66#!php 
     67sfPropelBehavior::add('Article', array('versionable' => array('columns' => array('version'  => 'my_version_column')))); 
     68  }}} 
     69 
     70  * Clear the cache 
     71 
     72    {{{ 
     73#!sh 
     74> php symfony cc 
     75    }}} 
    6476 
    6577== Usage == 
     
    88100<?php 
    89101 
    90 foreach ($article->getAllVersions() as $version
     102foreach ($article->getAllVersions() as $history_article
    91103{ 
    92    $history_article = $version->getResourceInstance(); 
    93104   echo sprintf("Version %d title : %s\n",  
    94                 $history_article->getVersion(),  
    95                 $history_article->getTitle()); 
     105                $history_article->getVersion(), 
     106                $history_article->getTitle() 
     107                ); 
    96108} 
    97109 
     
    162174Enabling the behaviors adds / modifies the following method to the Propel objects : 
    163175 
    164  * `void save()`: Adds a new version to resource's version history 
    165  * `void delete()`: Deletes resource's version history 
    166  * `void toVersion(integer $version_number)`: Populates resource properties with values from the requested version 
    167  * `ResourceVersion getLastVersion()`: Returns resource's last version 
    168  * `array getAllVersions()`: Returns all resource versions in an array 
     176 * `void save()`: Adds a new version to the object version history and increments the `version` property 
     177 * `void delete()`: Deletes the object version history 
     178 * `void toVersion(integer $version_number)`: Populates the properties of the current object with values from the requested version. Beware that saving the object afterwards will create a new version (and not update the previous version). 
     179 * `array getAllVersions()`: Returns all versions of the object in an ordered array 
     180 * `ResourceVersion getLastResourceVersion()`: Returns the object's last version object 
     181 * `array getAllResourceVersions()`: Returns all version objects in an array 
    169182  
    170183=== !ResourceVersion API === 
     
    183196=== 0.3 === 
    184197 
    185  * Add unit tests to check version_attributes deletion 
    186198 * Make plugin compatible with sfPropel's i18n capabilities 
    187  * Replace uuid by a simple composite key class name + id 
     199 * Change the calls to `getPrimaryKey` by calls to a [wiki:sfPropelActAsRatableBehaviorPlugin]-style `getReferenceKey` to allow extending objects with multiple primary keys. 
    188200 
    189201== Changelog == 
    190202 
    191 === Trunk === 
     203=== 2008-02-06 | Trunk === 
     204 
     205 * francois: More explicit documentation on installation 
     206 * francois: Added a few unit tests 
     207 * francois: Added a `getAllVersions` method returning an array of origin objects in a single query 
     208 * francois: [BC Break] Renamed `getAllVersions` to `getAllResourceVersions` 
     209 * francois: [BC Break] Renamed `getLastVersions` to `getLastResourceVersion` 
     210 * francois: [BC Break] Replaced uuid by a simple composite key class name + id 
    192211 
    193212=== 2008-02-06 | 0.2.2 alpha === 
  • plugins/sfPropelVersionableBehaviorPlugin/trunk/config/config.php

    r3485 r7387  
    2626  array ( 
    2727    'sfPropelVersionableBehavior', 
    28     'getLastVersion
     28    'getAllResourceVersions
    2929  ), 
    3030  array ( 
    3131    'sfPropelVersionableBehavior', 
    32     'setUuid' 
    33   ), 
    34   array ( 
    35     'sfPropelVersionableBehavior', 
    36     'getUuid' 
     32    'getLastResourceVersion' 
    3733  ), 
    3834  array ( 
  • plugins/sfPropelVersionableBehaviorPlugin/trunk/config/schema.yml

    r7368 r7387  
    11propel: 
    22  _attributes:            { package: plugins.sfPropelVersionableBehaviorPlugin.lib.model } 
     3 
    34  resource_version: 
    45    id: 
    56    number:               { type: integer, size: 11, required: true, primaryKey: true } 
    6     resource_uuid:        { type: char, size: 36, required: true, index: true } 
     7    resource_id:          { type: integer, required: true } 
    78    resource_name:        { type: varchar, size: 255, required: true } 
     9    _indexes: 
     10      resource_version_index: [resource_id, resource_name] 
     11 
    812  resource_attribute_version: 
    913    id: 
  • plugins/sfPropelVersionableBehaviorPlugin/trunk/lib/model/ResourceVersion.php

    r3485 r7387  
    2424  public function populateFromObject(BaseObject $resource) 
    2525  { 
    26     $this->setResourceUuid($resource->getUuid()); 
     26    $this->setResourceId($resource->getPrimaryKey()); 
    2727    $this->setResourceName(get_class($resource)); 
    2828    $this->setNumber($resource->getVersion()); 
  • plugins/sfPropelVersionableBehaviorPlugin/trunk/lib/sfPropelVersionableBehavior.class.php

    r7368 r7387  
    1515 *  
    1616 * <code> 
    17  *   $columns_map = array('uuid'     => MyClassPeer::UUID, 
    18  *                        'version'  => MyClassPeer::VERSION); 
     17 *   $columns_map = array('version'  => MyClassPeer::VERSION); 
    1918 *  
    2019 *   sfPropelBehavior::add('MyClass', array('versionable' => array('columns' => $columns_map))); 
     
    2322 * Column map values signification : 
    2423 *  
    25  *  - uuid : Model column holding resource's universally unique identifier (behavior takes care of generating these) 
    2624 *  - version : Model column holding resource's current version number 
    2725 *  
    2826 * @author Tristan Rivoallan <tristan@rivoallan.net> 
     27 * @author Francois Zaninotto <francois.zaninotto@symfony-project.com> 
    2928 */ 
    3029class sfPropelVersionableBehavior 
     
    5049  { 
    5150    $c = new Criteria(); 
    52     $c->add(ResourceVersionPeer::RESOURCE_UUID, $resource->getUuid()); 
     51    $c->add(ResourceVersionPeer::RESOURCE_ID, $resource->getPrimaryKey()); 
     52    $c->add(ResourceVersionPeer::RESOURCE_NAME, get_class($resource)); 
    5353    $c->add(ResourceVersionPeer::NUMBER, $version_num); 
    5454    $version = ResourceVersionPeer::doSelectOne($c); 
     
    5656    if (is_null($version)) 
    5757    { 
    58       $msg = sprintf('Resource "%s" has no version "%d"', $resource->getUuid(), $version_num); 
     58      $msg = sprintf('Resource "%s" has no version "%d"', $resource->getPrimaryKey(), $version_num); 
    5959      throw new Exception($msg); 
    6060    } 
    6161     
    6262    $resource = self::populateResourceFromVersion($resource, $version); 
    63      
    6463  } 
    6564  
     
    7069   * @return     ResourceVersion 
    7170   */ 
    72   public function getLastVersion(BaseObject $resource) 
    73   { 
    74     $c = new Criteria(); 
    75     $c->add(ResourceVersionPeer::RESOURCE_UUID, $resource->getUuid()); 
     71  public function getLastResourceVersion(BaseObject $resource) 
     72  { 
     73    $c = new Criteria(); 
     74    $c->add(ResourceVersionPeer::RESOURCE_ID, $resource->getPrimaryKey()); 
     75    $c->add(ResourceVersionPeer::RESOURCE_NAME, get_class($resource)); 
    7676    $c->addDescendingOrderByColumn(ResourceVersionPeer::NUMBER); 
     77     
    7778    return ResourceVersionPeer::doSelectOne($c); 
    7879  } 
    7980  
    8081  /** 
    81    * Returns all versions of resource. 
    82    *  
    83    * @param      BaseObject    $resource 
    84    * @return     array 
     82   * Returns all ResourceVersion instances related to the object, ordered by version asc. 
     83   *  
     84   * @param      BaseObject   $resource 
     85   * @return     array        List of ResourceVersion objects 
     86   */ 
     87  public function getAllResourceVersions(BaseObject $resource) 
     88  { 
     89    $c = new Criteria(); 
     90    $c->add(ResourceVersionPeer::RESOURCE_ID, $resource->getPrimaryKey()); 
     91    $c->add(ResourceVersionPeer::RESOURCE_NAME, get_class($resource)); 
     92    $c->addAscendingOrderByColumn(ResourceVersionPeer::NUMBER); 
     93     
     94    return ResourceVersionPeer::doSelect($c); 
     95  } 
     96 
     97  /** 
     98   * Returns all ResourceVersion instances related to the object, ordered by version asc. 
     99   *  
     100   * @param      BaseObject   $resource 
     101   * @return     array        List of BaseObject objects 
    85102   */ 
    86103  public function getAllVersions(BaseObject $resource) 
    87104  { 
    88105    $c = new Criteria(); 
    89     $c->add(ResourceVersionPeer::RESOURCE_UUID, $resource->getUuid()); 
    90     return ResourceVersionPeer::doSelect($c); 
     106    $c->add(ResourceVersionPeer::RESOURCE_ID, $resource->getPrimaryKey()); 
     107    $c->add(ResourceVersionPeer::RESOURCE_NAME, get_class($resource)); 
     108    $c->addAscendingOrderByColumn(ResourceVersionPeer::NUMBER); 
     109    $c->addJoin(ResourceAttributeVersionPeer::RESOURCE_VERSION_ID, ResourceVersionPeer::ID); 
     110    $attributes = ResourceAttributeVersionPeer::doSelect($c); 
     111     
     112    $objects = array(); 
     113    $object = null; 
     114    $class= get_class($resource); 
     115    $current_id = null; 
     116    foreach($attributes as $attribute) 
     117    { 
     118      if($attribute->getResourceVersionId() != $current_id) 
     119      { 
     120        if($object) 
     121        { 
     122          $objects[]= $object; 
     123        } 
     124        $current_id = $attribute->getResourceVersionId(); 
     125        $object = new $class; 
     126      } 
     127      $attrib_name = $attribute->getAttributeName(); 
     128      $setter = sprintf('set%s', $attrib_name); 
     129       
     130      if (!method_exists($resource, $setter)) 
     131      { 
     132        $msg = sprintf('Impossible to set attribute "%s" on resource "%s"',  
     133                      $attrib_name, get_class($resource)); 
     134        throw new Exception($msg); 
     135      } 
     136      $object->$setter($attribute->getAttributeValue()); 
     137       
     138    } 
     139    $objects[] = $object; 
     140     
     141    return $objects; 
    91142  } 
    92143 
     
    117168  } 
    118169 
    119   /** 
    120    * Returns resource UUID. Proxy method to real getter. 
    121    *  
    122    * @param      BaseObject    $resource 
    123    * @return     string 
    124    */ 
    125   public function getUuid(BaseObject $resource) 
    126   { 
    127     $getter = self::forgeMethodName($resource, 'get', 'uuid'); 
    128     return $resource->$getter();     
    129   } 
    130  
    131   /** 
    132    * Sets resource UUID. Proxy method to real setter. 
    133    *  
    134    * @param      BaseObject    $resource 
    135    * @param      string        $uuid 
    136    */ 
    137   public function setUuid(BaseObject $resource, $uuid) 
    138   { 
    139     $setter = self::forgeMethodName($resource, 'set', 'uuid'); 
    140     return $resource->$setter($uuid);     
    141   } 
    142  
    143170# ---- HOOKS 
    144171 
    145172  /** 
    146    * This hook is called before object is saved. It takes care of generating a new UUID if necessary. 
     173   * This hook is called before object is saved. 
    147174   *  
    148175   * @param      BaseObject    $resource 
     
    152179    if (self::versionConditionMet($resource)) 
    153180    { 
    154       if ($resource->isNew()) 
    155       { 
    156         $resource->setUuid(sfPropelVersionableBehaviorToolkit::generateUuid()); 
    157       } 
    158  
    159       if ($version = $resource->getLastVersion()) 
     181      if ($version = $resource->getLastResourceVersion()) 
    160182      { 
    161183        $resource->setVersion($version->getNumber() + 1); 
     
    180202      $version->populateFromObject($resource); 
    181203      $version->setNumber($resource->getVersion()); 
    182       $version->setResourceUuid($resource->getUuid()); 
    183204      $version->save(); 
    184205    } 
     
    191212  { 
    192213    $c = new Criteria(); 
    193     $c->add(ResourceVersionPeer::RESOURCE_UUID, $resource->getUuid()); 
     214    $c->add(ResourceVersionPeer::RESOURCE_ID, $resource->getPrimaryKey()); 
     215    $c->add(ResourceVersionPeer::RESOURCE_NAME, get_class($resource)); 
    194216    ResourceVersionPeer::doDelete($c); 
    195217  } 
     
    213235      if (!method_exists($resource, $setter)) 
    214236      { 
    215         $msg = sprint('Impossible to set attribute "%s" on resource "%s"',  
     237        $msg = sprintf('Impossible to set attribute "%s" on resource "%s"',  
    216238                      $attrib_name, get_class($resource)); 
    217239        throw new Exception($msg); 
     
    229251   * @param     BaseObject    $resource 
    230252   * @param     string        $prefix     Usually 'get' or 'set' 
    231    * @param     string        $column     uuid|version 
     253   * @param     string        $column     version 
    232254   */ 
    233255  private static function forgeMethodName($resource, $prefix, $column) 
  • plugins/sfPropelVersionableBehaviorPlugin/trunk/package.xml

    r7371 r7387  
    4141        </dir> 
    4242        <file name="sfPropelVersionableBehavior.class.php" role="data"/> 
    43         <file name="sfPropelVersionableBehaviorToolkit.class.php" role="data"/> 
    4443      </dir> 
    4544    </dir> 
  • plugins/sfPropelVersionableBehaviorPlugin/trunk/test/unit/PropelVersionableBehaviorTest.php

    r7368 r7387  
    4545  sfPropelVersionableBehaviorPlugin: 
    4646    test_class:          Article 
    47     test_uuid_column:    uuid 
    4847    test_version_column: version 
    4948    test_title_column:   title 
     
    5554*/ 
    5655$test_class = sfConfig::get('app_sfPropelVersionableBehaviorPlugin_test_class', 'Post'); 
    57 $test_class_uuid_column = sfConfig::get('app_sfPropelVersionableBehaviorPlugin_test_uuid_column', 'uuid'); 
    5856$test_class_version_column = sfConfig::get('app_sfPropelVersionableBehaviorPlugin_test_version_column', 'version'); 
    5957$test_class_title_column = sfConfig::get('app_sfPropelVersionableBehaviorPlugin_test_title_column', 'title'); 
     
    7270// cleanup database 
    7371call_user_func(array(_create_resource()->getPeer(), 'doDeleteAll')); 
     72ResourceAttributeVersionPeer::doDeleteAll(); 
    7473ResourceVersionPeer::doDeleteAll(); 
    7574 
    7675// register behavior on test object 
    7776sfPropelBehavior::add($test_class, array('versionable' => array( 
    78   'uuid'     => $test_class_uuid_column, 
    7977  'version'  => $test_class_version_column 
    8078))); 
    8179 
    82 $t = new lime_test(19, new lime_output_color()); 
     80$t = new lime_test(26, new lime_output_color()); 
    8381 
    8482// save() 
     
    8886$r->setByName($test_class_title_column, 'V1', BasePeer::TYPE_FIELDNAME); 
    8987$r->save(); 
    90  
    91 $t->isnt($r->getByName($test_class_uuid_column, BasePeer::TYPE_FIELDNAME), null, 'save() generates a universal unique id for new resources'); 
    92  
    93 $uuid = $r->getByName($test_class_uuid_column, BasePeer::TYPE_FIELDNAME); 
    94 $r->setByName($test_class_title_column, 'V2', BasePeer::TYPE_FIELDNAME); 
    95 $r->save(); 
    96  
    97 $t->is($r->getByName($test_class_uuid_column, BasePeer::TYPE_FIELDNAME), $uuid, 'save() does not generate a new universal unique id for existing resources'); 
     88$t->is($r->getByName($test_class_version_column, BasePeer::TYPE_FIELDNAME), 1, 'save() initializes the version number to 1 for new objects'); 
    9889 
    9990$c = new Criteria(); 
    100 $c->add(ResourceVersionPeer::RESOURCE_UUID, $r->getByName($test_class_uuid_column, BasePeer::TYPE_FIELDNAME)); 
     91$c->add(ResourceVersionPeer::RESOURCE_ID, $r->getPrimaryKey()); 
     92$c->add(ResourceVersionPeer::RESOURCE_NAME, get_class($r)); 
    10193$c->add(ResourceVersionPeer::NUMBER, $r->getByName($test_class_version_column, BasePeer::TYPE_FIELDNAME)); 
    10294$version = ResourceVersionPeer::doSelectOne($c); 
     
    10799  $t->is($attrib_version->getAttributeValue(), $r->$getter(), 'save() creates a new version of resource in database with appropriate parameters'); 
    108100} 
    109  
    110 // getLastVersion() 
    111 $t->diag('getLastVersion()'); 
    112  
    113 $t->is($r->getLastVersion()->getResourceInstance()->getByName($test_class_title_column, BasePeer::TYPE_FIELDNAME), 'V2', 'getLastVersion() returns last version of resource'); 
     101$r->setByName($test_class_title_column, 'V2', BasePeer::TYPE_FIELDNAME); 
     102$r->save(); 
     103$t->is($r->getByName($test_class_version_column, BasePeer::TYPE_FIELDNAME), 2, 'save() increments the version number'); 
     104 
     105// getLastResourceVersion() 
     106$t->diag('getLastResourceVersion()'); 
     107 
     108$t->is($r->getLastResourceVersion()->getResourceInstance()->getByName($test_class_title_column, BasePeer::TYPE_FIELDNAME), 'V2', 'getLastVersion() returns last version of resource'); 
    114109 
    115110$r->setByName($test_class_title_column, 'do not version me', BasePeer::TYPE_FIELDNAME); 
     
    121116 
    122117$r->toVersion(1); 
     118$t->is($r->getByName($test_class_version_column, BasePeer::TYPE_FIELDNAME), 1, 'toVersion() sets resource version to appropriate values'); 
    123119$t->is($r->getByName($test_class_title_column, BasePeer::TYPE_FIELDNAME), 'V1', 'toVersion() sets resource attributes to appropriate values'); 
    124120$r->save(); 
     
    134130} 
    135131 
     132// getAllResourceVersions() 
     133$t->diag('getAllResourceVersions()'); 
     134 
     135$r->setByName($test_class_title_column, 'V4', BasePeer::TYPE_FIELDNAME); 
     136$r->save(); 
     137$all_versions = $r->getAllResourceVersions(); 
     138$target_versions = array('V1', 'V2', 'V1', 'V4'); 
     139$t->is(count($all_versions), 4, 'getAllResourceVersions() returns right count of versions'); 
     140$versions_titles = array(); 
     141foreach($all_versions as $v) 
     142{ 
     143  $versions_titles[] = $v->getResourceInstance()->getByName($test_class_title_column, BasePeer::TYPE_FIELDNAME); 
     144} 
     145$t->is($versions_titles, $target_versions, 'getAllResourceVersions() returns the right versions'); 
     146 
    136147// getAllVersions() 
    137148$t->diag('getAllVersions()'); 
    138  
    139 $r->setByName($test_class_title_column, 'V4', BasePeer::TYPE_FIELDNAME); 
    140 $r->save(); 
    141 $all_versions = $r->getAllVersions(); 
    142 $target_versions = array('V1', 'V2', 'V1', 'V4'); 
    143 $t->diag('getAllVersions()'); 
    144 $t->is(count($all_versions), 4, 'getAllVersions() returns right count of versions'); 
     149$all_object_versions = $r->getAllVersions(); 
     150$t->is(count($all_object_versions), 4, 'getAllVersions() returns right count of objects'); 
    145151$versions_titles = array(); 
    146 foreach($all_versions as $v) 
    147 
    148   $versions_titles[] = $v->getResourceInstance()->getByName($test_class_title_column, BasePeer::TYPE_FIELDNAME); 
     152$versions_versions = array(); 
     153foreach($all_object_versions as $obj) 
     154
     155  $versions_titles[] = $obj->getByName($test_class_title_column, BasePeer::TYPE_FIELDNAME); 
     156  $versions_versions[] = $obj->getVersion(); 
    149157} 
    150158$t->is($versions_titles, $target_versions, 'getAllVersions() returns the right versions'); 
     159$t->is($versions_versions, array(1, 2, 3, 4), 'getAllVersions() returns the array of ordered versions'); 
    151160 
    152161// delete() 
    153162$t->diag('delete()'); 
    154  
     163$versions = $r->getAllResourceVersions(); 
    155164$r->delete(); 
    156 $t->is($r->getAllVersions(), null, 'delete() also deletes resource version history'); 
     165$t->is($r->getAllResourceVersions(), null, 'delete() also deletes resource version history'); 
     166foreach($versions as $version) 
     167
     168  // These verison objects now have no counterpart in database, but they are a convenient way to get to the ResourceAttributeVersion objects 
     169  $t->is($version->getResourceAttributeVersions(), null, 'delete() also deletes resource attribute version history'); 
     170
    157171 
    158172// setVersionConditionMethod() 
     
    176190$r->setByName($test_class_title_column, 'do not version me', BasePeer::TYPE_FIELDNAME); 
    177191$r->save(); 
    178 $t->is($r->getLastVersion()->getNumber(), 2, 'save() creates a version even if YourClass::versionConditionMet() is not found'); 
     192$t->is($r->getLastResourceVersion()->getNumber(), 2, 'save() creates a version even if YourClass::versionConditionMet() is not found'); 
    179193 
    180194// #1564 crashes while creating a new version if no prior version exists