Laravel - Eloquent overwriting a custom timestamp... WHY? - mysql

I am making an inventory management system.
When a product is out of stock, I make an entry in a table and note the "oos_at" field with the date/time.
later, when it is back in stock, i find that entry and update the "restocked_at" timestamp field.
However, when I do the second action, my "oos_at" field is overwritten with the timestamp of the query ('updated_at') field...
I had to keep track of this "oos_at" field on another entity so it wouldn't get overwritten and then use that field to update the "oos_at" field a second time when updating that table...
Below is my code....
class Pusher extends Model {
/**
*
*
* #param Carbon $oos_at
* #return bool
*/
public function setAsOutOfStock(Carbon $oos_at)
{
Log::info([
'FILE' => get_class($this),
'method' => 'setAsOutOfStock',
'pusher' => $this->id,
'param:oos_at' => $oos_at->toDateTimeString(),
]);
$this->pusherOutOfStocks()->create([
'location_id' => $this->location_id,
'product_id' => $this->product_id,
'oos_at' => $oos_at->toDateTimeString(),
]);
$this->oos = true;
$this->oos_at = $oos_at;
return $this->save();
}
/**
* Clear the PusherOutOfStocks attached to $this Pusher
* (This Pusher has been restocked!)
*
* #param Carbon $time
* #return bool
*/
public function setAsInStock(Carbon $time)
{
Log::info([
'FILE' => get_class($this),
'method' => 'setAsInStock',
'pusher' => $this->id,
'param:time' => $time->toDateTimeString(),
]);
$this->pusherOutOfStocks()->where('restocked_at', null)
->update(['restocked_at' => $time->toDateTimeString()]);
$this->oos = false;
$this->oos_at = null;
return $this->save();
}
}
When I die and dump the PusherOutOfStocks BEFORE the pusher is restocked, then the "oos_at" is set appropriately.
Illuminate\Database\Eloquent\Collection {#340
#items: array:1 [
0 => Newave\Engineering\PusherOutOfStock {#343
#fillable: array:5 [
0 => "pusher_id"
1 => "location_id"
2 => "product_id"
3 => "oos_at"
4 => "restocked_at"
]
#dates: array:2 [
0 => "oos_at"
1 => "restocked_at"
]
#connection: null
#table: null
#primaryKey: "id"
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:9 [
"id" => 246
"pusher_id" => 216
"location_id" => 634
"product_id" => 378
"oos_at" => "2016-03-11 03:00:00"
"restocked_at" => null
"created_at" => "2016-03-11 12:12:01"
"updated_at" => "2016-03-11 12:12:01"
"deleted_at" => null
]
#original: array:9 [
"id" => 246
"pusher_id" => 216
"location_id" => 634
"product_id" => 378
"oos_at" => "2016-03-11 03:00:00"
"restocked_at" => null
"created_at" => "2016-03-11 12:12:01"
"updated_at" => "2016-03-11 12:12:01"
"deleted_at" => null
]
#relations: []
#hidden: []
#visible: []
#appends: []
#guarded: array:1 [
0 => "*"
]
#dateFormat: null
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
+wasRecentlyCreated: false
#forceDeleting: false
}
]
}
When I die and dump the PusherOutOfStocks AFTER the pusher is restocked, then the "oos_at" is the same as "updated_at"
Illuminate\Database\Eloquent\Collection {#408
#items: array:1 [
0 => Newave\Engineering\PusherOutOfStock {#775
#fillable: array:5 [
0 => "pusher_id"
1 => "location_id"
2 => "product_id"
3 => "oos_at"
4 => "restocked_at"
]
#dates: array:2 [
0 => "oos_at"
1 => "restocked_at"
]
#connection: null
#table: null
#primaryKey: "id"
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:9 [
"id" => 244
"pusher_id" => 214
"location_id" => 626
"product_id" => 374
"oos_at" => "2016-03-11 12:10:23"
"restocked_at" => "2016-03-11 04:00:00"
"created_at" => "2016-03-11 12:10:22"
"updated_at" => "2016-03-11 12:10:23"
"deleted_at" => null
]
#original: array:9 [
"id" => 244
"pusher_id" => 214
"location_id" => 626
"product_id" => 374
"oos_at" => "2016-03-11 12:10:23"
"restocked_at" => "2016-03-11 04:00:00"
"created_at" => "2016-03-11 12:10:22"
"updated_at" => "2016-03-11 12:10:23"
"deleted_at" => null
]
#relations: []
#hidden: []
#visible: []
#appends: []
#guarded: array:1 [
0 => "*"
]
#dateFormat: null
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
+wasRecentlyCreated: false
#forceDeleting: false
}
]
}
I have even used DB::getQueryLog() and saw NOWHERE that 'oos_at' was being explicitly set/updated....
Nowhere else in my code is this table modified...
Does anyone understand what is happening here????
Thank you!!
=============
Extra Code Snippets
Table Migration::
Schema::create('pusher_out_of_stocks', function (Blueprint $table) {
$table->increments('id');
$table->integer('pusher_id');
$table->integer('location_id');
$table->integer('product_id');
$table->timestamp('oos_at');
$table->timestamp('restocked_at')->nullable();
$table->timestamps();
$table->softDeletes();
});
PusherOutOfStock Class
class PusherOutOfStock extends Model
{
use SoftDeletes;
protected $fillable = [
'pusher_id',
'location_id',
'product_id',
'oos_at',
'restocked_at',
];
protected $dates = [
'oos_at',
'restocked_at'
];
/**
* A PusherOutOfStock belongsTo a Product
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function product()
{
return $this->belongsTo(Product::class);
}
/**
* A PusherOutOfStock belongsTo a Pusher
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function pusher()
{
return $this->belongsTo(Pusher::class);
}
/**
* A PusherOutOfStock belongsTo a Location
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function location()
{
return $this->belongsTo(Location::class);
}
}
Below is the sequence the code goes through to hit that update method
First, it hits my InventoryController in my API namespace
public function upload(Request $request)
{
$data = $request->all();
$header = $this->getHeader($data);
$body = $this->getBody($data);
$reader = $this->getReaderFromHeader($header);
if ( ! $this->guardAgainstNoReader($reader))
return (new Response("Reader with mac-address: ". $header['reader_mac'] . " does not exist.", 409));
$result = $this->inventoryRepository->uploadPusherData($reader, $header, $body);
return $result;
}
Then it sends the request to the InventoryRepository
public function uploadPusherData(Reader $reader, $header, $body)
{
foreach ($body as $pusherData)
{
$result[] = $this->processPusherData($pusher, $header['timestamp'], $pusherData);
}
return $result;
}
Then, inside the repository, it processes one line at a time (in my test, there is only one line)
private function processPusherData(Pusher $pusher, $timestamp, $pusherData)
{
$latestInventory = $pusher->latestInventory;
if (! $latestInventory)
return $this->updatePusher($pusher, $timestamp, $pusherData);
if ($latestInventory->tags_blocked == $pusherData['data_TAGSBLKED'])
return $this->noChangeRecorded($pusher, $latestInventory, $timestamp);
return $this->updatePusher($pusher, $timestamp, $pusherData);
}
Then the pusher is updated...
public function updatePusher($pusher, $timestamp, $pusherData)
{
// See if there are any existing already
$prevInv = $pusher->latestInventory;
// Create the new data
$inventory = Inventory::create([
'pusher_id' => $pusher->id,
'product_id' => $pusher->product_id,
'reader_id' => $pusher->reader->id,
'tags_blocked' => $pusherData['data_TAGSBLKED'],
'paddle_exposed'=> $pusherData['paddle_exposed'],
'created_at' => Carbon::createFromTimestamp($timestamp)
->toDateTimeString(),
]);
if ( !$prevInv || $prevInv->id == $inventory->id )
{
return "first-data" . $timestamp;
}
return $this->checkForEvents($inventory, $prevInv);
}
We check if any events should be triggered... In this case, previous inventory had 9 items in stock... now there are 0.
private function checkForEvents(Inventory $currentInventory, Inventory $previousInventory)
{
if ( ! $previousInventory->oos && $currentInventory->oos && $previousInventory->pusher->oos_notified == 0)
{
$currentInventory->pusher->oos_notified = true;
$currentInventory->pusher->save();
return Event::fire(new InventoryOutOfStock($currentInventory));
}
if ( ( $previousInventory->oos || $previousInventory->status == "RESTOCK" )
&& $currentInventory->tags_blocked > 2 )
{
return Event::fire(new PusherWasRestocked($currentInventory));
}
if ( $currentInventory->status == "RESTOCK" && $previousInventory->pusher->low_stock_notified == 0)
{
$currentInventory->pusher->low_stock_notified = true;
$currentInventory->pusher->save();
return Event::fire(new LowStockAlert($currentInventory));
}
return "no-events";
}
This then fires the event InventoryOutOfStock
That triggers 3 events... 2 are related to notifications being sent etc..
'App\Events\InventoryOutOfStock' => [
'App\Listeners\InventoryOutOfStockUpdater',
'App\Listeners\EmailInventoryOutOfStockNotification',
'App\Listeners\SMSInventoryOutOfStockNotification',
// 'App\Listeners\OutOfStocksUpdater',
],
Which leads us to ...
public function handle(InventoryOutOfStock $event)
{
$pusher = $event->pusher;
$inventory = $event->inventory;
$product = $pusher->product;
$oos = $pusher->setAsOutOfStock($inventory->created_at);
$locationPushers = $product->getPushersByLocation($pusher->location);
$isInStock = false;
foreach ($locationPushers as $pusher)
if ($pusher->oos == 0)
$isInStock = true;
if (! $isInStock)
$product->productOutOfStocks()->create([
'location_id' => $pusher->location_id,
'oos_at' => $event->inventory->created_at,
]);
}

I think that you do not have to use the timestamp method to create your fields, but you should use the dateTime method:
Schema::create('pusher_out_of_stocks', function (Blueprint $table) {
$table->increments('id');
$table->integer('pusher_id');
$table->integer('location_id');
$table->integer('product_id');
$table->dateTime('oos_at');
$table->dateTime('restocked_at')->nullable();
$table->timestamps();
$table->softDeletes();
});
This should work :)
Hope it helped!

Related

Looping Array of Json to Database Laravel?

I have Json Data like this :
$data = '[
{
"OrderId": "1038806370",
"qtty": "1",
"Item": "Strawberry 250 gr",
"SKU": "20091"
},
{
"OrderId": "1038806370",
"qtty": "2",
"Item": "Strawberry 130 gr",
"SKU": "20092"
},
{
"OrderId": "1038806370",
"qtty": "1",
"Item": "Strawberry 130 gr",
"SKU": "20092"
}
]';
and I want to Save in my database MySql using PHP Laravel,...
I Want To save data from json to my table, there are table Order values [orderID,...] and OrderDetail values [orderID, SKU, Qty]
This is my code in controller
$order = json_decode($data, true);
foreach ($order as $ord) {
$check = Order::where('orderid', $ord['OrderId'])->get();
if (count($data) > 0) {
OrderDetail::firstOrCreate([
'order_id' => $ord['OrderId'],
'sku_id' => $ord['SKU'],
'qty' => $ord['qtty']
]);
} else {
Order::create([
'orderid'=> $ord['OrderId'],
]);
OrderDetail::firstOrCreate([
'order_id' => $ord['OrderId'],
'sku_id' => $ord['SKU'],
'qty' => $ord['qtty']
]);
}
}
but i dont get what i want, I get QTY of SKU 20091 is 2 but actual json data is 3
I'm not sure why you're counting the $data instead of $check variable. You don't really need the $check variable either though. I'll rewrite your code below.
$order = json_decode($data, true);
foreach ($order as $ord) {
// use EXIST query to check if Order exists or not.
if (Order::where('orderid', $ord['OrderId'])->exists())
OrderDetail::firstOrCreate([
'order_id' => $ord['OrderId'],
'sku_id' => $ord['SKU'],
'qty' => $ord['qtty']
]);
} else {
Order::create([
'orderid'=> $ord['OrderId'],
]);
OrderDetail::firstOrCreate([
'order_id' => $ord['OrderId'],
'sku_id' => $ord['SKU'],
'qty' => $ord['qtty']
]);
}
}
But your if/else could also be removed by using the firstOrCreate() method.
$orders = json_decode($data, true);
foreach ($orders as $order) {
// Get Order Model with orderid = $order['OrderId'] or create it if it doesn't exist
$model = Order::firstOrCreate([
'orderid'=> $order['OrderId']
]);
// Get OrderDetail with provided SKU, qtty and orderid or create it if it doesn't exist.
OrderDetail::firstOrCreate([
'order_id' => $model->orderid
'sku_id' => $order['SKU'],
'qty' => $order['qtty']
]);
}
You could also do it inline.
$orders = json_decode($data, true);
foreach ($orders as $order) {
OrderDetail::firstOrCreate([
'order_id' => Order::firstOrCreate(['orderid'=> $order['OrderId']])->orderid,
'sku_id' => $order['SKU'],
'qty' => $order['qtty'],
]);
}

Kartik-Widget GridView Filter TYPEAHEAD inactive

Following code throws out no error,but it's completely inactive, respectively redundant. JQuery is filtering nothing! Any ideas, how to fix this?
Here is code:
[
'attribute' => 'name',
'label' => 'Land',
'value' => function($model) {
if ($model->name) {
return $model->name;
} else {
return NULL;
}
},
'filterType' => GridView::FILTER_TYPEAHEAD,
'filterWidgetOptions' => [
'pluginOptions' => ['highlight' => true],
//'dataset' => [['local' => array_values(\app\models\Country::find()->orderBy('name')->asArray()->one())]
'dataset' => [['local' => array_values(ArrayHelper::map(\app\models\Country::find()->all(), 'id', 'name'))]
]],
'filterInputOptions' => ['placeholder' => 'JQuery will filter...'],
'format' => 'raw'
],
Here is var_dump of
$ausgabe_ = array(array_values(ArrayHelper::map(\app\models\Country::find()->all(), 'id', 'name')));
E:\xampp\htdocs\Yii-WSL\views\country\index.php:145:
array (size=1)
0 =>
array (size=25)
0 => string 'Arabische Emirate' (length=17)
1 => string 'Algerien' (length=8)
2 => string 'Australia' (length=9)
3 => string 'Belgien' (length=7)
4 => string 'Brasilien' (length=9)
5 => string 'Canada' (length=6)
6 => string 'Schweiz' (length=7)
7 => string 'China' (length=5)
8 => string 'Zypern' (length=6)
9 => string 'Germany' (length=7)
10 => string 'Westsahara' (length=10)
11 => string 'France' (length=6)
12 => string 'United Kingdom' (length=14)
13 => string 'Ungarn' (length=6)
14 => string 'India' (length=5)
15 => string 'Laos' (length=4)
16 => string 'Russia' (length=6)
17 => string 'Sudan' (length=5)
18 => string 'Turkmenistan' (length=12)
19 => string 'Ukraine' (length=7)
20 => string 'Uganda' (length=6)
21 => string 'United States' (length=13)
22 => string 'Vatikanstadt' (length=12)
23 => string 'Vietnam' (length=7)
24 => string 'Südafrika' (length=10)
Any further ideas,how to fix this?
P.S.: If I try like this.....:
'dataset' => [
['local' => array_values([ArrayHelper::map(\app\models\Country::find()->orderBy('name')->asArray()->all(), 'id', 'name ')])],
]
....result of
$ausgabe_ = array(array_values(ArrayHelper::map(Country::find()->orderBy('name')->asArray()->all(), 'id', 'name ')));
var_dump($ausgabe_);
is like this:
E:\xampp\htdocs\Yii-WSL\views\country\index.php:146:
array (size=1)
0 =>
array (size=25)
0 => null
1 => null
2 => null
3 => null
4 => null
5 => null
6 => null
7 => null
8 => null
9 => null
10 => null
11 => null
12 => null
13 => null
14 => null
15 => null
16 => null
17 => null
18 => null
19 => null
20 => null
21 => null
22 => null
23 => null
24 => null
Nothing helps to fix this problem. Further ideas?
Worth to note the array must be with integer type indexes and there cannot be missing numbers (indexes) (for example, 0; 1; 2; 3 is fine but 0; 1; 3; 4 is not because index 2 is missing).
The only valid structure (as example):
array(4) {
[0]=>
string(5) "Alpha"
[1]=>
string(4) "Beta"
[2]=>
string(5) "Gamma"
[3]=>
string(5) "Delta"
}
Your array is not valid:
The first (and only) element is 0 that contains other array. It cannot be like that;
That larger array has mixed indexes (read requirement in the first paragraph);
null values are not accepted.
What might solve your problem is if you use array_values:
'dataset' => [
['local' => array_values([ArrayHelper::map(\app\models\Country::find()->orderBy('name')->asArray()->all(), 'id', 'name ')])],
],

Joining multiple tables to get an collection of stock items

I'm currently trying to join 5 tables to retrieve a list of ordered items. Is it possible to have all the items together rather than having multiple collections of 'ordered_packs' with a different ItemID?
My code
if(!\App\OrderedPack::where('orderID', '=', $orderID)->get()->isEmpty()) {
$packs = \App\OrderedPack::where('ordered_packs.orderID', '=', $orderID)
->join('packs', 'ordered_packs.packID', '=', 'packs.packID')
->join('pack_items', 'packs.packID', '=', 'pack_items.packID')
->join('items', 'pack_items.itemID', '=', 'items.itemID')->get();
my returned result
Collection {#288 ▼
#items: array:2 [▼
0 => OrderedPack {#289 ▼
#primaryKey: "ordered_packID"
#table: "ordered_packs"
#connection: null
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:30 [▼
"ordered_packID" => 1
"orderID" => 80
"packID" => 7
"pack_quantity" => 12
"created_at" => "2016-02-11 14:20:29"
"updated_at" => "2016-03-08 16:21:02"
"pack_name" => "niceee"
"pack_description" => ""
"pack_itemID" => 5
"itemID" => 9
"item_code" => "INT T-C 12/15"
"companyID" => 1
"item_name" => "International Terms and Conditions"
"initial_level" => 5000
"current_level" => 4000
"item_typeID" => 6
"productID" => 1
"image_location" => "9.pdf"
"box_total" => 100
"offsite_level" => 1000
"locationID" => 1
"language" => "English"
"download_url" => ""
"archived" => 0
"low_stock_level" => 1000
"change_description" => ""
"old_itemID" => 0
"pdf_only" => 0
"total_stock" => 5000
"groupID" => 2
]
#original: array:30 [▶]
#relations: []
#hidden: []
#visible: []
#appends: []
#fillable: []
#guarded: array:1 [▶]
#dates: []
#dateFormat: null
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
+wasRecentlyCreated: false
}
1 => OrderedPack {#290 ▼
#primaryKey: "ordered_packID"
#table: "ordered_packs"
#connection: null
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:30 [▼
"ordered_packID" => 1
"orderID" => 80
"packID" => 7
"pack_quantity" => 12
"created_at" => "2016-02-11 14:18:35"
"updated_at" => "2016-03-08 16:21:02"
"pack_name" => "niceee"
"pack_description" => ""
"pack_itemID" => 6
"itemID" => 7
"item_code" => "GW CHO INT BRO 12/15"
"companyID" => 1
"item_name" => "GW Choice International Brochure (Including Details Guide) 12/15"
"initial_level" => 5000
"current_level" => 234
"item_typeID" => 1
"productID" => 2
"image_location" => "7.pdf"
"box_total" => 100
"offsite_level" => 2304
"locationID" => 1
"language" => "English"
"download_url" => ""
"archived" => 0
"low_stock_level" => 1000
"change_description" => ""
"old_itemID" => 0
"pdf_only" => 0
"total_stock" => 2538
"groupID" => 2
]
I have an orderedpack instance for every item in a pack. I would like one ordered pack instance that contains multiple items.
The tables
order->ordered_packs->packs->pack_items->items
In one query is not possible to take advantage of Laravel, but you could take advantage of eager loading:
$packs = \App\OrderedPack::where('ordered_packs.orderID', '=', $orderID)
->with('packs.pack_items.items')
->get();
Assuming your relationships are setup correctly

How to join three tables and get value in grid view

I have three tables :
contacts hasMany groups
contact_groups hasMany contacts
contact_contact_groups
columns in table contact
contact_id | contact_name
columns in table contact_groups
group_id | group_name
columns in table contact_contact_groups
contact_contact_group_id | contact_id | group_id
MODEL
contacs model
public function getContactContactGroups()
{
return $this->hasMany(ContactContactGroups::className(),
['contact_id' => 'contact_id']);
}
contact_groups model
public function getContactContactGroups()
{
return $this->hasMany(ContactContactGroups::className(),
['group_id' => 'group_id']);
}
contact_contact_groups model
public function getGroup()
{
return $this->hasOne(ContactGroups::className(), ['group_id' => 'group_id']);
}
public function getContact()
{
return $this->hasOne(Contacts::className(), ['contact_id' => 'contact_id']);
}
I want to display grid like this :
-----------------------------
Contact Name | Group Name
-----------------------------
Me | Uncategorized
Mother | Family
Jhon | Business
VIEW
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'tableOptions' =>['class' => 'table table-striped table-bordered'],
'columns' => [
[
'attribute' => 'contact_name',
'value' => 'contact_name',
],
[
'attribute' => 'contactContactGroups.group_id',
'value' => 'contactContactGroups.group.group_name',
'filter' => Html::activeDropDownList($searchModel, 'group_id', ArrayHelper::map(ContactGroups::find()->where(['group_status'=>'ACTIVE'])->asArray()->all(), 'group_id', 'group_name'),['class'=>'form-control','prompt' => 'Select Group']),
],
],]);
?>
ContactsController
public function actionIndex() {
$this->unsetThisButton(array(4,5));
$searchModel = new ContactsSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
But it showing (not set) not a group_name .
A simple way is based on adding a getter in your model eg: for contact_contact_groups model
you have a relation
public function getGroup()
{
return $this->hasOne(ContactGroups::className(), ['group_id' => 'group_id']);
}
use a getter for group_name
public function getGroup_group_name() {
return $this->group->group_name;
}
and in grid view in the attribute
[
'attribute' => 'group_group_name',
'filter' => Html::activeDropDownList($searchModel, 'group_id', ArrayHelper::map(ContactGroups::find()->where(['group_status'=>'ACTIVE'])->asArray()->all(), 'group_id', 'group_name'),['class'=>'form-control','prompt' => 'Select Group']),
],
do the same for the relation and field
I Found simple stuff like this :)
GRID (VIEW)
[
'attribute' => 'contactContactGroups.group_id',
'value'=>function ($data) {
$d = array();
foreach ($data->contactContactGroups as $k=>$m)
{
$d[] = ContactContactGroups::get_group_name_by_id($m->group_id);
}
return implode($d, ', ');
},
'filter' => Html::activeDropDownList($searchModel, 'group_id', ArrayHelper::map(ContactGroups::find()->where(['group_status'=>'ACTIVE'])->asArray()->all(), 'group_id', 'group_name'),['class'=>'form-control','prompt' => 'Select Group']),
],
models/ContactContactGroups.php Model
I create function get_group_name_by_id($id)
public static function get_group_name_by_id($id){
$model = ContactGroups::find()->where(["group_id" => $id])->one();
if(!empty($model)){
return $model->group_name;
}
return null;
}
so the result is :
Contact | Category
-------------------------------
Me | Business, Family
Erick | Business, Office
Jhon | Office
Thank's #scaisEdge, you give me some clue ;)

Foreign key relationship methods deferred and never created in RDBO

I'm playing with RoseDB::Object on the employees test dataset, and for some reason, I can't get my foreign key relationships ('department' and 'employee') to work on the DeptEmp object. (Class structure below).
When I try $e->dept_emp->[0]->department, I get:
Can't locate object method "department" via package "My::FakeEmployees::DeptEmp"
Methods for the following relationships and foreign keys were deferred and
then never actually created in the class My::FakeEmployees::DeptEmp.
TYPE NAME
---- ----
Foreign Key department
Foreign Key employee
I'm sure I have something set up wrong in my class structure, but what?
CLASS STRUCTURE (some classes omitted for clarity):
I created the various objects using the instructions in the RDBO tutorial:
package My::FakeEmployees::Employee;
use strict;
use base qw(My::FakeEmployees::DB::Object);
__PACKAGE__->meta->setup(
table => 'employees',
columns => [
emp_no => { type => 'serial', not_null => 1 },
birth_date => { type => 'date', not_null => 1 },
first_name => { type => 'varchar', length => 14, not_null => 1 },
last_name => { type => 'varchar', length => 16, not_null => 1 },
gender => { type => 'enum', check_in => [ 'M', 'F' ], not_null => 1 },
hire_date => { type => 'date', not_null => 1 },
],
primary_key_columns => ['emp_no'],
'relationships' => [
'departments' => {
'type' => 'many to many',
'map_class' => 'My::FakeEmployees::DeptEmp',
},
'dept_emp' => {
'type' => 'one to many',
'class' => 'My::FakeEmployees::DeptEmp',
'column_map' => { 'emp_no' => 'emp_no' },
},
'dept_manager' => {
'type' => 'one to many',
'class' => 'My::FakeEmployees::DeptManager',
'column_map' => { 'emp_no' => 'emp_no' },
},
'salaries' => {
'type' => 'one to many',
'class' => 'My::FakeEmployees::Salary',
'column_map' => { 'emp_no' => 'emp_no' },
},
'titles' => {
'type' => 'one to many',
'class' => 'My::FakeEmployees::Title',
'column_map' => { 'emp_no' => 'emp_no' },
},
],
);
__PACKAGE__->meta->make_manager_class('employees');
1;
package My::FakeEmployees::DeptEmp;
use strict;
use base qw(My::FakeEmployees::DB::Object);
__PACKAGE__->meta->setup(
table => 'dept_emp',
columns => [
dept_no => { type => 'character', not_null => 1 },
emp_no => { type => 'integer', not_null => 1 },
from_date => { type => 'date' },
to_date => { type => 'date' },
],
primary_key_columns => [ 'emp_no', 'dept_no' ],
foreign_keys => [
department => {
class => 'My::FakeEmployees::Departments',
key_columns => { dept_no => 'dept_no' },
},
employee => {
class => 'My::FakeEmployees::Employees',
key_columns => { emp_no => 'emp_no' },
},
],
);
__PACKAGE__->meta->make_manager_class('dept_emp');
1;
package My::FakeEmployees::Department;
use strict;
use base qw(My::FakeEmployees::DB::Object);
__PACKAGE__->meta->setup(
table => 'departments',
columns => [
dept_no => { type => 'character', length => 4, not_null => 1 },
dept_name => { type => 'varchar', length => 40, not_null => 1 },
],
primary_key_columns => ['dept_no'],
unique_key => ['dept_name'],
'relationships' => [
'employees' => {
'type' => 'many to many',
'map_class' => 'My::FakeEmployees::DeptEmp',
},
],
);
__PACKAGE__->meta->make_manager_class('departments');
1;
Your foreign key has a typo:
foreign_keys => [
department => {
class => 'My::FakeEmployees::Departments',
That should be 'Department', not 'Departments'
It turned out to be a mistake in my code. These lines in DeptEmp.pm:
foreign_keys => [
department => {
class => 'My::FakeEmployees::Departments',
key_columns => { dept_no => 'dept_no' },
},
employee => {
class => 'My::FakeEmployees::Employees',
key_columns => { emp_no => 'emp_no' },
},
],
Have incorrect class names. It should be My::FakeEmployees::Employee and My::FakeEmployees::Department. Singular, not plural.