Rework Site and top level tables

This commit is contained in:
Deon George 2021-12-17 14:59:55 +11:00
parent b4e569ccc8
commit 99a62828f5
8 changed files with 192 additions and 282 deletions

View File

@ -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);
}
}

View File

@ -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);

View File

@ -6,6 +6,5 @@ use Illuminate\Database\Eloquent\Model;
class Language extends Model
{
protected $table = 'ab_language';
public $timestamps = FALSE;
}

View File

@ -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;
}
}

View File

@ -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 <br/><span class="carousel-title-normal">and Title</span>',
'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.<br/>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.<br/>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);
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,67 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CleanupSite extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('sites', function (Blueprint $table) {
$table->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');
}
}

View File

@ -24,6 +24,6 @@ class CountryTableSeeder extends Seeder
$oo = Currency::where('iso_code','AUD')->firstOrFail();
$oo->countries()->save($o);
$oo->country()->save($o);
}
}