diff --git a/composer.json b/composer.json index 8c0537b..41149e9 100644 --- a/composer.json +++ b/composer.json @@ -24,5 +24,15 @@ "psr-4": { "Torann\\Currency\\": "src/" } + }, + "extra": { + "laravel": { + "providers": [ + "Torann\\Currency\\CurrencyServiceProvider" + ], + "aliases": { + "Currency": "Torann\\Currency\\Facades\\Currency" + } + } } } diff --git a/config/currency.php b/config/currency.php index 0f580af..f9da49d 100644 --- a/config/currency.php +++ b/config/currency.php @@ -15,13 +15,28 @@ 'default' => 'USD', + /* + |-------------------------------------------------------------------------- + | Source + |-------------------------------------------------------------------------- + | + | Select which source to use to retrieve the rates + | + | Fixer http://fixer.io + | Open Exchange Rates https://openexchangerates.org + | + | Supported: "fixer", "openexchangerates" + | + */ + + 'source' => 'fixer', + /* |-------------------------------------------------------------------------- | API Key for OpenExchangeRates.org |-------------------------------------------------------------------------- | - | Only required if you with to use the Open Exchange Rates api. You can - | always just use Yahoo, the current default. + | Only required if you with to use the Open Exchange Rates api. | */ diff --git a/database/migrations/2013_11_26_161502_alter_currency_table_add_update_column.php b/database/migrations/2013_11_26_161502_alter_currency_table_add_update_column.php new file mode 100644 index 0000000..b93e4b6 --- /dev/null +++ b/database/migrations/2013_11_26_161502_alter_currency_table_add_update_column.php @@ -0,0 +1,45 @@ +table_name = config('currency.drivers.database.table'); + } + + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table($this->table_name, function ($table) { + $table->boolean('auto_update')->default(true)->after('active'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table($this->table_name, function ($table) { + $table->dropColumn('auto_update'); + }); + } +} diff --git a/src/Console/Update.php b/src/Console/Update.php index eda4ec7..9bee0b0 100644 --- a/src/Console/Update.php +++ b/src/Console/Update.php @@ -3,131 +3,201 @@ namespace Torann\Currency\Console; use DateTime; +use DateTimeZone; use Illuminate\Console\Command; class Update extends Command { - /** - * The name and signature of the console command. - * - * @var string - */ - protected $signature = 'currency:update - {--o|openexchangerates : Get rates from OpenExchangeRates.org}'; - - /** - * The console command description. - * - * @var string - */ - protected $description = 'Update exchange rates from an online source'; - - /** - * Currency instance - * - * @var \Torann\Currency\Currency - */ - protected $currency; - - /** - * Create a new command instance. - */ - public function __construct() - { - $this->currency = app('currency'); - - parent::__construct(); - } - - /** - * Execute the console command for Laravel 5.4 and below - * - * @return void - */ - public function fire() - { - $this->handle(); - } - - /** - * Execute the console command. - * - * @return void - */ - public function handle() - { - // Get Settings - $defaultCurrency = $this->currency->config('default'); - - if (!$api = $this->currency->config('api_key')) { - $this->error('An API key is needed from OpenExchangeRates.org to continue.'); - - return; - } - - // Get rates - $this->updateFromOpenExchangeRates($defaultCurrency, $api); - } - - /** - * Fetch rates from the API - * - * @param $defaultCurrency - * @param $api - */ - private function updateFromOpenExchangeRates($defaultCurrency, $api) - { - $this->info('Updating currency exchange rates from OpenExchangeRates.org...'); - - // Make request - $content = json_decode($this->request("http://openexchangerates.org/api/latest.json?base={$defaultCurrency}&app_id={$api}&show_alternative=1")); - - // Error getting content? - if (isset($content->error)) { - $this->error($content->description); - - return; - } - - // Parse timestamp for DB - $timestamp = (new DateTime())->setTimestamp($content->timestamp); - - // Update each rate - foreach ($content->rates as $code => $value) { - $this->currency->getDriver()->update($code, [ - 'exchange_rate' => $value, - 'updated_at' => $timestamp, - ]); - } - - $this->currency->clearCache(); - - $this->info('Update!'); - } - - /** - * Make the request to the sever. - * - * @param $url - * - * @return string - */ - private function request($url) - { - $ch = curl_init($url); - - curl_setopt($ch, CURLOPT_HEADER, false); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20); - curl_setopt($ch, CURLOPT_TIMEOUT, 20); - curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1"); - curl_setopt($ch, CURLOPT_HTTPGET, true); - curl_setopt($ch, CURLOPT_MAXREDIRS, 2); - curl_setopt($ch, CURLOPT_MAXCONNECTS, 2); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - - $response = curl_exec($ch); - curl_close($ch); - - return $response; - } + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'currency:update {currency? : Optional currency to be updated, otherwise all will be updated} + {--o|openexchangerates : Get rates from OpenExchangeRates.org} + {--f|fixer : Get rates from Fixer}'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Update exchange rates from an online source'; + + /** + * Currency instance + * + * @var \Torann\Currency\Currency + */ + protected $currency; + + /** + * Create a new command instance. + */ + public function __construct() + { + $this->currency = app('currency'); + + parent::__construct(); + } + + /** + * Execute the console command for Laravel 5.4 and below + * + * @return void + */ + public function fire() + { + $this->handle(); + } + + /** + * Execute the console command. + * + * @return void + */ + public function handle() + { + // Get Settings + $defaultCurrency = $this->currency->config('default'); + + $source = config('currency.source'); + + // Check options + if ($this->input->getOption('openexchangerates')) { + $source = "openexchangerates"; + } else if ($this->input->getOption('fixer')) { + $source = "fixer"; + } + + // Get rates + if ($source === 'openexchangerates') { + + // Make sure the API key is set + if (!$api = $this->currency->config('api_key')) { + $this->error('An API key is needed from OpenExchangeRates.org to continue.'); + return; + } + + $this->updateFromOpenExchangeRates($defaultCurrency, $api); + + } else if ($source === 'fixer') { + $this->updateFromFixer($defaultCurrency); + } else { + $this->error('There is no source configured to update the currencies from.'); + } + + } + + private function updateFromFixer($defaultCurrency) + { + $this->info('Updating currency exchange rates from Fixer.io...'); + + $result = json_decode($this->request("http://api.fixer.io/latest?base={$defaultCurrency}")); + + if (isset($result->error)) { + $this->error($result->description); + return; + } + + // As there's no timestamp, according to Fixer.io, it updates at around 4pm CET. + // Hence why we're manually putting in the time here. + $timestamp = new DateTime($result->date . ' 16:00:00', new DateTimeZone('CET')); + + $this->updateRates($result->rates, $timestamp); + + // Fixer doesn't return the base rate as 1, hence we need to update it manually. + $this->currency->getDriver()->update($defaultCurrency, [ + 'exchange_rate' => 1, + 'updated_at' => $timestamp, + ]); + + } + + /** + * Fetch rates from the API + * + * @param $defaultCurrency + * @param $api + */ + private function updateFromOpenExchangeRates($defaultCurrency, $api) + { + $this->info('Updating currency exchange rates from OpenExchangeRates.org...'); + + // Make request + $content = json_decode($this->request("http://openexchangerates.org/api/latest.json?base={$defaultCurrency}&app_id={$api}&show_alternative=1")); + + // Error getting content? + if (isset($content->error)) { + $this->error($content->description); + + return; + } + + // Parse timestamp for DB + $timestamp = (new DateTime())->setTimestamp($content->timestamp); + + $this->updateRates($content->rates, $timestamp); + + $this->currency->clearCache(); + + $this->info('Update!'); + } + + /** + * Update the rates with the given timestamp + * + * @param $rates + * @param $timestamp + */ + private function updateRates($rates, $timestamp) + { + //If we're updating only one rate + if ($currency = $this->argument('currency')) { + /** @var \stdClass $rates */ + if (isset($rates->{$currency})) { + $this->currency->getDriver()->update($currency, [ + 'exchange_rate' => $rates->{$currency}, + 'updated_at' => $timestamp, + ]); + } else { + $this->error('The currency cannot be found.'); + } + + } else { + // Update all rates + foreach ($rates as $code => $value) { + $this->currency->getDriver()->update($code, [ + 'exchange_rate' => $value, + 'updated_at' => $timestamp, + ]); + } + } + } + + /** + * Make the request to the sever. + * + * @param $url + * + * @return string + */ + private function request($url) + { + $ch = curl_init($url); + + curl_setopt($ch, CURLOPT_HEADER, false); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20); + curl_setopt($ch, CURLOPT_TIMEOUT, 20); + curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1"); + curl_setopt($ch, CURLOPT_HTTPGET, true); + curl_setopt($ch, CURLOPT_MAXREDIRS, 2); + curl_setopt($ch, CURLOPT_MAXCONNECTS, 2); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + + $response = curl_exec($ch); + curl_close($ch); + + return $response; + } } diff --git a/src/Contracts/DriverInterface.php b/src/Contracts/DriverInterface.php index 8097e4a..1317e0d 100644 --- a/src/Contracts/DriverInterface.php +++ b/src/Contracts/DriverInterface.php @@ -31,17 +31,18 @@ public function all(); * @return mixed */ public function find($code, $active = 1); - - /** - * Update given currency. - * - * @param string $code - * @param array $attributes - * @param DateTime $timestamp - * - * @return int - */ - public function update($code, array $attributes, DateTime $timestamp = null); + + /** + * Update given currency. + * + * @param string $code + * @param array $attributes + * @param DateTime $timestamp + * @param bool $auto Whether or not it's performed automatically + * + * @return int + */ + public function update($code, array $attributes, DateTime $timestamp = null, $auto = false); /** * Remove given currency from storage. diff --git a/src/Drivers/Database.php b/src/Drivers/Database.php index e326e60..f060ee8 100644 --- a/src/Drivers/Database.php +++ b/src/Drivers/Database.php @@ -47,6 +47,7 @@ public function create(array $params) 'format' => '', 'exchange_rate' => 1, 'active' => 0, + 'auto_update' => 1, 'created_at' => $created, 'updated_at' => $created, ], $params); @@ -97,7 +98,7 @@ public function find($code, $active = 1) /** * {@inheritdoc} */ - public function update($code, array $attributes, DateTime $timestamp = null) + public function update($code, array $attributes, DateTime $timestamp = null, $auto = false) { $table = $this->config('table'); @@ -106,9 +107,17 @@ public function update($code, array $attributes, DateTime $timestamp = null) $attributes['updated_at'] = new DateTime('now'); } - return $this->database->table($table) - ->where('code', strtoupper($code)) - ->update($attributes); + //Only apply to those with auto update if it's automatically updating + if ($auto) { + return $this->database->table($table) + ->where('code', strtoupper($code)) + ->where('auto_update', 1) + ->update($attributes); + } else { + return $this->database->table($table) + ->where('code', strtoupper($code)) + ->update($attributes); + } } /** diff --git a/src/Drivers/Filesystem.php b/src/Drivers/Filesystem.php index 16b7c68..1c9ac48 100644 --- a/src/Drivers/Filesystem.php +++ b/src/Drivers/Filesystem.php @@ -54,6 +54,7 @@ public function create(array $params) 'format' => '', 'exchange_rate' => 1, 'active' => 0, + 'auto_update' => 1, 'created_at' => $created, 'updated_at' => $created, ], $params); @@ -95,7 +96,7 @@ public function find($code, $active = 1) /** * {@inheritdoc} */ - public function update($code, array $attributes, DateTime $timestamp = null) + public function update($code, array $attributes, DateTime $timestamp = null, $auto = false) { // Get blacklist path $path = $this->config('path'); @@ -114,7 +115,14 @@ public function update($code, array $attributes, DateTime $timestamp = null) } // Merge values - $currencies[$code] = array_merge($currencies[$code], $attributes); + if ($auto) { + //If auto update disabled + if ($currencies[$code]['auto_update']) { + $currencies[$code] = array_merge($currencies[$code], $attributes); + } + } else { + $currencies[ $code ] = array_merge($currencies[ $code ], $attributes); + } return $this->filesystem->put($path, json_encode($currencies, JSON_PRETTY_PRINT)); }