Have one action where i am creating few models at the same time both are extends from ActiveRecord.
<?php class User extends ActiveRecord
{
}
class Balance Extends ActiveRecord
{
}
Controller class:
...
actionSignup(){
$model = new User();
$balance = new Balance();
$user->balance_id = ???;
$balance->user_id = $user->balance_id;
}
So till i do not save any models, i cant get id of this models! The best way to bound this models is generate some unique id in code and add specific column to database?
actionSignup(){
$balance = new Balance();
$balance>save();
$model = new User();
$user->balance_id = $balance->id;
$user->save();
$balance->user_id = $user->user_id;
$balance->save();
}
Related
I'm a new bit who is trying to build an app using Laravel 5.5, and the Eloquent model.
I have two classes: (1)
Customer
and (2)
VIPCustomer which extends Customer.
You may immediately tell VIPCustomer contains all attributes that a customer has, and other extra attributes.
Just to be clear, a customer may not be a VIP, and a VIP must be a customer; The customer may immediately opt-in to be a VIP the first time he shops.
Therefore, I am attempting to do something like this in the database:
Customer:
+------------------------+
|id|name|gender|join_date|
+------------------------+
VIPCustomer:
+----------------------------------+
|customer_id|valid_until|type|point|
+----------------------------------+
(customer_id is a foriegn key referencing Customer.id)
And accordingly, in the model php file:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Customer extends Model
{
}
.
namespace App;
use Illuminate\Database\Eloquent\Model;
class VIPCustomer extends Customer
{
public $incrementing = false;
}
And that's it? I saw there are others saying I should using polymorphic relationship but I don't understand what it means.
In addition, is it possible to do instantiate a new VIP Customer something like this?
$customer = new VIPCustomer;
$customer->name = 'Alice';
$customer->gender = 'F';
$customer->type = 'gold';
$customer->point = 0;
$customer->save();
On top of that, say when the VIP membership ends, is it possible to preserve that person as Customer? Because I'm afraid deleting that person will delete him from both Customer and VIPCustomer tables.
Thank you very much in advance.
Your current VIPCustomer class looks like a class that holds a VIP data, not a subject (a customer). Then so, I would rename it as VIPCustomerData here and make a new VIPCustomer to inherit Customer class instead.
class Customer extends Model
{
protected $table = 'customers';
}
Make sure you define the table name to avoid it being guessed by inheritance. Then tell VIPCustomer to has a relation to VIPCustomerData.
class VIPCustomer extends Customer
{
public function vipData()
{
return $this->hasOne(VIPCustomerData::class, 'customer_id', 'id');
}
}
Now, the problem is whenever you're going to retrieve VIP customers like VIPCustomer::get(), you'll get whole customers instead. So, applying global scope is needed.
class VIPCustomer extends Customer
{
protected static function boot()
{
parent::boot();
static::addGlobalScope('weareviptypeofcustomer', function ($q) {
$q->has('vipData'); // only customers with vip data
});
}
public function vipData()
{
return $this->hasOne(VIPCustomerData::class, 'customer_id', 'id');
}
}
To create a new Customer as VIP, of course 2 queries is needed to insert here. Example,
$vipCustomer = new VIPCustomer;
$vipCustomer->name = 'Alice';
$vipCustomer->gender = 'F';
$vipCustomer->save();
$vipCustomerData = new VIPCustomerData;
$vipCustomerData->type = 'gold';
$vipCustomerData->point = 0;
$vipCustomer->vipData()->save($vipCustomerData);
Example of updating point.
$vipCustomerData = $vipCustomer->vipData; // or $vipCustomer->vipData()->first();
$vipCustomerData->point = 10;
$vipCustomerData->save();
Example of removing VIP status from customer. Of course just delete VIPCustomerData from its table.
$vipCustomer->vipData()->delete();
However, it's better to maintain these subjects as one class if there is no special column to treat each subject differently.
class Customer extends Model
{
protected $table = 'customers';
protected $with = ['vipData']; // always eager load related 'vipData'
protected $appends = ['is_vip']; // append 'is_vip' accessor
public function vipData()
{
return $this->hasOne(static::class, 'customer_id', 'id');
}
public function getIsVipAttribute()
{
return (bool) $this->vipData;
}
}
$customers = Customer::all();
foreach($customers as $customer) {
if ($customer->is_vip) {
// is VIP
} else {
}
}
Laravel documentation suggests the following way to set up an eloquent model:
$user = user::with($conditions)->first();
What if I want to set up my eloquent model inside the model itself:
$user = new user();
$user->setup($conditions);
// class definition
class user extends Eloquent{
public function setup($conditions){
// load current object with table data
// something like
$this->where($conditions)->first();
// previous line output is dangling, is ok to assign it to $this variable?
}
}
If you're extending from Eloquent model, you may try the following approach. I assume you have a unique id column.
public function setup($conditions)
{
$model = self::with($conditions)->first();
if (! is_null($model)) {
$this->exists = true;
$this->forceFill(self::find($model->id)->toArray());
}
return $this;
}
Hope this solve your issue.
I am working on Yii2, however I have a model this model have some attributes, some are required on insert/create mode and some are required on update mode, let say mode = scenario, So I created a Form model with 2 scenarios insert and update, then I set validation rules for the attributes as the scenario, the question is: shall I define the scenarios in both models(Active Record and Form Model)?
Thank you in advance.
Scenarios should be defined in your model ..
and you should set the scenario youwant use in your related action
public function actionUpdate(){
....
$model->scenario = 'update';
...
ActiveRecord read from the database has the "update" scenario, while a new record has the "insert" scenario.
$modelA = User::model()->findByPk(1); // $model->scenario = 'update'
$modelB = new User(); // $model->scenario = 'insert'
$modelB->scenario = 'light'; // custom scenario
if ($modelB->validate()) { // will only apply rules of the "light" scenario
...............
..............
}
You can do so, in your model:
class YourModel extends \yii\db\ActiveRecord
{
const SCENARIO_CREATE = 'create';
const SCENARIO_UPDATE = 'update';
...
public function scenarios(){
$scenarios = parent::scenarios();
$scenarios[static::SCENARIO_CREATE] = ['field_1', 'field_2'];
$scenarios[static::SCENARIO_UPDATE] = ['field_1', 'field_3'];
return $scenarios;
}
...
}
In Your conttroller:
class YourController extends Controller {
...
public function actionCreate(){
$model = new YourModel()
$model->scenario = YourModel::SCENARIO_CREATE;
if($model->validate()){ // validate fields specifed in YourModel SCENARIO_CREATE
...
}
...
}
...
public function actionUpdate(){
$model = new YourModel()
$model->scenario = YourModel::SCENARIO_UPDATE;
if($model->validate()){ // validate fields specifed in YourModel SCENARIO_UPDATE
...
}
...
}
}
If my answer helpful, please put a tick))
I seem to be stumped on how to automatically save related models when creating a model instance in Laravel. Consider:
A User Model:
<?php
// file: User.php
class User extends Eloquent
{
public function role()
{
$this->hasOne('Role');
}
}
A Role Model:
<?php
// file: Role.php
class Role extends Eloquent
{
public function user()
{
$this->belongsTo('User');
}
}
Now lets say I want to create a new user and assign a it a role. Its quite easy to get the association to work if I set the role relationship after I save the user. For example, this works great:
$user = new User();
$user->name = 'Bobby';
$user->save();
$role = new Role();
$role->type = "Super Hero";
$user->role()->save($role);
However, if I want to push or cascade the save it fails to assign the foreignKey. I'd like to save() only once, and have the relationships save via cascade. For example, this doesn't work:
$user = new User();
$user->name = 'Bobby';
$role = new Role();
$role->type = "Super Hero";
$user->role = $role; // or $user->role()->save($role);
$user->save(); // push()?
This would be somewhat similar to how Doctrine 2 handles persisting. Is it possible to create both at the same time in Eloquent?
i used polimorphic relation in laravel but my problem is, how to pass relation_type dynamically (Example:When i want to create tickets for Organization pass Organization Model namespace or for Contact pass Contact Model namespace).
This is my model
class Ticket
public function relation(){
return $this->morphTo();
}
class Organization
public function tickets(){
return $this->morphMany('Ticket','relation');
}
class Contact
public function tickets(){
return $this->morphMany('Ticket','relation');
}
i don't now it is possible but i want a function that accept two param
public function ticketRelation($model, $Id){
$modelNamespace = $model::findById($id);
$ticket = new Ticket();
$ticket->save();
$modelNamespace->tickets()->save($ticket);
}
In this casse a $model param should be accept Organization or Contact to associate new ticket
And if i realize this i need only one route that accept a model and an Id to associate new ticket.How to pass an class like a param in this method ?
All you need to do to link a Ticket to either Organization or Contact is:
$organization = new Organization;
$organization->save();
$contact = new Contact();
$contact->save();
$organizationTicket = new Ticket;
$organizationTicket->relation()->associate($organization);
$organizationTicket->save();
$contactTicket = new Ticket;
$contactTicket ->relation()->associate($contact);
$contactTicket ->save();
Yes, it is possible to achieve what you want with your function.
Since PHP 5.3 it is possible to dynamically call class static methods on a variable containing class name, so if $model contains a valid namespaced class name you can just do:
public function ticketRelation($class, $id){
$model= $class::findOrFail($id);
$ticket = new Ticket();
$ticket->relation()->associate($model);
$ticket->save();
}