/** * Apply changes from the CSV file * * @param string $path Path to the CSV file * @return void */ protected function _handleCsv($path = '') { $tableName = Inflector::pluralize(Inflector::classify($this->_table->getName())); if ('' === trim($path)) { $pathFinder = new MigrationPathFinder(); $path = $pathFinder->find($tableName); } $parser = new MigrationParser(); $csvData = $parser->wrapFromPath($path); $csvData = array_merge($csvData, $this->_requiredFields); $tableFields = $this->_getTableFields(); if (empty($tableFields)) { $this->_createFromCsv($csvData); } else { $this->_updateFromCsv($csvData, $tableFields); } }
/** * Method that retrieves fields from csv file and returns them in associate array format. * * @param string $moduleName Module Name * @return array */ public function getFieldsDefinitions($moduleName = null) { if (!empty($this->_fieldDefinitions)) { return $this->_fieldDefinitions; } if (is_null($moduleName)) { if (is_callable([$this, 'alias'])) { $moduleName = $this->alias(); } else { throw new RuntimeException("Failed getting field definitions for unknown module"); } } $pathFinder = new MigrationPathFinder(); $path = $pathFinder->find($moduleName); // Parser knows how to make sure that the file exists. But it can // also throw other exceptions, which we don't want to avoid for // now. if (is_readable($path)) { $parser = new MigrationParser(); $this->_fieldDefinitions = $parser->wrapFromPath($path); } return $this->_fieldDefinitions; }
/** * Check migration.csv fields * * @param array $modules List of modules to check * @return int Count of errors found */ protected function _checkMigrationFields(array $modules = []) { $errors = []; $warnings = []; $this->out('Checking migration fields:', 2); foreach ($modules as $module => $path) { $moduleErrors = []; $this->out(' - ' . $module . ' ... ', 0); $fields = null; try { $pathFinder = new MigrationPathFinder(); $path = $pathFinder->find($module); $parser = new MigrationParser(); $fields = $parser->parseFromPath($path); } catch (\Exception $e) { // We've already reported this problem in _checkMigrationPresence(); } if ($fields) { $seenFields = []; // Check each field one by one foreach ($fields as $field) { // Field name is required if (empty($field['name'])) { $moduleErrors[] = $module . " migration has a field without a name"; } else { // Check for field duplicates if (in_array($field['name'], $seenFields)) { $moduleErrors[] = $module . " migration specifies field '" . $field['name'] . "' more than once"; } else { $seenFields[] = $field['name']; } // Field type is required if (empty($field['type'])) { $moduleErrors[] = $module . " migration does not specify type for field '" . $field['name'] . "'"; } else { $type = null; $limit = null; // Matches: // * date, time, string, and other simple types // * list(something), related(Others) and other simple limits // * related(Vendor/Plugin.Model) and other complex limits if (preg_match('/^(\\w+?)\\(([\\w\\/\\.]+?)\\)$/', $field['type'], $matches)) { $type = $matches[1]; $limit = $matches[2]; } else { $type = $field['type']; } // Field type must be valid if (!$this->_isValidFieldType($type)) { $moduleErrors[] = $module . " migration specifies invalid type '" . $type . "' for field '" . $field['name'] . "'"; } else { switch ($type) { case 'related': // Only check for simple modules, not the vendor/plugin ones if (preg_match('/^\\w+$/', $limit) && !$this->_isValidModule($limit, array_keys($modules))) { $moduleErrors[] = $module . " migration relates to unknown module '{$limit}' in '" . $field['name'] . "' field"; } // Documents module can be used as `files(Documents)` for a container of the uploaded files, // or as `related(Documents)` as a regular module relationship. It's often easy to overlook // which one was desired. Failing on either one is incorrect, as both are valid. A // warning is needed instead for the `related(Documents)` case instead. // The only known legitimate case is in the Files, which is join table between Documents and FileStorage. if ('Documents' == $limit && 'Files' != $module) { $warnings[] = $module . " migration uses 'related' type for 'Documents' in '" . $field['name'] . "'. Maybe wanted 'files(Documents)'?"; } break; case 'list': case 'money': case 'metric': if (!$this->_isValidList($limit)) { $moduleErrors[] = $module . " migration uses unknown or empty list '{$limit}' in '" . $field['name'] . "' field"; } break; } } } } } // Check for the required fields // TODO: Allow specifying the required fields as the command line argument (for things like trashed) $requiredFields = ['id', 'created', 'modified']; foreach ($requiredFields as $requiredField) { if (!in_array($requiredField, $seenFields)) { $moduleErrors[] = $module . " migration is missing a required field '{$requiredField}'"; } } } $result = empty($moduleErrors) ? '<success>OK</success>' : '<error>FAIL</error>'; $this->out($result); $errors = array_merge($errors, $moduleErrors); } $this->_printCheckStatus($errors, $warnings); return count($errors); }
/** * Get csv file's last modified time. * * @param string $tableName target table name * @return string */ protected function _getLastModifiedTime($tableName) { $tableName = Inflector::camelize($tableName); $pathFinder = new MigrationPathFinder(); $path = $pathFinder->find($tableName); // Unit time stamp to YYYYMMDDhhmmss $result = date('YmdHis', filemtime($path)); return $result; }
/** * Method that retrieves and returns csv migration fields. * * @param Request $request Request object * @return array */ protected function _getMigrationFields(Request $request) { $result = []; try { $pathFinder = new MigrationPathFinder(); $path = $pathFinder->find($request->controller); $parser = new MigrationParser(); $result = $parser->wrapFromPath($path); } catch (InvalidArgumentException $e) { Log::error($e); } return $result; }