Yii2 - How to user multiple table (model) in a single form - yii2

I need to use multiple table in a single form, on form submitted the data will save in multiple tables in the data base, also wants to perform validation and update.

I suggested snippet of code, at beginning of controller class define
private $_rel = null;
controller action ,
public function actionSaveUser(){
if (!empty($_POST['Contact'])){
$model = new Contact;
$model->attributes = $_POST['Contact'];
if ($model->save()){
$this->_rel = new Address;
$this->_rel->attributes = $_POST['Contact'];
if ($this->_rel->save()){
$this->render('view_name');
} else{
throw new CHttpException(404, 'Something went wrong message..');
}
}
}
}
I hope this code help you.

Related

Save data in 2 different tables with laravel

how can i save a record in 2 different tables.
I have my article model and my article controller in this way. My second table is called History
I hope you can help me, thank you very much
my article model:
protected $fillable =[
'idcategoria','codigo','nombre','precio_proveedor','precio_venta','iva','ieps','stock','stock1','descripcion','condicion'
];
public function categoria(){
return $this->belongsTo('App\Categoria');
}
my article controller, store method:
protected static function boot()
{
parent::boot();
// this triggers everytime an Article model is saved
static::saved(dd($articulo) { dd($article);
$historial = new Historial();
$historial->nombre = $articulo->nombre;
$historial->precio_proveedor = $articulo->precio_proveedor;
$historial->stock = $articulo->stock;
$historial->save();
});
}
In my history table I only need to save nombre, precio_proveedor,
stock
You can use observers for this. Add this in your Article model:
protected static function boot()
{
parent::boot();
// this triggers everytime an Article model is saved
static::saved(function (Article $article) {
$history = new History();
$history->nombre = $article->nombre;
$history->precio_proveedor = $article->precio_proveedor;
$history->stock = $article->stock;
$history->save();
});
}
Reference: https://www.larashout.com/how-to-use-laravel-model-observers

Laravel - Update dynamic form fields in database

I have a dynamic form where the user should be able to add or remove fields while editing.
I am able to update the exact number fields that are in the database table. But what I want is if a user clicked a 'Delete Subject' and 'Update' buttons, I want that entire row deleted from the database.
And, if he added a subject by clicking 'Add another Subject' the form and clicked 'Update' I want those subjects added. What am I missing here?
Note: I built a One-to-Many relation between New and Subjects, where a New has many subjects and many subjects belong to a New (It works fine).
My form looks like this
New Model
protected $fillable = ['name', 'address'];
public function subjects() {
return $this->hasMany(Subjects::class, 'new_id');
}
Subjects Model
protected $fillable = ['new_id', 'sub_code', 'sub_name', 'sub_img'];
public function subs(){
return $this->belongsTo(New::class, 'new_id');
}
Create Method
public function create(Request $request, New $new){
$new = New::FindorFail($id)
$subjects= [];
$sub_images = $request->file('sub_img');
$sub_name = $request->sub_name;
for ($i=0; $i < count(request('sub_code')); ++$i)
{
$subjects = new Subjects;
$subjecs->sub_code = request('sub_code')[$i];
$subjects->sub_name = request('sub_name')[$i];
$sub_img_name = uniqid() . '.' . $sub_images[$i]->getClientOriginalExtension();
$sub_images[$i]->move(public_path('/images/'), $sub_img_name);
$subjects->sub_img = '/images/'.$sub_img_name;
$new->subjects()->save($subjects);
}
}
Update Method
public function update(Request $request, $id){
$new=New::FindOrFail($id)
$subjects = Subjects::with(['subs'])->where('new_id', $new->id)->get();
$new->update($request->all());
$i=0;
foreach( $subjects as $new_subjects)
{
$sub_images =request()->file('sub_img');
$sub_name = request('sub_name');
if(isset($sub_images[$i]))
{
$pathToStore = public_path('images');
if($request->hasFile('sub_img') && isset($sub_images[$i]))
{
$sub_img_name = uniqid() . '.' . $sub_images[$i]->getClientOriginalExtension();
$sub_images[$i]->move(public_path('/images/'), $sub_img_name);
$new_subjects->sub_img = '/images/'.$sub_img_name;
$new_subjects->sub_code = request('sub_code')[$i];
$new_subjects->sub_name = request('sub_name')[$i];
$new_subjects->sub_img = "images/{$sub_img_name}";
$i++;
$new->subjects()->save($new_subjects);
}
}
}
}
Subjects Database
I want this table row be updated (added or deleted) after user edit the form.
From my experience with Laravel, I think the problem is that you call the Product model instead of the New model so maybe you need to fix it.
you reference the New model :
public function subs(){
enter code herereturn $this->belongsTo(New::class, 'new_id');
}
then you use the wrong model Product :
$new=Product::FinOrFail($id)
Another thing is to double check the fillable attribute within the Subject model also you can write the update action and do something like

Yii2 pass query result to a action in another controller

I'm trying to insert record into my audit table upon update of record in any other table. For example, if a user update his profile I want to store the old record and the newly updated record in my audit table. For this in my user model I'm trying to use beforeSave() and pass the value to my audit controller
public function beforeSave($insert)
{
if((parent::beforeSave($insert))){
// Place your custom code here
$query = DepCustomer::findOne($this->customer_id);
Yii::$app->runAction('audit-trial/createaudit', ['query' => $query]);
return true;
}
}
And the action code in audit controller for now
public function actionCreateaudit($query)
{
$model = new Audit();
$model->old = '';
foreach($query as $name => $value){
//$temp = $name .': '. $value.', ';
//$contentBefore[] = $temp;
$audit->old = $audit->old.$name .': '. $value. ', ';
}
// I've not yet any other code for now I'm trying to get the old value
$model->save();
}
I'm getting 404 not found error. What do I need to change in my code to make it work? Thank you!
instead of runAction() . If you want to perform operation on another model, prefer to create a static function in that model (in your case Audit model) to save the data
public function beforeSave($insert)
{
if((parent::beforeSave($insert))){
// Place your custom code here
$query = DepCustomer::findOne($this->customer_id);
Audit::saveOldDetails($query);
return true;
}
}
and write saveOldDetails function in Audit Model
public static saveOldDetails($query){
// your business logic here
}
Refer this link
http://www.yiiframework.com/doc-2.0/yii-base-controller.html#runAction()-detail

How do you assign roles to users with the basic template in Yii2?

http://www.yiiframework.com/doc-2.0/guide-security-authorization.html#role-based-access-control-rbac
In the documentation, it says that you can assign the role to the user in the advanced template by using this code:
public function signup()
{
if ($this->validate()) {
$user = new User();
$user->username = $this->username;
$user->email = $this->email;
$user->setPassword($this->password);
$user->generateAuthKey();
$user->save(false);
// the following three lines were added:
$auth = Yii::$app->authManager;
$authorRole = $auth->getRole('author');
$auth->assign($authorRole, $user->getId());
return $user;
}
return null;
}
The problem is that I am using the basic template. Is there a way of doing this inside the basic template?
I thought about using the afterSave method; however, I am not sure how to do this.
public function afterSave($insert)
{
}
Any idea on how it can be done?
public function afterSave($insert)
{
$auth = Yii::$app->authManager;
$authorRole = $auth->getRole('author');
$auth->assign($authorRole, $this->Id());
}
I am thinking this could work, but I am not totally sure.
It does not depend on used template.
Your example is correct, except few things.
$this->Id() should be replaced with $this->id (assuming primary key of users table is named id).
Note that you need also call parent implementation of afterSave() method and you missed $changedAttributes parameter:
/**
* #inheritdoc
*/
public function afterSave($insert, $changedAttributes)
{
$auth = Yii::$app->authManager;
$authorRole = $auth->getRole('author');
$auth->assign($authorRole, $this->id);
parent::afterSave($insert, $changedAttributes);
}
For further improvements, you can wrap saving in transaction, so if something is failed in afterSave(), model is not saved (afterSave() event handler is executed after model is saved in database).
Also you can move assigning role logic to separate method.
Note that with this logic every registered user will have that role. You can wrap it with some condition, however it's better to assign role through admin interface.
You can see how it's implemented for example in this extension. For example you can create separate form, action and extend GridView ActionColumn with additional icon for assigning role.

ASP.NET MVC LINQ-2-SQL as model - how to update?

Is it possible to use LINQ2SQL as MVC model and bind? - Since L2S "attachement" problems are really showstopping.
[HttpPost]
public ActionResult Save(ItemCart edCart)
{
using (DataContext DB = new DataContext())
{
DB.Carts.Attach(edCart);
DB.Carts.Context.Refresh(RefreshMode.KeepChanges, edCart);
DB.Carts.Context.SubmitChanges();
DB.SubmitChanges();
}
return RedirectToAction("Index");
}
That does not work. :S
What does your Save View look like?
You can't just attach a new item to the EntitySet like that. -> Attaching requires a lot of checks and it is a real pain to implement. I tried it myself and didn't like it at all.
In your [HttpPost] method you'll need to update the model before you can save it:
[HttpPost]
public ActionResult Save(int id, ItemCart edCart) {
DataContext DB = new DataContext(); // I'm doing this without a using keyword for cleanliness
var originalCart = DB.Carts.SingleOrDefault(c => c.ID == id); // First you need to get the old database entry
if (ModelState.IsValid & TryUpdateModel(edCart, "Cart")) { // This is where the magic happens.
// Save New Instance
DB.SubmitChanges.
return RedirectToAction("Details", new { id = originalCart.ID });
} else {
// Invalid - redisplay with errors
return View(edCart);
}
}
It tries to update the model from the controllers valueprovider using they "Cart" prefix.