コード例 #1
0
ファイル: _dbfactory.php プロジェクト: nemein/openpsa
 /**
  * Import object unserialized with midgard_replicator::unserialize()
  *
  * This method does ACL checks and triggers watchers etc.
  *
  * @param object $unserialized_object object gotten from midgard_replicator::unserialize()
  * @param boolean $use_force set use of force for the midcom_helper_replicator_import_object() call
  * @return boolean indicating success/failure
  * @todo refactor to smaller methods
  * @todo Add some magic to prevent importing of replication loops (see documentation/TODO for details about the potential problem)
  * @todo Verify support for the special cases of privilege
  * @todo Make sure older version is not imported over newer one (maybe configurable override ?)
  */
 function import(&$unserialized_object, $use_force = false)
 {
     if (is_a($unserialized_object, 'midgard_blob')) {
         debug_add("You must use import_blob method to import BLOBs", MIDCOM_LOG_ERROR);
         midcom_connection::set_error(MGD_ERR_ERROR);
         return false;
     }
     // We need this helper (workaround Zend bug)
     if (!function_exists('midcom_helper_replicator_import_object')) {
         midcom::get('componentloader')->load('midcom.helper.replicator');
     }
     if (!midcom::get('dbclassloader')->is_mgdschema_object($unserialized_object)) {
         debug_add("Unserialized object " . get_class($unserialized_object) . " is not recognized as supported MgdSchema class.", MIDCOM_LOG_ERROR);
         midcom_connection::set_error(MGD_ERR_ERROR);
         return false;
     }
     // Load the required component for DBA class
     $midcom_dba_classname = midcom::get('dbclassloader')->get_midcom_class_name_for_mgdschema_object($unserialized_object);
     if (!midcom::get('dbclassloader')->load_mgdschema_class_handler($midcom_dba_classname)) {
         debug_add("Failed to load the handling component for {$midcom_dba_classname}, cannot import.", MIDCOM_LOG_ERROR);
         midcom_connection::set_error(MGD_ERR_ERROR);
         return false;
     }
     // Get an object for ACL checks, use existing one if possible
     $acl_object = new $midcom_dba_classname($unserialized_object->guid);
     if (is_object($acl_object) && $acl_object->id) {
         if (!midcom::get('dbfactory')->is_a($acl_object, get_class($unserialized_object))) {
             $acl_class = get_class($acl_object);
             $unserialized_class = get_class($unserialized_object);
             debug_add("The local object we got is not of compatible type ({$acl_class} vs {$unserialized_class}), this means duplicate GUID", MIDCOM_LOG_ERROR);
             midcom_connection::set_error(MGD_ERR_DUPLICATE);
             return false;
         }
         // Got an existing object
         $acl_object_in_db = true;
         $actual_object_in_db = true;
         /* PONDER: should we copy values from unserialized here as well ?? likely we should (think moving article)
            midcom_baseclasses_core_dbobject::cast_object($acl_object, $unserialized_object)
            */
     } else {
         $error_code = midcom_connection::get_error();
         // switch is a loop, get the value only once this way
         switch ($error_code) {
             case MGD_ERR_ACCESS_DENIED:
                 $actual_object_in_db = true;
                 debug_add("Could not instantiate ACL object due to ACCESS_DENIED error, this means we can abort early", MIDCOM_LOG_ERROR);
                 return false;
                 break;
             case MGD_ERR_OBJECT_DELETED:
             case MGD_ERR_OBJECT_PURGED:
                 $actual_object_in_db = true;
                 break;
             default:
                 $actual_object_in_db = false;
                 break;
         }
         // Copy-construct
         $acl_object_in_db = false;
         $acl_object = new $midcom_dba_classname();
         if (!midcom_baseclasses_core_dbobject::cast_object($acl_object, $unserialized_object)) {
             debug_add('Failed to cast MidCOM DBA object for ACL checks from $unserialized_object', MIDCOM_LOG_ERROR);
             debug_print_r('$unserialized_object: ', $unserialized_object);
             return false;
         }
     }
     // Magic to check for various corner cases to determine the action to take later on
     switch (true) {
         case $unserialized_object->action == 'purged':
             // Purges not supported yet
             debug_add("Purges not supported yet (they require extra special love)", MIDCOM_LOG_ERROR);
             midcom_connection::set_error(MGD_ERR_OBJECT_PURGED);
             return false;
             break;
             // action is created but object is already in db, cast to update
         // action is created but object is already in db, cast to update
         case $unserialized_object->action == 'created' && $actual_object_in_db:
             $handle_action = 'updated';
             break;
         case $unserialized_object->action == 'updated' && !$actual_object_in_db:
             $handle_action = 'created';
             break;
         default:
             if ($unserialized_object->action) {
                 $handle_action = $unserialized_object->action;
             } else {
                 $handle_action = 'updated';
             }
             break;
     }
     if (!$acl_object->_on_importing()) {
         debug_add("The _on_importing event handler returned false.", MIDCOM_LOG_ERROR);
         // set errno if not set
         if (midcom_connection::get_error() === MGD_ERR_OK) {
             midcom_connection::set_error(MGD_ERR_ERROR);
         }
         return false;
     }
     switch ($handle_action) {
         case 'deleted':
             if (!$actual_object_in_db) {
                 midcom_helper_replicator_import_object($unserialized_object, $use_force);
                 break;
             }
             if (!midcom_baseclasses_core_dbobject::delete_pre_checks($acl_object)) {
                 debug_add('delete pre-flight check returned false', MIDCOM_LOG_ERROR);
                 return false;
             }
             // Actual import
             if (!midcom_helper_replicator_import_object($unserialized_object, $use_force)) {
                 /**
                  * BEGIN workaround
                  * For http://trac.midgard-project.org/ticket/200
                  */
                 if (midcom_connection::get_error() === MGD_ERR_OBJECT_IMPORTED) {
                     debug_add('Trying to workaround problem importing deleted action, calling $acl_object->delete()', MIDCOM_LOG_WARN);
                     if ($acl_object->delete()) {
                         debug_add('$acl_object->delete() succeeded, returning true early', MIDCOM_LOG_INFO);
                         return true;
                     }
                     debug_add("\$acl_object->delete() failed for {$acl_object->guid}, errstr: " . midcom_connection::get_error_string(), MIDCOM_LOG_ERROR);
                     // reset errno()
                     midcom_connection::set_error(MGD_ERR_OBJECT_IMPORTED);
                 }
                 /** END workaround */
                 debug_add('midcom_helper_replicator_import_object returned false, errstr: ' . midcom_connection::get_error_string(), MIDCOM_LOG_ERROR);
                 return false;
             }
             midcom_baseclasses_core_dbobject::delete_post_ops($acl_object);
             break;
         case 'updated':
             if (!midcom_baseclasses_core_dbobject::update_pre_checks($acl_object)) {
                 debug_add('update pre-flight check returned false', MIDCOM_LOG_ERROR);
                 return false;
             }
             // Actual import
             if (!midcom_helper_replicator_import_object($unserialized_object, $use_force)) {
                 debug_add('midcom_helper_replicator_import_object returned false, errstr: ' . midcom_connection::get_error_string(), MIDCOM_LOG_ERROR);
                 return false;
             }
             // "refresh" acl_object
             if (!midcom_baseclasses_core_dbobject::cast_object($acl_object, $unserialized_object)) {
                 // this shouldn't happen, but shouldn't be fatal either...
             }
             midcom_baseclasses_core_dbobject::update_post_ops($acl_object);
             break;
         case 'created':
             if (!midcom_baseclasses_core_dbobject::create_pre_checks($acl_object)) {
                 debug_add('creation pre-flight check returned false', MIDCOM_LOG_ERROR);
                 return false;
             }
             // Actual import
             if (!midcom_helper_replicator_import_object($unserialized_object, $use_force)) {
                 debug_add('midcom_helper_replicator_import_object returned false, errstr: ' . midcom_connection::get_error_string(), MIDCOM_LOG_ERROR);
                 return false;
             }
             // refresh object to avoid issues with _on_created requiring ID
             $acl_object_refresh = new $midcom_dba_classname($unserialized_object->guid);
             if (is_object($acl_object_refresh) && $acl_object_refresh->id) {
                 $acl_object = $acl_object_refresh;
                 midcom_baseclasses_core_dbobject::create_post_ops($acl_object);
             } else {
                 // refresh failed (it really shouldn't), what to do ??
             }
             break;
         default:
             debug_add("Do not know how to handle action '{$handle_action}'", MIDCOM_LOG_ERROR);
             midcom_connection::set_error(MGD_ERR_ERROR);
             return false;
             break;
     }
     $acl_object->_on_imported();
     midcom::get('componentloader')->trigger_watches(MIDCOM_OPERATION_DBA_IMPORT, $acl_object);
     return true;
 }