Model store with different column than primaryKey - php

I have this Laravel/OctoberCMS Model to interface with my ExchangeModel.
It's a one sided relationship with my ExchangeModel.
Currently it stores in the Customer database table via ExchangeModel.id. But i'd like it to store as ExchangeModel.currencyISO, which is a 3 letter country code.
What do I need to setup in the relation to get laravel to store it via the other field I try to define via otherKey or key instead of the primaryKey(id)?
<?php namespace PhunTime\Client\Models;
use Model;
/**
* Customer Model
*/
class Customer extends Model {
/**
* #var string The database table used by the model.
*/
public $table = 'CUSTOMER';
public $primaryKey = 'customerNumber';
/**
* #var array Relations
*/
public $belongsTo = ['currency' => ['PhunTime\ExchangeRate\Models\ExchangeModel',
'key' => 'currencyISO',// EUR,USD,YEN
'otherKey' => 'currencyISO'
]];
}
Clarification of the structure:
- Customer
- id
- name
- currency(varchar(3)) <-- relation
- ExchangeModel
- id
- currencyISO
Currently the ExchangeModel.id gets stored in Customer.currency
I want ExchangeModel.currencyISO to be stored in Customer.currency
Customer.currency is already a varchar field suitable to accept it.
Currently if I specify type:relation in fields.yaml it stores it by ExchangeModel.id no matter what I specify how it should store it. use of otherKey, foreignKey, key, nothing helps changing octobers mind.
Currently i'm using a type: dropdown that i populate via getcurrencyOptions() but in my feeling this is a less than ideal situation.

Related

Can't set value for Non-relational column in pivot table with Laravel factory

hey everybody is it technically possible to set data in an extra column in the pivot table?
my database is like
products
sellers
id
id
title
name
brand_id
and...
prodduct_sellrs
id
product_id
seller_id
price
and I want to Seed my database with factory Faker data and here is my code in my seeder (I've already made the ProductFactory and.... )
Product::factory()
->foruser()
->hasCategories()
->hasTags()
->hassellers()
->forBrand()
->forAttributeSet()
->create();
but when I run it I get this error
General error: 1364 Field 'price' doesn't have a default value
which is truly right but anybody can help how I can define value for price in the pivot table?
You can use factory callbacks
Factory callbacks - Laravel
After create your Product, you can create data for your relational tabble
namespace Database\Factories;
use App\Models\Product;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class ProductFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Product::class;
/**
* Configure the model factory.
*
* #return $this
*/
public function configure()
{
return $this->afterCreating(function (Product $product) {
$product->sellers()->save(factory(App\ProductSeller::class)->make());
});
}
// ...
}
I realized my answer If anyone wanted to use
Product::factory()
->foruser()
->hasCategories()
->hasAttached(
Seller::factory()->count(10),
['price'=>423432432]
)
and it solved, here it is

Laravel polymorphic with custom foreign key

I have problem with custom shipmentable_type. My structure looks like this:
transfers:
id - integer
name - string
shipment:
id - integer
name - string
shipmentale:
shipment_id - integer
shipmentable_id - integer
shipmentabl_type - enum ( transfer, order, complaint, internet )
Now I have in my Transfer model realtion like this:
public function shipments()
{
return $this->morphToMany(Shipment::class, 'shipmentable');
}
The problem is, that to table shipmentable, to column shipmentable_type is going sth like this now: App/Models/Transfer, but I would like to force to be there 'transfer' in this case. Is it possible?
From the docs
By default, Laravel will use the fully qualified class name to store the type of the related model. However, you may wish to decouple your database from your application's internal structure. In that case, you may define a relationship "morph map" to instruct Eloquent to use a custom name for each model instead of the class name:
use Illuminate\Database\Eloquent\Relations\Relation;
Relation::morphMap([
'transfer' => 'App/Models/Transfer'
]);
You may register the morphMap in the boot function of your AppServiceProvider or create a separate service provider if you wish.
To set a value other than the model's fully qualified name in shipmentable_type, there is the Relation::morphMap() function.
Relation::morphMap([
'transfer' => 'App/Models/Transfer'
]);
This should be set in the AppServiceProvider or similar.
I've had this issue but unfortunately I had multiple models pointing at transfer with multiple locations. You can resolve them dynamically on your model:
class Transfers extends Model
{
/**
* Declare the class to get connect polymorphic relationships.
*
* #var string|null
*/
protected $morphClass = null;
/**
* Get the associated morph class.
*
* #return string|null
*/
public function getMorphClass()
{
return $this->morphClass ?: static::class;
}
public function shipments()
{
$this->morphClass = 'transfer';
return $this->morphToMany(Shipment::class, 'shipmentable');
}
// ...
}

Laravel factory seeding error

I have four tables Book, Author, User, Rating where Author and User table have many to many relationship with Book table, and Rating table has a foreign key with book and user table. 5 Authors and users are created, now I want to create book and rating table together where user_id and book_id will be same for book and rating table! I'm trying this way but this give me error in Rating factory! May be variable scope! How to solve this?
'user_id' => $userRandom,
class BooksTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
factory(App\Book::class, 2)->create()->each(function ($book) {
$author = App\Author::all();
$user = App\User::all();
$userRandom = $user->random();
factory(App\Rating::class)->create([
'book_id' => $book->id,
'user_id' => $userRandom,
]);
$book->authors()->save($author->random());
$book->users()->save($userRandom);
});
}
}
1) Make sure that:
'user_id' => $userRandom // keeps exact id.
Otherwise You'll need to pass it like:
'user_id' => $userRandom->id
2) Make sure that You've defined $fillable attribute of Rating model.
You cannot just do create and pass some array (assoc) if You've not defined field names in $fillable.
You may also use the create method to save a new model in a single line.
The inserted model instance will be returned to you from the method.
However, before doing so, you will need to specify either a fillable or guarded attribute on the model, as all Eloquent models protect against mass-assignment by default.
So, to get started, you should define which model attributes you want to make mass assignable.
You may do this using the $fillable property on the model.
Read about Mass Assignment https://laravel.com/docs/5.4/eloquent

How to retrieve information from the database without createCommand?

I have following code in my controller:
$listproduct=Yii::app()->db->createCommand()
->select('product')
->from('product_form')
->where('product_name=:product_name and type=:type', array(':product_name'=>'HP', ':type'=>$gettype ))
->queryRow();
$gettype is responsible for retrieving types of the product. (e.g if the name of the product is HP and type($gettype) is PC, it will display the HP product where type is PC). I could not realize this function without createCommand. How can I do it?
You could use CActiveRecord features
assuming you have a CActiveRecode model class named
class ProductForm extends CActiveRecord
{
/**
* #return string the associated database table name
*/
public function tableName()
{
.......
you could use
For obtain all the models you can use findAllByAttributes()
$listProduct= ProductForm::model()->
findAllByAttributes(array('product_name'=>'HP', 'type' =>$gettype ));
for obtain a single model you can use findByAttributes()
you can take a look at http://www.yiiframework.com/doc/guide/1.1/en/database.ar

how does laravel finds the connection between models and its table in database

in my model i have
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Page extends Model
{
//
}
in my controller i can say Page:all() and get all the rows from pages table
but i dont see any connection between Page model and pages table in the database
does it just guess table name based on the model name (lower case with extra s at the end ) or it's mentioned somewhere else ?
As you can see in the docs, this is the magic of Laravel :-)
https://laravel.com/docs/5.2/eloquent#defining-models (see Table Names)
If you want, you can set another name manually by user the following
protected $table = 'my_table_name';
And to go a bit further, this is how Laravel gets the table name in the base Model you can found at /vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
/**
* Get the table associated with the model.
*
* #return string
*/
public function getTable()
{
if (isset($this->table)) {
return $this->table;
}
return str_replace('\\', '', Str::snake(Str::plural(class_basename($this))));
}
You can specify the table by putting the below code into your model
protected $table = 'your table name';
Otherwise, it takes a table name as a plural form of the model.
For example, if your model name Product then by default it connects the table named 'products'.
So if your table name is not different then no need to configure it. It's will connect automatically
By default, it takes the "snake case" of the class name used in the model. Also, add a final "s" to make the plural.
You can also define a custom name by adding the variable
protected $table = 'my_table_name';
in the model class.
For instance:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'my_flights';
}

Categories