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\$
2
  • \$\begingroup\$ I need? Does the code below completes to two tasks? \$\endgroup\$
    – Ludisposed
    Feb 4, 2019 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, 2019 at 11:48

1 Answer 1

1
\$\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\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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