1
\$\begingroup\$

I need:

  1. Daily save new exchange rates from the REST API in the database.

  2. Return the current exchange rate for a given currency, the whole table for a given day, the exchange rate for a given currency depending on the given currency and convert currency.

The code works, but I know it should not look that way. I do not know how to write it better.

2019_01_31_155244_create_nbp_rates_table.php

<?php

    use Illuminate\Support\Facades\Schema;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Database\Migrations\Migration;

    class CreateNbpRatesTable extends Migration
    {

        /**
         * Run the migrations.
         *
         * @return void
         */
        public function up()
        {
            Schema::connection('mysql_nbp')->create('rates', function (Blueprint $table) {
                $table->increments('id');
                $table->char('no', 20)->unique();
                $table->date('effectiveDate')->unique();
                $table->json('table_a');
                $table->timestamps();
            });
        }

        /**
         * Reverse the migrations.
         *
         * @return void
         */
        public function down()
        {
            Schema::connection('mysql_nbp')->dropIfExists('rates');
        }

    }

NBP.php - model

<?php

    namespace Modules\NBP\Entities;

    use Illuminate\Database\Eloquent\Model;
    use Exception;
    use GuzzleHttp\Client;
    use GuzzleHttp\Exception\RequestException;

    class NBP extends Model
    {

        protected $table = 'rates';
        protected $connection = 'mysql_nbp';
        protected $fillable = [
            'no', 'effectiveDate', 'table_a'
        ];
        public $date;
        protected $_ratesCurrent;
        protected $_ratesByDate;

        function __construct()
        {
            parent::__construct();
        }

        public function getCurrentRates()
        {
            return $this->getByDateRates(self::max('effectiveDate'));
        }

        public function getByDateRates($date)
        {
            $this->date = $date;
            $this->validatedDate();

            while (true) {
                $result = self::where('effectiveDate', $this->date)->get()->toArray();
                if (count($result) == 0) {
                    $this->date = date('Y-m-d', strtotime($this->date . "-1 days"));
                } else {
                    $result = self::where('effectiveDate', $this->date)->get()->toArray();
                    $this->effectiveDate = $result[0]['effectiveDate'];
                    $this->no = $result[0]['no'];
                    $this->table = json_decode($result[0]['table_a'], true);
                    $this->_ratesByDate = $this->generateTable();
                    break;
                }
            }
            return $this->_ratesByDate;
        }

        public function getCurrentRateByIso($iso)
        {
            if (!isset($this->_ratesCurrent)) {
                $this->getCurrentRates();
            }
            if (array_key_exists($iso, $this->_ratesCurrent)) {
                return $this->_ratesCurrent[$iso];
            } else {
                throw new Exception('Brak kursu dla podanego kodu ISO', 400);
            }
        }

        public function getByDateRateByIso($iso, $date)
        {
            $this->date = $date;
            $this->validatedDate();
            $this->getByDateRates($date);

            if (array_key_exists($iso, $this->_ratesByDate)) {
                return $this->_ratesByDate[$iso];
            } else {
                throw new Exception('Brak kursu dla podanego kodu ISO', 400);
            }
        }

        public function exchange($isoFrom, $isoTo, $amount, $date = false)
        {
            if (!is_numeric($amount)) {
                throw new Exception('Nieprawidłowa kwota', 400);
            }
            $this->date = $date;
            if ($isoFrom == $isoTo) {
                return $amount;
            }

            if ($this->date === false) {
                $this->date = date('Y-m-d');
            } else {
                $this->validatedDate();
            }
            if ($isoFrom == 'PLN') {
                return $amount * $this->getByDateRateByIso($isoTo, $this->date);
            }

            if ($isoTo == 'PLN') {
                return $amount / $this->getByDateRateByIso($isoFrom, $this->date);
            }

            return $amount * $this->getByDateRateByIso($isoFrom, $this->date) / $this->getByDateRateByIso($isoTo, $this->date);
        }

        private function validatedDate()
        {
            if (!$this->date) {
                throw new Exception('Brak daty', 400);
            }

            try {
                new \DateTime($this->date);
                $this->date = date('Y-m-d', strtotime($this->date));
            } catch (\Exception $e) {
                throw new Exception('Nieprawidłowy format daty', 400);
            }
        }

        private function generateTable()
        {
            if (!$this->table) {
                throw new Exception('Brak wyników', 400);
            }
            $rates = [];
            foreach ($this->table as $rate) {
                $rates[(string) $rate['code']] = $rate['mid'];
            }
            $this->rates = $rates;
            return $this->rates;
        }

        public function downloadNowTables() {
            $begin = new \DateTime(date('Y-m-d', strtotime('- 1 week')));
            $end = new \DateTime(date('Y-m-d'));
            $end = $end->modify('+1 day');

            $interval = new \DateInterval('P1D');
            $daterange = new \DatePeriod($begin, $interval, $end);
            $GuzzleClient = new Client([
                'base_uri' => 'http://api.nbp.pl/api/',
                'defaults' => [
                    'headers' => ['Accept' => 'application/json']
                ]
            ]);
            foreach ($daterange as $date) {
                var_dump($date->format("Y-m-d"));
                while (true) {
                    try {
                        if (self::where('effectiveDate',$date->format("Y-m-d"))->count() == 0) {
                            $response = $GuzzleClient->get('exchangerates/tables/a/' . $date->format("Y-m-d"));
                            $array = json_decode($response->getBody(), true);
                            $rates = [];
                            foreach ($array[0]['rates'] as $rate) {
                                $rates[$rate['code']] = $rate;
                            }
                            self::insert([
                                'no' => $array[0]['no'],
                                'effectiveDate' => $array[0]['effectiveDate'],
                                'table_a' => json_encode($rates),
                                'created_at' => date('Y-m-d H:i:s'),
                                'updated_at' => date('Y-m-d H:i:s')
                            ]);
                        }
                        break;
                    } catch (RequestException $e) {
                        if (strpos($e->getMessage(), 'Brak danych')) {
                            break;
                        }
                    }
                }
            }
        }

    }
\$\endgroup\$
  • \$\begingroup\$ I need? Does the code below completes to two tasks? \$\endgroup\$ – Ludisposed Feb 4 at 14:10
  • \$\begingroup\$ Yes. It is working fine now and I need your opinions on the things I have done in this code to improve myself. \$\endgroup\$ – MRO Feb 5 at 11:48
0
\$\begingroup\$

The API's URL is harcoded here, shouldn't it be better to use a configuration file? What if you want to use a different one or the API owners change the address?

'base_uri' => 'http://api.nbp.pl/api/',
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.