Loading app/Console/Commands/ImportResourceCategories.php 0 → 100644 +170 −0 Original line number Diff line number Diff line <?php namespace App\Console\Commands; use App\Language; use App\Resource; use App\ResourceCategory; use Illuminate\Console\Command; /** * Class ImportResources * @package App\Console\Commands * @see https://laravel.com/docs/5.6/artisan */ class ImportResourceCategories extends Command { protected $signature = 'import:resource-categories {csv_file_name}'; protected $description = 'Import resource categories into the API via a CSV file.'; protected $csv_file_name = null; protected $csv_file_pathinfo = []; protected $csv_headers = null; protected $csv_data = []; protected static $required_headers = [ 'resource category', 'resource category parent' ]; protected static $cached_categories = []; public function handle() { ini_set('auto_detect_line_endings', true); $this->csv_file_name = $this->argument('csv_file_name'); try { // exception will be thrown if file is invalid $this->csv_file_pathinfo = $this->checkFileProperties($this->csv_file_name); } catch (\Exception $exception) { $this->output->writeln("<error>Error encountered:</error> {$exception->getMessage()}"); return false; } list($this->csv_headers, $this->csv_data) = $this->getFileData($this->csv_file_name); $this->checkHeaders($this->csv_headers); // throws exception if fails // we now have the resources list foreach ($this->csv_data as $csv_row_number => $_category) { $resource_category = ResourceCategory::firstOrCreate([ 'name' => $_category['resource category'], 'parent_category' => $_category['resource category parent'] ]); if (!$resource_category->exists()) { $resource_category->save(); } } } protected function checkHeaders($csv_headers) { foreach (static::$required_headers as $required_header) { if (in_array($required_header, $csv_headers) === false) { throw new \Exception ("Missing required header in CSV: {$required_header}"); } } } protected function getFileData($csv_file_name) { $file_handle = fopen($csv_file_name, 'r'); $csv_headers = null; $csv_data = []; $row_number = 0; $empty_rows = 0; // if 3 empty rows are encountered we just break the loop- assumed end of data while (($csv_row = fgetcsv($file_handle)) !== false) { $row_number++; // the header is also a row in the CSV if ($csv_headers === null) { $_csv_headers = []; foreach ($csv_row as $header) { $_csv_headers[] = trim(strtolower($header)); } $csv_headers = $_csv_headers; unset($_csv_headers); continue; } // skip empty rows if (array_filter(array_unique($csv_row)) === []) { $empty_rows++; if ($empty_rows >= 3) { // assume we have reached the end of the data $this->output->writeln("<comment>Assumed end of data:</comment> {$row_number}"); break; } else { $this->output->writeln("<comment>Skip empty row:</comment> {$row_number}"); continue; } } $_csv_data = []; foreach ($csv_headers as $header_index => $header) { $_csv_data[$header] = trim($csv_row[$header_index]); // we trim to ensure no additional spaces // ensure the data is expected - primarily for the URL's $validation_method = camel_case('validate ' . $header); if (method_exists($this, $validation_method) && !empty($_csv_data[$header])) { if (!$this->$validation_method($_csv_data[$header])) { throw new \Exception("Issue with {$header} on row: {$row_number}"); } } } $csv_data[$row_number] = $_csv_data; // add the row to the data with same row number as that in the CSV unset($_csv_data); } return [$csv_headers, $csv_data]; } protected function checkFileProperties($csv_file_name) { if (file_exists($csv_file_name) === false) { throw new \Exception('File does not exist'); } $csv_file_pathinfo = pathinfo($csv_file_name); // extension is only defined if one is provided, eg /etc/hosts will have no extension if (!isset($csv_file_pathinfo['extension']) || $csv_file_pathinfo['extension'] !== 'csv') { throw new \Exception('File is not CSV'); } return $csv_file_pathinfo; } protected function validateUkAsset($uk_asset) { return $this->validateUrl($uk_asset); } protected function validateFrAsset($asset) { return $this->validateUrl($asset); } protected function validateDeAsset($asset) { return $this->validateUrl($asset); } protected function validateNoAsset($asset) { return $this->validateUrl($asset); } protected function validateUrl($asset) { return filter_var($asset, FILTER_VALIDATE_URL); } } No newline at end of file app/Console/Commands/ImportResources.php +25 −26 Original line number Diff line number Diff line Loading @@ -56,29 +56,29 @@ class ImportResources extends Command // we now have the resources list foreach ($this->csv_data as $csv_row_number => $_resource) { $language = null; $resource_link = null; // add here cases for the different kinds of resources we are importing if (!empty($_resource['uk asset'])) { $language = $this->getLanguageFor('uk'); $resource_link = $_resource['uk asset']; } else if (!empty($_resource['nl asset'])) { $language = $this->getLanguageFor('nl'); $resource_link = $_resource['nl asset']; } else if (!empty($_resource['de asset'])) { $language = $this->getLanguageFor('de'); $resource_link = $_resource['de asset']; } else if (!empty($_resource['no asset'])) { $language = $this->getLanguageFor('no'); $resource_link = $_resource['no asset']; } else if (!empty($_resource['sl asset'])) { $language = $this->getLanguageFor('sl'); $resource_link = $_resource['sl asset']; } else { $this->output->writeln("<comment>Could not determine language</comment> {$csv_row_number}"); continue; } $language = $this->getLanguageFor($_resource['language']); $resource_link = $_resource['url']; // // add here cases for the different kinds of resources we are importing // if (!empty($_resource['uk asset'])) { // $language = $this->getLanguageFor('uk'); // $resource_link = $_resource['uk asset']; // } else if (!empty($_resource['nl asset'])) { // $language = $this->getLanguageFor('nl'); // $resource_link = $_resource['nl asset']; // } else if (!empty($_resource['de asset'])) { // $language = $this->getLanguageFor('de'); // $resource_link = $_resource['de asset']; // } else if (!empty($_resource['no asset'])) { // $language = $this->getLanguageFor('no'); // $resource_link = $_resource['no asset']; // } else if (!empty($_resource['sl asset'])) { // $language = $this->getLanguageFor('sl'); // $resource_link = $_resource['sl asset']; // } else { // $this->output->writeln("<comment>Could not determine language</comment> {$csv_row_number}"); // continue; // } // check for duplicates if ($this->isDuplicateResource($language->id, $resource_link)) { Loading @@ -100,15 +100,14 @@ class ImportResources extends Command } } protected function getResourceCategory($category, $parent_category) protected function getResourceCategory($category) { if (isset(static::$cached_categories[$category])) { return static::$cached_categories[$category]; } $resource_category = ResourceCategory::firstOrCreate([ 'name' => $category, 'parent_category' => $parent_category 'name' => $category ]); if (!$resource_category->exists()) { Loading app/Console/Kernel.php +2 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ namespace App\Console; use App\Console\Commands\AddCurrency; use App\Console\Commands\ImportResourceCategories; use App\Console\Commands\ImportResources; use App\Console\Commands\Make\MakeAdminUser; use Illuminate\Console\Scheduling\Schedule; Loading @@ -17,6 +18,7 @@ class Kernel extends ConsoleKernel */ protected $commands = [ ImportResources::class, ImportResourceCategories::class, AddCurrency::class, MakeAdminUser::class ]; Loading database/migrations/2018_04_18_121713_import_emily_questions.php +4 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,10 @@ class ImportEmilyQuestions extends CharacterMigration */ public function up() { if (!\App\ResourceCategory::count()) { throw new \Exception('Import resources first.'); } $this->created_at = date('Y-m-d H:i:s'); $this->character = new \App\Character(); Loading database/migrations/CharacterMigration.php +4 −2 Original line number Diff line number Diff line Loading @@ -187,9 +187,11 @@ class CharacterMigration extends Migration foreach ($_answer['resource_categories'] as $_resource_category) { $category = \App\ResourceCategory::where('name', 'LIKE', $_resource_category)->first(); if ($category) { $answer->resourceCategories()->syncWithoutDetaching($category); if (!$category) { throw new \Exception('Resource category not found: ' . $_resource_category); } $answer->resourceCategories()->syncWithoutDetaching($category); } } } Loading Loading
app/Console/Commands/ImportResourceCategories.php 0 → 100644 +170 −0 Original line number Diff line number Diff line <?php namespace App\Console\Commands; use App\Language; use App\Resource; use App\ResourceCategory; use Illuminate\Console\Command; /** * Class ImportResources * @package App\Console\Commands * @see https://laravel.com/docs/5.6/artisan */ class ImportResourceCategories extends Command { protected $signature = 'import:resource-categories {csv_file_name}'; protected $description = 'Import resource categories into the API via a CSV file.'; protected $csv_file_name = null; protected $csv_file_pathinfo = []; protected $csv_headers = null; protected $csv_data = []; protected static $required_headers = [ 'resource category', 'resource category parent' ]; protected static $cached_categories = []; public function handle() { ini_set('auto_detect_line_endings', true); $this->csv_file_name = $this->argument('csv_file_name'); try { // exception will be thrown if file is invalid $this->csv_file_pathinfo = $this->checkFileProperties($this->csv_file_name); } catch (\Exception $exception) { $this->output->writeln("<error>Error encountered:</error> {$exception->getMessage()}"); return false; } list($this->csv_headers, $this->csv_data) = $this->getFileData($this->csv_file_name); $this->checkHeaders($this->csv_headers); // throws exception if fails // we now have the resources list foreach ($this->csv_data as $csv_row_number => $_category) { $resource_category = ResourceCategory::firstOrCreate([ 'name' => $_category['resource category'], 'parent_category' => $_category['resource category parent'] ]); if (!$resource_category->exists()) { $resource_category->save(); } } } protected function checkHeaders($csv_headers) { foreach (static::$required_headers as $required_header) { if (in_array($required_header, $csv_headers) === false) { throw new \Exception ("Missing required header in CSV: {$required_header}"); } } } protected function getFileData($csv_file_name) { $file_handle = fopen($csv_file_name, 'r'); $csv_headers = null; $csv_data = []; $row_number = 0; $empty_rows = 0; // if 3 empty rows are encountered we just break the loop- assumed end of data while (($csv_row = fgetcsv($file_handle)) !== false) { $row_number++; // the header is also a row in the CSV if ($csv_headers === null) { $_csv_headers = []; foreach ($csv_row as $header) { $_csv_headers[] = trim(strtolower($header)); } $csv_headers = $_csv_headers; unset($_csv_headers); continue; } // skip empty rows if (array_filter(array_unique($csv_row)) === []) { $empty_rows++; if ($empty_rows >= 3) { // assume we have reached the end of the data $this->output->writeln("<comment>Assumed end of data:</comment> {$row_number}"); break; } else { $this->output->writeln("<comment>Skip empty row:</comment> {$row_number}"); continue; } } $_csv_data = []; foreach ($csv_headers as $header_index => $header) { $_csv_data[$header] = trim($csv_row[$header_index]); // we trim to ensure no additional spaces // ensure the data is expected - primarily for the URL's $validation_method = camel_case('validate ' . $header); if (method_exists($this, $validation_method) && !empty($_csv_data[$header])) { if (!$this->$validation_method($_csv_data[$header])) { throw new \Exception("Issue with {$header} on row: {$row_number}"); } } } $csv_data[$row_number] = $_csv_data; // add the row to the data with same row number as that in the CSV unset($_csv_data); } return [$csv_headers, $csv_data]; } protected function checkFileProperties($csv_file_name) { if (file_exists($csv_file_name) === false) { throw new \Exception('File does not exist'); } $csv_file_pathinfo = pathinfo($csv_file_name); // extension is only defined if one is provided, eg /etc/hosts will have no extension if (!isset($csv_file_pathinfo['extension']) || $csv_file_pathinfo['extension'] !== 'csv') { throw new \Exception('File is not CSV'); } return $csv_file_pathinfo; } protected function validateUkAsset($uk_asset) { return $this->validateUrl($uk_asset); } protected function validateFrAsset($asset) { return $this->validateUrl($asset); } protected function validateDeAsset($asset) { return $this->validateUrl($asset); } protected function validateNoAsset($asset) { return $this->validateUrl($asset); } protected function validateUrl($asset) { return filter_var($asset, FILTER_VALIDATE_URL); } } No newline at end of file
app/Console/Commands/ImportResources.php +25 −26 Original line number Diff line number Diff line Loading @@ -56,29 +56,29 @@ class ImportResources extends Command // we now have the resources list foreach ($this->csv_data as $csv_row_number => $_resource) { $language = null; $resource_link = null; // add here cases for the different kinds of resources we are importing if (!empty($_resource['uk asset'])) { $language = $this->getLanguageFor('uk'); $resource_link = $_resource['uk asset']; } else if (!empty($_resource['nl asset'])) { $language = $this->getLanguageFor('nl'); $resource_link = $_resource['nl asset']; } else if (!empty($_resource['de asset'])) { $language = $this->getLanguageFor('de'); $resource_link = $_resource['de asset']; } else if (!empty($_resource['no asset'])) { $language = $this->getLanguageFor('no'); $resource_link = $_resource['no asset']; } else if (!empty($_resource['sl asset'])) { $language = $this->getLanguageFor('sl'); $resource_link = $_resource['sl asset']; } else { $this->output->writeln("<comment>Could not determine language</comment> {$csv_row_number}"); continue; } $language = $this->getLanguageFor($_resource['language']); $resource_link = $_resource['url']; // // add here cases for the different kinds of resources we are importing // if (!empty($_resource['uk asset'])) { // $language = $this->getLanguageFor('uk'); // $resource_link = $_resource['uk asset']; // } else if (!empty($_resource['nl asset'])) { // $language = $this->getLanguageFor('nl'); // $resource_link = $_resource['nl asset']; // } else if (!empty($_resource['de asset'])) { // $language = $this->getLanguageFor('de'); // $resource_link = $_resource['de asset']; // } else if (!empty($_resource['no asset'])) { // $language = $this->getLanguageFor('no'); // $resource_link = $_resource['no asset']; // } else if (!empty($_resource['sl asset'])) { // $language = $this->getLanguageFor('sl'); // $resource_link = $_resource['sl asset']; // } else { // $this->output->writeln("<comment>Could not determine language</comment> {$csv_row_number}"); // continue; // } // check for duplicates if ($this->isDuplicateResource($language->id, $resource_link)) { Loading @@ -100,15 +100,14 @@ class ImportResources extends Command } } protected function getResourceCategory($category, $parent_category) protected function getResourceCategory($category) { if (isset(static::$cached_categories[$category])) { return static::$cached_categories[$category]; } $resource_category = ResourceCategory::firstOrCreate([ 'name' => $category, 'parent_category' => $parent_category 'name' => $category ]); if (!$resource_category->exists()) { Loading
app/Console/Kernel.php +2 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ namespace App\Console; use App\Console\Commands\AddCurrency; use App\Console\Commands\ImportResourceCategories; use App\Console\Commands\ImportResources; use App\Console\Commands\Make\MakeAdminUser; use Illuminate\Console\Scheduling\Schedule; Loading @@ -17,6 +18,7 @@ class Kernel extends ConsoleKernel */ protected $commands = [ ImportResources::class, ImportResourceCategories::class, AddCurrency::class, MakeAdminUser::class ]; Loading
database/migrations/2018_04_18_121713_import_emily_questions.php +4 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,10 @@ class ImportEmilyQuestions extends CharacterMigration */ public function up() { if (!\App\ResourceCategory::count()) { throw new \Exception('Import resources first.'); } $this->created_at = date('Y-m-d H:i:s'); $this->character = new \App\Character(); Loading
database/migrations/CharacterMigration.php +4 −2 Original line number Diff line number Diff line Loading @@ -187,9 +187,11 @@ class CharacterMigration extends Migration foreach ($_answer['resource_categories'] as $_resource_category) { $category = \App\ResourceCategory::where('name', 'LIKE', $_resource_category)->first(); if ($category) { $answer->resourceCategories()->syncWithoutDetaching($category); if (!$category) { throw new \Exception('Resource category not found: ' . $_resource_category); } $answer->resourceCategories()->syncWithoutDetaching($category); } } } Loading