From 99a62828f58a2986e10a01f34a591674459c939d Mon Sep 17 00:00:00 2001 From: Deon George Date: Fri, 17 Dec 2021 14:59:55 +1100 Subject: [PATCH] Rework Site and top level tables --- app/Models/Country.php | 11 +- app/Models/Currency.php | 14 +- app/Models/Language.php | 1 - app/Models/Site.php | 92 +++--- app/Models/SiteDetail.php | 275 +++++------------- app/Models/Tax.php | 12 +- .../2021_12_17_131958_cleanup_site.php | 67 +++++ database/seeders/CountryTableSeeder.php | 2 +- 8 files changed, 192 insertions(+), 282 deletions(-) create mode 100644 database/migrations/2021_12_17_131958_cleanup_site.php diff --git a/app/Models/Country.php b/app/Models/Country.php index b63401f..781e823 100644 --- a/app/Models/Country.php +++ b/app/Models/Country.php @@ -6,9 +6,10 @@ use Illuminate\Database\Eloquent\Model; class Country extends Model { - protected $table = 'ab_country'; public $timestamps = FALSE; + /* RELATIONS */ + /** * The currency this country belongs to */ @@ -21,12 +22,4 @@ class Country extends Model { return $this->hasMany(Tax::class); } - - /** - * The accounts in this country - */ - public function users() - { - return $this->hasMany(User::class); - } } \ No newline at end of file diff --git a/app/Models/Currency.php b/app/Models/Currency.php index 7eb1201..22195b4 100644 --- a/app/Models/Currency.php +++ b/app/Models/Currency.php @@ -6,9 +6,6 @@ use Illuminate\Database\Eloquent\Model; class Currency extends Model { - // @todo - temp Until Implemented - protected $fillable = ['rounding']; - protected $table = 'ab_currency'; public $timestamps = FALSE; const ROUND_HALF_UP = 1; @@ -16,14 +13,15 @@ class Currency extends Model const ROUND_HALF_EVEN = 3; const ROUND_HALF_ODD = 4; - /** - * The accounts in this country - */ - public function countries() + /* RELATIONS */ + + public function country() { - return $this->hasMany(Country::class); + return $this->hasOne(Country::class); } + /* METHODS */ + public function round($value,$mode=self::ROUND_HALF_UP) { return round($value,$this->rounding,$mode); diff --git a/app/Models/Language.php b/app/Models/Language.php index 2d6cfb9..6b157ed 100644 --- a/app/Models/Language.php +++ b/app/Models/Language.php @@ -6,6 +6,5 @@ use Illuminate\Database\Eloquent\Model; class Language extends Model { - protected $table = 'ab_language'; public $timestamps = FALSE; } \ No newline at end of file diff --git a/app/Models/Site.php b/app/Models/Site.php index fc75766..65b7147 100644 --- a/app/Models/Site.php +++ b/app/Models/Site.php @@ -4,18 +4,37 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; -use Illuminate\Support\Collection; use Illuminate\Support\Facades\Log; +/** + * This table is used to uniquely identify the website and database behind a URL. + */ class Site extends Model { use HasFactory; public $timestamps = FALSE; - protected $casts = [ - 'address'=>'array', - ]; + public function __get($key) + { + // If we already have a value, return it + if ($x = parent::__get($key)) + return $x; + + // Get the value from the details table + if (($x=$this->detail_item($key)) !== NULL) + return $x; + + // Get a default value for this key + if (($value = SiteDetail::sample($key)) === NULL) + abort(500,sprintf('No default value for [%s]',$key)); + + // At this point our DB doesnt have this value, we'll log an alert + if ($this->exists) + Log::alert(sprintf('Site [%d] is missing value for key [%s] - providing a default [%s]',$this->site_id,$key,serialize($value))); + + return $value; + } /* RELATIONS */ @@ -41,53 +60,11 @@ class Site extends Model /* ATTRIBUTES */ - public function getAllowedKeysAttribute(): Collection - { - return $this->_sampledata()->keys(); - } - - /* METHODS */ - - public function __get($key) - { - static $details = NULL; - - if ($x = parent::__get($key)) - return $x; - - // Get the value from the details table - if (($x=$this->detail_item($key)) !== NULL) - return $x; - - if (is_null($details)) - $details = new SiteDetail; - - // Get a default value for this key - $value = $details->sample($key); - - // At this point our DB doesnt have this value, we'll log an alert - if ($this->exists) - Log::alert(sprintf('Site is missing value for key [%s] - providing a default [%s]',$key,serialize($value))); - - return $value; - } - - /* GENERAL METHODS */ - /** - * Get a key from the site_details + * Return the site address as an array * - * @param $key - * @return mixed + * @return array */ - private function detail_item($key) - { - if (($x=$this->details->search(function($item) use ($key) { return $item->key == $key; })) !== FALSE) - return $this->details->get($x)->value; - - return NULL; - } - public function getAddressAttribute(): array { return [ @@ -102,7 +79,7 @@ class Site extends Model * * @return string */ - public function getEmailLogoAttribute() + public function getEmailLogoAttribute(): string { return (($x=$this->detail_item('email_logo')) !== NULL) ? '/storage/'.$x : '/image/generic/150/20/fff'; } @@ -113,8 +90,23 @@ class Site extends Model * @param $value * @return string */ - public function getSiteLogoAttribute($value) + public function getSiteLogoAttribute($value): string { return (($x=$this->detail_item('site_logo')) !== NULL) ? '/storage/'.$x : '/image/generic/150/20/fff'; } + + /* METHODS */ + + /** + * Get a key from the site_details + * + * @param $key + * @return mixed + */ + private function detail_item($key) + { + return (($x=$this->details->search(function($item) use ($key) { return $item->key === $key; })) !== FALSE) + ? $this->details->get($x)->value + : NULL; + } } \ No newline at end of file diff --git a/app/Models/SiteDetail.php b/app/Models/SiteDetail.php index 2582882..f7dc8c7 100644 --- a/app/Models/SiteDetail.php +++ b/app/Models/SiteDetail.php @@ -3,15 +3,56 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; -use Illuminate\Support\Collection; +use Illuminate\Support\Arr; use Leenooks\Traits\CompositeKeys; class SiteDetail extends Model { use CompositeKeys; + protected $casts = [ + 'social' => 'array', + 'top_menu' => 'array', + ]; + public $incrementing = false; protected $primaryKey = ['site_id','key']; + + /** + * Sample data to use with new sites, if there is no database record + */ + private const sampleData = [ + 'country_id' => 61, + 'currency_id' => 6, + 'language_id' => 1, + 'site_id' => 0, + 'site_name' => 'MY OSB SITE', + 'site_description'=>'Example Site', + 'site_phone'=>'+0 1 2345 6789', + 'site_email' => 'nobody@example.com', + 'site_address1' => 'Address line 1', + 'site_address2' => 'Address line 2', + 'site_city' => 'City', + 'site_state' => 'State', + 'site_postcode' => '12345', + 'social'=>[ + ['name'=>'facebook','url'=>'http://www.facebook.com'], + ['name'=>'linkedin','url'=>'http://www.linkedin.com'], + ['name'=>'twitter','url'=>'http://www.twitter.com'], + ], + 'top_menu'=>[ + 'Home'=>['name'=>'Home','url'=>'/','children'=>[ + ['name'=>'Link 1','url'=>'#/l2', 'children'=>[]], + ['name'=>'Link 2','url'=>'#/l2', 'children'=>[]], + ]], + 'Option1'=>['name'=>'Option 1','url'=>'/o1','children'=>[]], + 'Option2'=>['name'=>'Option 2','url'=>'/o2','children'=>[ + ['name'=>'O2 Link 1','url'=>'#/o2l1', 'children'=>[]], + ['name'=>'O2 Link 1','url'=>'#/o2l2', 'children'=>[]], + ]], + ] + ]; + public $timestamps = FALSE; /* RELATIONS */ @@ -23,224 +64,45 @@ class SiteDetail extends Model /* ATTRIBUTES */ + /** + * Enable us to cast some values + * @param $value + * @return void + */ public function getValueAttribute($value) { - if (! $this->key) - return $value; - - switch (gettype($this->_sampledata()->get($this->key))) { - case 'array': return unserialize($value); - default: return $value; + switch(Arr::get($this->casts,$this->key)) { + case 'array': + return unserialize($value); + default: + return $value; } } - public function setKeyAttribute($value) - { - if (! $this->_sampledata()->has($value)) - throw new \Exception(sprintf('Key [%s] is not expected.',$value)); - - $this->attributes['key'] = $value; - } - + /** + * Set our value, casting it if required + * + * @param $key + * @param $value + * @return string + * @throws \Exception + */ public function setValueAttribute($value) { // Check that the value can be set if (! $this->key) throw new \Exception('Please set key first'); - // Check that the value is of the right type - $x = $this->_sampledata()->get($this->key); - - if ($value && (! $this->checkType($value,$x))) - throw new \Exception(sprintf('Value for [%s] is not the of the correct type [%s] for this attribute, expecting [%s].',$this->key,gettype($value),gettype($this->_sampledata()->get($this->key)))); - - switch (gettype($x)) { + switch(Arr::get($this->casts,$this->key)) { case 'array': - $this->attributes['value'] = serialize($value ?: []); + $value = serialize($value ?: []); break; - - default: - $this->attributes['value'] = $value ?: ''; } + + $this->attributes['value'] = $value; } - /* GENERAL METHODS */ - - /** - * Check that two variables are the same type - * - * @param $a - * @param $b - * @return bool - */ - private function checkType($a,$b): bool - { - return gettype($a) == gettype($b); - } - - /** - * Pre-load this model with Sample Data, if there is no database record - */ - private function _sampleData(): Collection - { - return collect([ - /* - 'aboutus'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', - 'activity'=>[ - ['title'=>'Project 1','description'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.','subtitle'=>'Lorem ipsum dolor sit amet','image_small'=>'/image/generic/150/75/a00','image_large'=>'/image/generic/500/400/700'], - ['title'=>'Project 2','description'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.','subtitle'=>'Lorem ipsum dolor sit amet','image_small'=>'/image/generic/150/75/b00','image_large'=>'/image/generic/500/400/800'], - ['title'=>'Project 3','description'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.','subtitle'=>'Lorem ipsum dolor sit amet','image_small'=>'/image/generic/150/75/c00','image_large'=>'/image/generic/500/400/900'], - ['title'=>'Project 4','description'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.','subtitle'=>'Lorem ipsum dolor sit amet','image_small'=>'/image/generic/150/75/d00','image_large'=>'/image/generic/500/400/a00'], - ], - 'activity_intro'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - 'block_quotes'=>[ - [ - 'title'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - 'image'=>'/image/generic/150/75/1A3AAA' - ], - ], - 'clients'=>[ - [ - 'image'=>'/image/generic/200/100/999', - 'hover'=>'/image/generic/200/100/399', - ], - [ - 'image'=>'/image/generic/200/100/999', - 'hover'=>'/image/generic/200/100/499', - ], - [ - 'image'=>'/image/generic/200/100/999', - 'hover'=>'/image/generic/200/100/599', - ], - [ - 'image'=>'/image/generic/200/100/999', - 'hover'=>'/image/generic/200/100/699', - ], - [ - 'image'=>'/image/generic/200/100/999', - 'hover'=>'/image/generic/200/100/689', - ], - [ - 'image'=>'/image/generic/200/100/999', - 'hover'=>'/image/generic/200/100/679', - ], - [ - 'image'=>'/image/generic/200/100/999', - 'hover'=>'/image/generic/200/100/669', - ], - [ - 'image'=>'/image/generic/200/100/999', - 'hover'=>'/image/generic/200/100/659', - ], - [ - 'image'=>'/image/generic/200/100/999', - 'hover'=>'/image/generic/200/100/649', - ], - ], - 'clients_intro'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore', - 'language_id'=>1, - 'page_tabs'=>[ - [ - 'title'=>'Title 1', - 'image'=>'/image/generic/200/100/999', - 'text'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua', - - ], - [ - 'title'=>'Title 2', - 'image'=>'/image/generic/200/100/799', - 'text'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua', - - ], - [ - 'title'=>'Title 3', - 'image'=>'/image/generic/200/100/979', - 'text'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua', - ], - ], - 'site_slider'=>[ - [ - 'title'=>'Header
and Title', - 'text'=>'This is what you were looking for', - 'style'=>1, - 'image'=>'url(/image/generic/300/300/eee)', - 'button'=>['text'=>'Purchase Now','url'=>'#'], - ], - [ - 'title'=>'Header and Title', - 'text'=>'This is what you were looking for', - 'text2'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed est nunc, sagittis at consectetur id.', - 'style'=>2, - 'image'=>'url(/image/generic/400/400/ddd)', - 'button'=>['text'=>'Purchase Now','url'=>'#'], - ], - [ - 'title'=>'Header and Title', - 'text'=>'This is what you were looking for', - 'text2'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed est nunc, sagittis at consectetur id.', - 'style'=>2, - 'image'=>'url(/image/generic/500/500/eee)', - //'button'=>['text'=>'Purchase Now','url'=>'#'], - ], - ], - 'services'=>[ - ['title'=>'Title 1','text'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.','icon'=>'fa fa-location-arrow blue','image'=>NULL], - ['title'=>'Title 2','text'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.','icon'=>'fa fa-compress green','image'=>NULL], - ['title'=>'Title 3','text'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.','icon'=>'fa fa-check red','image'=>'/image/generic/200/100/999'], - ], - */ - 'email_logo'=>route('image',['width'=>150,'height'=>20,'color'=>'eee']), - 'site_address1' => 'Address line 1', - 'site_address2' => 'Address line 2', - 'site_description'=>'Example Site', - 'site_email' => 'nobody@example.com', - 'site_city' => 'City', - 'site_fax'=>'+0 1 2345 6789', - 'site_name' => 'MY OSB SITE', - 'site_state' => 'State', - 'site_phone'=>'+0 1 2345 6789', - 'site_postcode' => '12345', - 'site_tax'=>'12 123 123 123', - 'site_logo'=>route('image',['width'=>128,'height'=>32,'color'=>'eee']), - 'social'=>[ - ['name'=>'facebook','url'=>'http://www.facebook.com'], - ['name'=>'linkedin','url'=>'http://www.linkedin.com'], - ['name'=>'twitter','url'=>'http://www.twitter.com'], - ], - /* - 'steps'=>[ - ['title'=>'Title 1','description'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud'], - ['title'=>'Title 2','description'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud'], - ['title'=>'Title 3','description'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud'], - ], - 'testimonials'=>[ - [ - 'title'=>'Title 1', - 'name'=>'Bart Simpson', - 'quote'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud', - 'photo'=>'/image/generic/200/100/999', - ], - [ - 'title'=>'Title 2', - 'name'=>'Lisa Simpson', - 'quote'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud', - 'photo'=>'/image/generic/200/100/499', - ], - ], - */ - 'top_menu'=>[ - 'Home'=>['name'=>'Home','url'=>'/','children'=>[ - ['name'=>'Link 1','url'=>'#/l2', 'children'=>[]], - ['name'=>'Link 2','url'=>'#/l2', 'children'=>[]], - ]], - 'Option1'=>['name'=>'Option 1','url'=>'/o1','children'=>[]], - 'Option2'=>['name'=>'Option 2','url'=>'/o2','children'=>[ - ['name'=>'O2 Link 1','url'=>'#/o2l1', 'children'=>[]], - ['name'=>'O2 Link 1','url'=>'#/o2l2', 'children'=>[]], - ]], - ], - ]); - } + /* METHODS */ /** * Get a sample key value @@ -249,11 +111,8 @@ class SiteDetail extends Model * @return mixed * @throws \Exception */ - public function sample($key) + public static function sample($key) { - if (! $x=$this->_sampledata()->get($key)) - throw new \Exception('Key doesnt exist: '.$key); - - return $x; + return Arr::get(self::sampleData,$key); } } \ No newline at end of file diff --git a/app/Models/Tax.php b/app/Models/Tax.php index f34ad15..b135a92 100644 --- a/app/Models/Tax.php +++ b/app/Models/Tax.php @@ -6,10 +6,12 @@ use Illuminate\Database\Eloquent\Model; class Tax extends Model { - protected $table = 'ab_tax'; - const CREATED_AT = 'date_orig'; - const UPDATED_AT = 'date_last'; + public $timestamps = FALSE; - protected $dates = ['date_orig','date_last']; - public $dateFormat = 'U'; + /* RELATIONS */ + + public function country() + { + return $this->belongsTo(Country::class); + } } \ No newline at end of file diff --git a/database/migrations/2021_12_17_131958_cleanup_site.php b/database/migrations/2021_12_17_131958_cleanup_site.php new file mode 100644 index 0000000..405986b --- /dev/null +++ b/database/migrations/2021_12_17_131958_cleanup_site.php @@ -0,0 +1,67 @@ +dropColumn(['date_orig']); + }); + + DB::statement('ALTER TABLE ab_country RENAME TO countries'); + DB::statement('ALTER TABLE countries MODIFY id int(11) NOT NULL;'); + DB::statement('ALTER TABLE countries MODIFY name varchar(128) NOT NULL;'); + DB::statement('ALTER TABLE countries MODIFY notes text DEFAULT NULL;'); + + DB::statement('ALTER TABLE ab_currency RENAME TO currencies'); + DB::statement('ALTER TABLE currencies MODIFY id int(11) NOT NULL;'); + DB::statement('ALTER TABLE currencies MODIFY name varchar(128) NOT NULL;'); + DB::statement('ALTER TABLE currencies MODIFY notes text DEFAULT NULL;'); + DB::statement('ALTER TABLE currencies RENAME COLUMN convert_array TO rates;'); + + DB::statement('ALTER TABLE ab_language RENAME TO languages'); + + Schema::table('countries', function (Blueprint $table) { + $table->dropColumn(['description']); + + $table->foreign(['currency_id'])->references(['id'])->on('currencies'); + }); + + Schema::table('currencies', function (Blueprint $table) { + $table->dropForeign('fk_cur_cty'); + $table->dropIndex('fk_cur_cty_idx'); + $table->dropColumn(['country_id']); + }); + + DB::statement('ALTER TABLE ab_tax RENAME TO taxes'); + DB::statement('ALTER TABLE taxes MODIFY description text DEFAULT NULL;'); + DB::statement('ALTER TABLE taxes MODIFY id int(11) NOT NULL;'); + DB::statement('ALTER TABLE taxes MODIFY country_id int(11) NOT NULL;'); + Schema::table('taxes', function (Blueprint $table) { + $table->dropColumn(['date_orig','date_last','tax_id_collect','tax_id_name','tax_id_req','tax_id_exempt','tax_id_regex']); + $table->dropIndex('fk_tax_cty_idx'); + $table->dropForeign('fk_tax_cty'); + + $table->foreign(['country_id'])->references(['id'])->on('countries'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + abort(500,'Cant go back'); + } +} diff --git a/database/seeders/CountryTableSeeder.php b/database/seeders/CountryTableSeeder.php index 806294c..bc43eed 100644 --- a/database/seeders/CountryTableSeeder.php +++ b/database/seeders/CountryTableSeeder.php @@ -24,6 +24,6 @@ class CountryTableSeeder extends Seeder $oo = Currency::where('iso_code','AUD')->firstOrFail(); - $oo->countries()->save($o); + $oo->country()->save($o); } } \ No newline at end of file