null, 'source_name' => null, 'provider_class' => null, 'key_column' => null, 'import_state' => 'unknown', 'last_error_message' => null, 'last_attempt' => null, ); protected $settingsTable = 'import_source_setting'; protected $settingsRemoteId = 'source_id'; private $rowModifiers; public function fetchLastRun($required = false) { return $this->fetchLastRunBefore(time() + 1, $required); } public function fetchLastRunBefore($timestamp, $required = false) { if (! $this->hasBeenLoadedFromDb()) { return $this->nullUnlessRequired($required); } if ($timestamp === null) { $timestamp = time(); } $db = $this->getDb(); $query = $db->select()->from( array('ir' => 'import_run'), 'ir.id' )->where('ir.source_id = ?', $this->id) ->where('ir.start_time < ?', date('Y-m-d H:i:s', $timestamp)) ->order('ir.start_time DESC') ->limit(1); $runId = $db->fetchOne($query); if ($runId) { return ImportRun::load($runId, $this->getConnection()); } else { return $this->nullUnlessRequired($required); } } protected function nullUnlessRequired($required) { if ($required) { throw new NotFoundError( 'No data has been imported for "%s" yet', $this->source_name ); } return null; } public function applyModifiers(& $data) { $modifiers = $this->getRowModifiers(); if (! empty($modifiers)) { foreach ($data as &$row) { $this->applyModifiersToRow($row); } } return $this; } public function applyModifiersToRow(& $row) { $modifiers = $this->getRowModifiers(); foreach ($modifiers as $key => $mods) { foreach ($mods as $mod) { if (! property_exists($row, $key)) { // Partial support for nested keys. Must write result to // a dedicated flat key if (strpos($key, '.') !== false) { $val = SyncUtils::getSpecificValue($row, $key); if ($val !== null) { $target = $mod->getTargetProperty($key); if (strpos($target, '.') !== false) { throw new ConfigurationError( 'Cannot set value for nested key "%s"', $target ); } $row->$target = $mod->transform($val); } } continue; } $target = $mod->getTargetProperty($key); if (is_array($row->$key) && ! $mod->hasArraySupport()) { $new = array(); foreach ($row->$key as $k => $v) { $new[$k] = $mod->transform($v); } $row->$target = $new; } else { $row->$target = $mod->transform($row->$key); } } } return $this; } public function getRowModifiers() { if ($this->rowModifiers === null) { $this->prepareRowModifiers(); } return $this->rowModifiers; } public function hasRowModifiers() { return count($this->getRowModifiers()) > 0; } public function fetchRowModifiers() { $db = $this->getDb(); return ImportRowModifier::loadAll( $this->getConnection(), $db->select() ->from('import_row_modifier') ->where('source_id = ?', $this->id) ->order('priority DESC') ); } protected function prepareRowModifiers() { $modifiers = array(); foreach ($this->fetchRowModifiers() as $mod) { if (! array_key_exists($mod->property_name, $modifiers)) { $modifiers[$mod->property_name] = array(); } $modifiers[$mod->property_name][] = $mod->getInstance(); } $this->rowModifiers = $modifiers; } public function listModifierTargetProperties() { $list = array(); foreach ($this->getRowModifiers() as $rowMods) { foreach ($rowMods as $mod) { if ($mod->hasTargetProperty()) { $list[$mod->getTargetProperty()] = true; } } } return array_keys($list); } public function checkForChanges($runImport = false) { $hadChanges = false; Benchmark::measure('Starting with import ' . $this->source_name); try { $import = new Import($this); $this->last_attempt = date('Y-m-d H:i:s'); if ($import->providesChanges()) { Benchmark::measure('Found changes for ' . $this->source_name); $hadChanges = true; $this->import_state = 'pending-changes'; if ($runImport && $import->run()) { Benchmark::measure('Import succeeded for ' . $this->source_name); $this->import_state = 'in-sync'; } } else { $this->import_state = 'in-sync'; } $this->last_error_message = null; } catch (Exception $e) { $this->import_state = 'failing'; Benchmark::measure('Import failed for ' . $this->source_name); $this->last_error_message = $e->getMessage(); } if ($this->hasBeenModified()) { $this->store(); } return $hadChanges; } public function runImport() { return $this->checkForChanges(true); } }