Yii2: How to delete with relation 3 table on Yii2 - yii2

I have the following tables and I want to click delete at Pak button which can delete all 3 tables relations.
How can I achieve that?
table Pak : id_pak, pak_name/////
table Church : id_church, church_name, id_pak/////
table Member : id_member, name_member, id_church////
public function actionDelete($id)
{
$this->findModel($id);
$select = Church::find()
->select('church_name')
->where(['id_pak' => $id])
->all();
$a3 = Church::find()
->select('id_church')
->where(['id_pak' => $id])
->all();
$select2 = Member::find()
->select('member_name')
->where(['id_church'=> $a3])
->all();
Church::find()->where(['id_pak' => $id])->one()->delete();
Pak::find()->where(['id_pak' =>$id])->one()->delete();
Member::find()->where(['id_church'=> $a3])->one()->delete();
return $this->redirect(['index','select'=>$select,'select2'=>$select2]);
}

Using Constraints with innoDB Engine
If you are using InnoDB and have added the constraints on delete cascade correctly and defined the respective relations in the models you don't need to worry about the related records in the other tables you just need to find the model in the Pak and delete it.
public function actionDelete($id)
{
$this->findModel($id)->delete();
return $this->redirect(['index']);
}
protected function findModel( $id ) {
if ( ($model = Pak::findOne ( $id )) !== null ) {
return $model;
}
throw new NotFoundHttpException ( 'The requested page does not exist.' );
}
Removing Manually
Or if you are not using innoDB or not using constraints for any reason then you can override the beforeDelete() in the ActiveRecord Model for Pak and remove all the child rows for the Pak Model in the Church and override beforeDelete() inside the Church to delete all child rows in Member model and return true from there to continue deleting the actual record in the Pak model
I assume that you have the following relations defined in the Pak model
public function getChurch(){
return $this->hasOne(Church::className(), ['id_pak'=>'id_pak']);
}
and the following inside the Church model
public function getMember(){
return $this->hasOne(Member::className(),['id_church'=>'id_church']);
}
Then override the beforeDelete() in the Pak model
public function beforeDelete() {
$this->church->delete();
return parent::beforeDelete ();
}
and override the beforeDelete() in the Church Model
public function beforeDelete() {
$this->member->delete();
return parent::beforeDelete ();
}
and in your actionDelete() just find the model and call delete
public function actionDelete($id)
{
$this->findModel($id)->delete();
return $this->redirect(['index']);
}
There is also a nice article on implementing recursiveDelete() method in a parent model here.

Following code may help you to solve your problem.
public function actionDelete($id)
{
$select = Church::find()
->select('church_name')
->where(['id_pak' => $id])
->all();
$a3 = Church::find()
->select('id_church')
->where(['id_pak' => $id])
->all();
$select2 = Member::find()
->select('member_name')
->where(['id_church'=> $a3])
->all();
// ---------- start ---------------
$park = Park::find()->where(['id_pak' => $id])->one();
if ( $park->delete() ){
Pak::deleteAll('id_pak = :id', [':id' => $id]);
foreach ($a3 as $value) {
Member::deleteAll('id_church = :id', [':id' => $value->id_church ]);
}
}
// ---------- end ---------------
return $this->redirect(['index','select'=>$select,'select2'=>$select2]);
}

Related

How can I insert into laravel pivot table?

I have 3 tables:
stations (id,station_name)
products (id,product_name)
product_station (station_id,product_id)
Station Model
protected $fillable = ['station_name'];
public function products(){
return $this->belongsToMany(Product::class);
}
Product Model
protected $fillable = ['product_name'];
public function stations(){
return $this->belongsToMany(Station::class);
}
I already have inserted stations and products and i want to insert
station with it's own product using into Pivot table
AdminProductStationcontroller
public function create()
{
$station = Station::pluck('station_name','id')->all();
$products = Product::pluck('product_name','id')->all();
return view('admin.product_stations.create',compact('station','products'));
}
I think there is error in store function below
public function store(Request $request)
{
$station = new Station();
$product = new Product();
$station->save();
$station->products()->attach($product);
return redirect('/admin/product_stations');
}
So i have got this error
(2/2) QueryException
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'product_id' cannot be null (SQL: insert into product_station (product_id, station_id) values (, 25))
attach() expects a single or an array of ids of the related Model implying that the Model should have been created beforehand.
What you're looking for is the save(Model) method.
$station->products()->save($product);
More on the above in the docs: https://laravel.com/docs/5.8/eloquent-relationships#updating-many-to-many-relationships
You should firstly save
$station = new Station();
$station->save();
$product = new Product();
$product->save();
then
https://laravel.com/docs/6.x/eloquent-relationships#updating-many-to-many-relationships
$station->products()->attach($product->id);
OR
You can try to save like so
$station->products()->save($product);
// Post Model
public function categories()
{
return $this->belongsToMany('App\Category')->withTimestamps();
}
public function tags()
{
return $this->belongsToMany('App\Tag')->withTimestamps();
}
public function store(Request $request)
{
$this->validate($request,[
'title' =>'required',
'image' => 'mimes:jpeg,jpg,bmp,png',
'categories' => 'required',
'tags' => 'required',
'body' => 'required',
'live_demo' =>'required'
]);
$image = $request->file('image');
$slug = str_slug($request->title);
if (isset($image))
{
$currentDate = Carbon::now()->toDateString();
$imagename = $slug.'-'.$currentDate.'-'. uniqid() .'.'. $image->getClientOriginalExtension();
$image_resize = Image::make($image->getRealPath());
$image_resize->resize(1600,1066);
if (!file_exists('storage/uploads/post'))
{
mkdir('storage/uploads/post',0777,true);
}
//$image->move('storage/uploads/post',$imagename);
$image_resize->save('storage/uploads/post/'.$imagename);
}else{
$imagename = "default.png";
}
$post = new Post();
$post->user_id = Auth::id();
$post->title = $request->title;
$post->slug = str_slug($request->title);
$post->image = $imagename;
$post->body = $request->body;
$post->price = $request->price;
$post->live_demo = $request->live_demo;
if(isset($request->status))
{
$post->status =true;
}else
{
$post->status = false;
}
$post->is_approved = true;
$post->save();
$post->categories()->attach($request->categories);
$post->tags()->attach($request->tags);
Toastr::success('Post Successfully Save:)','Success');
return redirect()->route('admin.post.index');
}
// Pivot table create category_post column create category_id, post_id.
// Pivot table create post_tag, and column create post_id, and tag_id
$station->products()->sync($request->products , false);

Base Table not found on unique value validation in MongoDB with laravel

I'm using laravel 5.3 with jenssegers/laravel-mongodb package for managing mongodb connections.
I want to check every time a user send a request to register a website in my controller if it's unique then let the user to register his/her website domain.
I wrote below code for validation but What I get in result is :
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'iranad.seat' doesn't exist (SQL: select count(*) as aggregate from `seat` where `domain` = order.org)
my controller code :
public function store(Request $request) {
$seat = new Seat();
$validator = Validator::make($request->all(), [
'domain' => 'required|regex:/^([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/|unique:seat', //validating user is entering correct url like : iranad.ir
'category' => 'required',
]);
if ($validator->fails()) {
return response()->json($validator->messages(), 400);
} else {
try {
$statusCode = 200;
$seat->user_id = Auth::user()->id;
$seat->url = $request->input('domain');
$seat->cats = $request->input('category');
$seat->filter = [];
if($request->input('category') == 'all') {
$obj['cats'] = 'false';
$seat->target = $obj;
} else {
$obj['cats'] = 'true';
$seat->target = $obj;
}
$seat->status = 'Waiting';
$seat->save();
} catch (\Exception $e) {
$statusCode = 400;
} finally {
$response = \Response::json($seat, $statusCode);
return $response;
}
}
}
My Seat Model :
namespace App;
use Moloquent;
use Carbon\Carbon;
class Seat extends Moloquent {
public function getCreatedAtAttribute($value) {
return Carbon::createFromTimestamp(strtotime($value))
->timezone('Asia/Tehran')
->toDateTimeString();
}
}
Obviously The validator is checking if domain is unique in mysql tables which causes this error, How can I change my validation process to check mongodb instead of mysql ?
I solved the problem, The solution is that you should add Moloquent to your model and define database connection :
namespace App\Models;
use Moloquent;
use Carbon\Carbon;
class Seat extends Moloquent
{
protected $collection = 'seat';
protected $connection = 'mongodb';
}

How to insert same data record to multiple table on Yii2

I'm using yii2-advanced. I've several table :
tb_user:(iduser(PK),username),
tb_profile:(id,iduser(FK)),
tb_status:(id,iduser(FK))
My question is how can i insert iduser(PK) from tb_user to iduser(FK) on tb_profile and tb_status after i push the signup button.
For a while i think i must to do some modification of bevahiours() function on User model and i found some error, or adding trigger syntax on the table ? (i think this is not a good ways).
Is there anyone who can help me, how to solve my problem ?
this is the User model before the modification :
<?php
namespace common\models;
use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class User extends ActiveRecord implements IdentityInterface
{
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
/**
* #inheritdoc
*/
public static function tableName()
{
return '{{%user}}';
}
/**
* #inheritdoc
*/
public function behaviors()
{
return [
'timestamp' => [
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => 'created_at',
ActiveRecord::EVENT_BEFORE_UPDATE => 'updated_at',
],
'value' => function () {return date('Y-m-d h:m:s');},
],
];
}
/**
* #inheritdoc
*/
public function rules()
{
return [
['status', 'default', 'value' => self::STATUS_ACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
];
}
/**
* #inheritdoc
*/
public static function findIdentity($id)
{
return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
}
/**
* #inheritdoc
*/
public function getId()
{
return $this->getPrimaryKey();
}
}
?>
The Controller :
public function actionSignup()
{
$model = new SignupForm();
if ($model->load(Yii::$app->request->post())) {
if ($user = $model->signup()) {
if (Yii::$app->getUser()->login($user)) {
return $this->goHome();
}
}
}
return $this->render('signup', [
'model' => $model,
]);
}
I had similar situation in one of my project where i had 2 tables like user,user_image where user_id was foreign key to add the path.
For those kind of situation you can use either of following approach
1.Insert record in both table on click of signup button. You will have to write update action accordingly.
$user = new User();
$user->name = "John"
$user->email = "John#gmail.com"
//Add if any other fields in table
$user->save(); //save the record
$user_image = new UserImage();
$user_image->user_id = $user->id;
$user_image->image = "image path"
//Add any other images here
$user_image->save();//save the record
2.You can also call create action of UserImage and do the same. If you use this approach than you might also need to use any other unique column to find the id of that user and use it to insert new record,for example in my table email is unique column so i can write following code in UserImage and get the id
$user = User::findOne(['email' => 'john#gmail.com']);//this will return whole row
$user_image->user_id = $user->id;
$user_image->image = "image path"
//Add any other images here
$user_image->save();//save the record
And that way you can use the code as per it suits your need
Thank you

Yii2 Select only few columns from related model

In controller i have:
public function actionGetItems()
{
$model = new \app\models\WarehouseItems;
$items = $model->find()->with(['user'])->asArray()->all();
return $items;
}
In WarehouseItem model i have standard (created by gii) relation declaration:
public function getUser()
{
return $this->hasOne('\dektrium\user\models\User', ['user_id' => 'user_id']);
}
How can i control which column data do i get from "user" relation? I currently get all columns which is not good as that data is being sent to Angular in JSON format.
Right now i have to loop trough $items and filer out all columns i dont want to send.
You should simply modify the relation query like this :
$items = \app\models\WarehouseItems::find()->with([
'user' => function ($query) {
$query->select('id, col1, col2');
}
])->asArray()->all();
Read more : http://www.yiiframework.com/doc-2.0/yii-db-activequerytrait.html#with()-detail
Your code should go this way.
public function actionGetItems()
{
$items = \app\models\WarehouseItems::find()
->joinWith([
/*
*You need to use alias and then must select index key from parent table
*and foreign key from child table else your query will give an error as
*undefined index **relation_key**
*/
'user as u' => function($query){
$query->select(['u.user_id', 'u.col1', 'u.col2']);
}
])
->asArray()
->all();
return $items;
}
Inside WarehouseItem model
/**
* #return ActiveQuery
*/
public function getUser()
{
$query = User::find()
->select(['id', 'col1', 'col2'])
->where([
'id' => $this->user_id,
]);
/**
* Default hasOne, setup multiple for hasMany
* $query->multiple = true;
*/
return $query;
}

Yii2 Dynamic Form update Action is not working

I like to explain my problem clearly,
Am using wbraganca/yii2-dynamicform
Here create action is working perfectly, but in update action
In the code which i marked, i don't know what i need to do, i dont have such field (addresses) in customer table. am stuck on that.
suppose if i create a variable in model like public $addressess, it makes me the reload the table again, and that cause while update the same form, data's getting reload and form viewing as empty without empty,
if create a function on that name, i don't know what to write on that..
Am simply using code like this
public function getaddressess()
{
}
Create Action Code
public function actionCreate()
{
$modelCustomer = new Customer;
$modelsAddress = [new Address];
if ($modelCustomer->load(Yii::$app->request->post())) {
$modelsAddress = Model::createMultiple(Address::classname());
Model::loadMultiple($modelsAddress, Yii::$app->request->post());
// ajax validation
if (Yii::$app->request->isAjax) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ArrayHelper::merge(
ActiveForm::validateMultiple($modelsAddress),
ActiveForm::validate($modelCustomer)
);
}
// validate all models
$valid = $modelCustomer->validate();
$valid = Model::validateMultiple($modelsAddress) && $valid;
if ($valid) {
$transaction = \Yii::$app->db->beginTransaction();
try {
if ($flag = $modelCustomer->save(false)) {
foreach ($modelsAddress as $modelAddress) {
$modelAddress->customer_id = $modelCustomer->id;
if (! ($flag = $modelAddress->save(false))) {
$transaction->rollBack();
break;
}
}
}
if ($flag) {
$transaction->commit();
return $this->redirect(['view', 'id' => $modelCustomer->id]);
}
} catch (Exception $e) {
$transaction->rollBack();
}
}
}
return $this->render('create', [
'modelCustomer' => $modelCustomer,
'modelsAddress' => (empty($modelsAddress)) ? [new Address] : $modelsAddress
]);
}
Help me to sort out this problem
$modelsAddress=$modelCustomer->addresses in that example mean array of related Address() instances
public function actionCreate()
{
$modelCustomer = new Customer;
$modelsAddress = $this->getaddressess($modelCustomer->id);
//...................
}
public function getaddressess($id)
{
$model = Address::find()->where(['id' => $id])->all();
return $model;
}
from
public function getaddressess($id)
{
$model = Address::find()->where(['id' => $id])->all();
return $model;
}
Shared above you will also need to add
on your Update view file :
'model' => $model,
'modelsAddress'=>$modelsAddress,
Hope this helps. It worked for me
It should be getAddresses() instead of getaddresses() (although both could work, I'd go with the first one to meet conventions). Or you could set a public $addresses if you don't need extra encapsulation.
suppose if i create a variable in model like public $addressess, it makes me the reload the table again, and that cause while update the same form, data's getting reload and form viewing as empty without empty,
I think you have a validation issue - no validator to mark the field as safe and you see it as empty after posting.
Add public $addresses to your Customer model.
Add "addresses" to your validation rules as safe (or more appropriate validator). This way after posting the form, it probably won't render empty.
This line code ---> $modelsAddress = $modelCustomer->addresses;
is get from model for customer at line ---> public function getAddresses()
this public function line code is code for get array related table from active record method on yii2.
$modelCustomer->addresses the word addresses should come from the $modelCustomer model you must have a relationship to the other table where you add the multiple values. In my example described in the video I have two tables po table and po_items table po_items table has foreign key of po_id. So when you make the Models using gii you will get a relationship in the model that is what you have to use instead of the addresses.
the relationship according my database should be - poItems you will see this at line 14
Add this to Customer Model
public function getAddresses(){
return $this->hasMany(Address::className(), ['id' => 'id']);
}
enter image description hereIn Po.php models:
public function getPoItems()
{
return $this->hasMany(PoItem::className(), ['po_id' => 'id']);
}
In PoController.php
public function actionUpdate($id)
{
$model = $this->findModel($id);
//$modelsPoItem = [new PoItem];
$modelsPoItem = $model->poItems;
if ($model->load(Yii::$app->request->post()) && $model->save())
{
$oldIDs = ArrayHelper::map($modelsPoItem, 'id', 'id');
$modelsPoItem = Model::createMultiple(PoItem::classname(), $modelsPoItem);
Model::loadMultiple($modelsPoItem, Yii::$app->request->post());
$deletedIDs = array_diff($oldIDs, array_filter(ArrayHelper::map($modelsPoItem, 'id', 'id')));
// validate all models
$valid = $model->validate();
$valid = Model::validateMultiple($modelsPoItem) && $valid;
if ($valid) {
$transaction = \Yii::$app->db->beginTransaction();
try {
if ($flag = $model->save(false)) {
if (! empty($deletedIDs))
{
PoItem::deleteAll(['id' => $deletedIDs]);
}
foreach ($modelsPoItem as $modelPoItem)
{
$modelPoItem->po_id = $model->id;
if (! ($flag = $modelPoItem->save(false))) {
$transaction->rollBack();
break;
}
}
}
if ($flag) {
$transaction->commit();
return $this->redirect(['view', 'id' => $model->id]);
}
} catch (Exception $e) {
$transaction->rollBack();
}
}
}
return $this->render('update', [
'model' => $model,
'modelsPoItem' => (empty($modelsPoItem)) ? [new PoItem] : $modelsPoItem
]);
}