I have a model with the relation called "reviews":
class ReportStructure extends \yii\db\ActiveRecord
{
const REVIEW_LIST_NAME = 'reviews';
public function getReviewList()
{
return $this->hasOne(FileIndexList::className(), ['id_owner' => 'id_report'])
->where('list_name = :list_name', [':list_name' => self::REVIEW_LIST_NAME]);
}
public function getReviews()
{
return $this->hasMany(FileIndex::className(), ['id_file_index' => 'id_file_index'])->via('reviewList');
}
}
In View, the reviews are displayed by GridView widget. The user can add or delete reviews by the other View. The user should specify at least one review. I added the validation rule to the model:
public function rules()
{
return [
['reviews', 'checkReviews'],
];
}
public function checkReviews($attribute)
{
if (count($this->reviews) === 0) {
$this->addError($attribute, 'You should add at least one review');
}
}
But it seems that rule even not fired.
public function actionIndex($idSupply, $restoreTab = false) {
$this->initData($idSupply, $report, $reestrData, $structure, $elements);
$ok = $report->load(Yii::$app->request->post()) &&
$reestrData->load(Yii::$app->request->post()) &&
Model::loadMultiple($elements, Yii::$app->request->post());
if($ok) {
$ok = $report->validate() &&
$reestrData->validate() &&
Model::validateMultiple($elements) &&
$structure->validate();
if($ok) {
$report->id_status = Status::STATUS_VERIFIED;
$this->saveData($report, $reestrData, $structure, $elements);
return $this->redirect(['supplies/update', 'id' => $idSupply]);
}
}
return $this->render('index', [
'structure' => $structure,
'report' => $report,
'reestrData' => $reestrData,
'elements' => $elements,
'restoreTab' => $restoreTab
]);
}
That's how the data is initialized. $elements are the objects of one class, I use tabular input for them.
private function initData($idSupply, &$report, &$reestrData, &$structure, &$elements) {
$report = \app\models\Reports::findOne($idSupply);
$reestrData = \app\models\ReestrData::findOne($report->id_reestr_data);
$structure = \app\models\report\ReportStructure::findOne($report->id_supply);
$elements = [
'titleIndex' => FileIndex::getInstance($structure->id_title_index, $structure->getAttributeLabel('id_title_index')),
'abstractIndex' => FileIndex::getInstance($structure->id_abstract_index, $structure->getAttributeLabel('id_abstract_index')),
'technicalSpecificationIndex' => FileIndex::getInstance($structure->id_technical_specification_index, $structure->getAttributeLabel('id_technical_specification_index')),
'contentsIndex' => FileIndex::getInstance($structure->id_contents_index, $structure->getAttributeLabel('id_contents_index')),
'imageListIndex' => FileIndex::getInstance($structure->id_image_list_index, $structure->getAttributeLabel('id_image_list_index'), false),
'tableListIndex' => FileIndex::getInstance($structure->id_table_list_index, $structure->getAttributeLabel('id_table_list_index'), false),
'textAnnexListIndex' => FileIndex::getInstance($structure->id_text_annex_list_index, $structure->getAttributeLabel('id_text_annex_list_index'), false),
'graphAnnexListIndex' => FileIndex::getInstance($structure->id_graph_annex_list_index, $structure->getAttributeLabel('id_graph_annex_list_index'), false),
'glossaryIndex' => FileIndex::getInstance($structure->id_glossary_index, $structure->getAttributeLabel('id_glossary_index'), false),
'reportIntroductionIndex' => FileIndex::getInstance($structure->id_report_introduction_index, $structure->getAttributeLabel('id_report_introduction_index')),
'reportMainPartIndex' => FileIndex::getInstance($structure->id_report_main_part_index, $structure->getAttributeLabel('id_report_main_part_index')),
'reportConclusionIndex' => FileIndex::getInstance($structure->id_report_conclusion_index, $structure->getAttributeLabel('id_report_conclusion_index')),
'bibliographyIndex' => FileIndex::getInstance($structure->id_bibliography_index, $structure->getAttributeLabel('id_bibliography_index')),
'metrologicalExpertiseIndex' => FileIndex::getInstance($structure->id_metrologicalexpertise_index, $structure->getAttributeLabel('id_metrologicalexpertise_index')),
'patentResearchIndex' => FileIndex::getInstance($structure->id_patent_research_index, $structure->getAttributeLabel('id_patent_research_index')),
'costStatementIndex' => FileIndex::getInstance($structure->id_cost_statement_index, $structure->getAttributeLabel('id_cost_statement_index')),
];
}
And tht's how the data is saved:
private function saveData($report, $reestrData, $structure, $elements) {
$reestrData->save(false);
$report->save(false);
foreach ($elements as $element) {
$element->save(false);
}
$structure->id_title_index = $elements['titleIndex']->id_file_index;
$structure->id_abstract_index = $elements['abstractIndex']->id_file_index;
$structure->id_technical_specification_index = $elements['technicalSpecificationIndex']->id_file_index;
$structure->id_contents_index = $elements['contentsIndex']->id_file_index;
$structure->id_image_list_index = $elements['imageListIndex']->id_file_index;
$structure->id_table_list_index = $elements['tableListIndex']->id_file_index;
$structure->id_text_annex_list_index = $elements['textAnnexListIndex']->id_file_index;
$structure->id_graph_annex_list_index = $elements['graphAnnexListIndex']->id_file_index;
$structure->id_glossary_index = $elements['glossaryIndex']->id_file_index;
$structure->id_report_introduction_index = $elements['reportIntroductionIndex']->id_file_index;
$structure->id_report_main_part_index = $elements['reportMainPartIndex']->id_file_index;
$structure->id_report_conclusion_index = $elements['reportConclusionIndex']->id_file_index;
$structure->id_bibliography_index = $elements['bibliographyIndex']->id_file_index;
$structure->id_metrologicalexpertise_index = $elements['metrologicalExpertiseIndex']->id_file_index;
$structure->id_patent_research_index = $elements['patentResearchIndex']->id_file_index;
$structure->id_cost_statement_index = $elements['costStatementIndex']->id_file_index;
$structure->save(false);
}
I eventually decided not to use validation for the relation at all and simply check reviews count in the controller:
if (count($structure->reviews) === 0) {
$ok = false;
Yii::$app->session->setFlash('danger', 'You should add at least one review!');
}
I think it's better to check it in beforeDelete method.
you can add this method to your model, and check, if it's the only review, then returns false.
public function beforeDelete()
{
if (!parent::beforeDelete()) {
return false;
}
if(self::find()->count() >1)
return true;
else
return false;
}
Related
i have laravel excel maatwebsite import update function, it works really well but i want to mark record that change by add "correction_flag" variable. the question is, how can i set this "correction_flag" when import.
this is my import function:
public function collection(Collection $rows)
{
foreach ($rows as $row)
{
$tgl_lahir_cell = $this->transformDate($row['tanggal_lahir']);
$tgl_awal_masa_kerja_cell = $this->transformDate($row['tanggal_awal_masa_kerja']);
$tgl_menjadi_permanen_cell = $this->transformDate($row['tanggal_menjadi_permanen']);
$tgl_keluar_cell = $this->transformDate($row['tanggal_keluar']);
if($tgl_lahir_cell == '1970-01-01') {
$formatedDate1 = NULL;
}else{
$formatedDate1 = $tgl_lahir_cell;
}
if($tgl_awal_masa_kerja_cell == '1970-01-01') {
$formatedDate2 = NULL;
}else{
$formatedDate2 = $tgl_awal_masa_kerja_cell;
}
if($tgl_menjadi_permanen_cell == '1970-01-01') {
$formatedDate3 = NULL;
}else{
$formatedDate3 = $tgl_menjadi_permanen_cell;
}
if($tgl_keluar_cell == '1970-01-01') {
$formatedDate4 = NULL;
}else{
$formatedDate4 = $tgl_keluar_cell;
}
Tempdat::where('cc', Auth::user()->ccode)
->where('id_tempdat', $row['id_tempdat'])
->update([
'golongan' => $row['golongan'],
'nama' => $row['nama'],
'jenis_kelamin' => $row['jenis_kelamin'],
'tgl_lahir' => $formatedDate1,
'tgl_awal_masa_kerja' => $formatedDate2,
'tgl_menjadi_permanen' => $formatedDate3,
'status_awal' => $row['status_di_awal_periode'],
'gaji_pokok_awal' => $row['gaji_pokok_di_awal_periode'],
'tunjangan_tetap_awal' => $row['tunjangan_tetap_di_awal_periode'],
'total_upah_awal' => $row['total_upah_di_awal_periode'],
'status_akhir' => $row['status_di_akhir_periode'],
'tgl_keluar' => $formatedDate4,
'status2_akhir' => $row['keterangan_keluar'],
'gaji_pokok_akhir' => $row['gaji_pokok_di_akhir_periode'],
'tunjangan_tetap_akhir' => $row['tunjangan_tetap_di_akhir_periode'],
'total_upah_akhir' => $row['total_upah_di_akhir_periode'],
'jumlah_pesangon_paid_awal' => $row['pesangon_dibayarkan_pada_periode'],
'correction_flag' => 'CORRECTED'
]);
}
}
public function headingRow(): int
{
return 4;
}
public function startRow(): int
{
return 5;
}
i already tried to put correction_flag like the example above but its just make all record uploaded marked CORRECTED eventhou there is no changes happend.
You need to first() the query, because laravel model event listeners won't work if there's mass update/create. So what you need to do is:
$tempdat = Tempdat::where('cc', Auth::user()->ccode)->where('id_tempdat', $row['id_tempdat'])->first();
if($tempdat){
$tempdat->update([
...
]);
}
And add this function to your Temptdat model:
protected static function booted()
{
parent::boot();
self::saving(function ($model) {
if ($model->isDirty()) {
$model->correction_flag = 'CORRECTED';
}
});
}
In controller
Login information is added inside an array and passed to model. Why it is not inserted in table.
$loginInfo = [
'agent' => $this->getUserAgentInfo(),
'ip' => $this->request->getIPAddress(),
'logintime' => date('Y-m-d h:i:s'),
];
$data=$model->saveLoginInfo($loginInfo);
...
...
public function getUserAgentInfo()
{
$agent = $this->request->getUserAgent();
if ($agent->isBrowser())
{
$currentAgent = $agent->getBrowser();
}
elseif ($agent->isRobot())
{
$currentAgent = $this->agent->robot();
}
elseif ($agent->isMobile())
{
$currentAgent = $agent->getMobile();
}
else{
$currentAgent = 'Undefined User Agent';
}
return $currentAgent;
}
In Model
public function saveLoginInfo($data){
$this->db->table('login_activity')->set($data)->insert();
}
i have a form whereby on updating the data and storing it to the database it shows a success message.if one of the inputs isn't filled it shows an error.am getting a bug whereby when i want to re-update the data and i open the form with the existing inputs when i click save the data should just redirect back to the previous page and not show the success message as the data hasnt being updated.how can i achieve this,am looking for a logic here fellow devs..here is my update function code
public function update(Request $request)
{
try {
$validation = Validator::make($request->all(), [
'systemid' => 'required',
'category' => 'required',
'subcategory' => 'required',
'prdcategory' => 'required',
'prdbrand' => 'required'
]);
Log::debug('Request: '.json_encode($request->file()));
if ($validation->fails()) {
throw new \Exception("validation_error", 19);
}
$systemid = $request->systemid;
$product_details = product::where('systemid', $systemid)->first();
$changed = false;
if ($request->has('product_name')) {
if ($product_details->name != $request->product_name) {
$product_details->name = $request->product_name;
$changed = true;
}
}
if ($request->has('category')) {
if ($product_details->prdcategory_id != $request->category) {
$product_details->prdcategory_id = $request->category;
$changed = true;
}
}
if ($request->has('subcategory')) {
if ($product_details->prdsubcategory_id != $request->subcategory) {
$product_details->prdsubcategory_id = $request->subcategory;
$changed = true;
}
if ($product_details->ptype == 'voucher') {
$voucher = voucher::where('product_id', $product_details->id)->first();
if($voucher->subcategory_id != $request->subcategory){
$voucher->subcategory_id = $request->subcategory;
$voucher->save();
$changed = true;
}
}
}
if ($request->has('prdcategory')) {
if ($product_details->prdprdcategory_id != $request->prdcategory) {
$product_details->prdprdcategory_id = $request->prdcategory;
$changed = true;
}
}
if ($request->has('prdbrand')) {
if ($product_details->brand_id != $request->prdbrand) {
$product_details->brand_id = $request->prdbrand;
$changed = true;
}
}
if ($request->has('description')) {
if ($product_details->description != $request->description) {
$product_details->description = $request->description;
$changed = true;
}
}
if ($changed == true || true) {
$product_details->save();
$msg = "Product information updated successfully";
$data = view('layouts.dialog', compact('msg'));
//i have added this code but it doesnt work
} else if($changed == false) {
return back();
$data = '';
}
}
return $data;
}
my laravel project version is 5.8
The following line will always evaluate to True
$changed == true || true
And you have a catch statement missing at the end so I had to add it.
And I advise you to simply get the dirty version of $product_details.
You can use $product_details->isDirty() // boolean.
Or even better way is to use $product_details->wasChanged() // boolean
Here is the code after some tweaks:
public function update(Request $request)
{
try {
$validation = Validator::make($request->all(), [
'systemid' => 'required',
'category' => 'required',
'subcategory' => 'required',
'prdcategory' => 'required',
'prdbrand' => 'required'
]);
Log::debug('Request: '.json_encode($request->file()));
if ($validation->fails()) {
throw new \Exception('validation_error', 19);
}
$systemid = $request->systemid;
$product_details = Product::where('systemid', $systemid)->first();
$changed = false;
// Looping for all inputs:
$fieldsToCheck = [
'name' => 'product_name',
'prdcategory_id' => 'category',
'prdsubcategory_id' => 'subcategory',
'prdprdcategory_id' => 'prdcategory',
'brand_id' => 'prdbrand',
'description' => 'description',
];
foreach ($fieldsToCheck as $productColumnName => $requestFieldName) {
$requestInput = $request->{$requestFieldName};
if ($request->has($requestFieldName)) {
if ($product_details->$productColumnName != $requestInput) {
$product_details->$productColumnName = $requestInput;
$changed = true;
}
}
// Exception for Sub Category to check for the voucher.
if ($requestFieldName == 'subcategory') {
$this->handleVoucher($requestInput);
}
}
// here I advise you to simply get the dirty version of $product_details
// you can use $product_details->isDirty() // boolean
// or even better use $product_details->wasChanged() // boolean
if ($changed) {
$product_details->save();
$msg = 'Product information updated successfully';
$data = view('layouts.dialog', compact('msg'));
} else {
return back();
// Todo Mo: No need for this line so I commented it out.
//$data = '';
}
} catch (\Exception $e) {
dd($e->getMessage(), 'Oops, error occurred');
}
return $data;
}
private function handleVoucher($product_details, $subcategory)
{
if ($product_details->ptype == 'voucher') {
$voucher = voucher::where('product_id', $product_details->id)->first();
if ($voucher->subcategory_id != $subcategory) {
$voucher->subcategory_id = $subcategory;
$voucher->save();
}
}
}
I have a model "SalesContract" which has a "belongsTo" relationship with a class called "Asset". However, it does not work (I cannot set or get).
Could it be an issue with the "asset()" helper method?
If I change the name of my method to something like "related_asset()", then it works.
This does NOT work:
public function asset()
{
return $this->belongsTo(Asset::class);
}
This DOES work:
public function related_asset()
{
return $this->belongsTo(Asset::class);
}
Full model:
class SalesContract extends Model
{
use SoftDeletes;
use Commentable;
const icon_class = 'far fa-file-signature';
const default_buyer_fee = 100;
const default_carproof_fee = 36.45;
protected $fillable = [
'number', 'asset_id', 'seller_id', 'buyer_id', 'buyer_representative', 'sale_date', 'sale_price',
'apply_sales_taxes_to_sale_price', 'buyer_fee', 'carproof_fee', 'deposit'
];
protected $casts = [
'sale_date' => 'datetime',
'sale_price' => 'float',
'carproof_fee' => 'float',
'buyer_fee' => 'float',
'deposit' => 'float',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime'
];
protected $appends = [
'subtotal', 'taxable_amount', 'sales_taxes', 'total', 'balance'
];
protected static function boot()
{
parent::boot();
static::addGlobalScope('order', function (Builder $builder) {
$builder->orderBy('created_at', 'desc');
});
static::saving(function($table) {
if (empty($table->id)) {
if ($current_user = Auth::user()) {
$table->created_by_user_id = $current_user->id;
}
}
});
}
public function __construct(array $attributes = [])
{
if (empty($this->sale_date)) {
$this->sale_date = Carbon::today()->format('Y-m-d');
}
if (empty($this->id)) {
if (empty($this->number)) {
if ($asset = $this->asset) {
$this->number = $asset->external_file_number ?? $asset->internal_file_number;
}
}
$this->buyer_fee = $this->buyer_fee ?? self::default_buyer_fee;
$this->carproof_fee = $this->carproof_fee ?? self::default_carproof_fee;
$this->apply_sales_taxes_to_sale_price = $this->apply_sales_taxes_to_sale_price ?? 1;
}
parent::__construct($attributes);
}
public function __toString()
{
return __('sales_contracts.item_label', ['number' => $this->number ?? $this->id]);
}
public function scopeFilter($query, $filters)
{
$filters = is_array($filters) ? array_filter($filters) : [];
return $query->where($filters);
}
public function asset()
{
return $this->belongsTo(Asset::class);
}
public function seller()
{
return $this->belongsTo(Contact::class);
}
public function buyer()
{
return $this->belongsTo(Contact::class);
}
public function created_by_user()
{
return $this->belongsTo(User::class);
}
public function getSubtotalAttribute()
{
return $this->sale_price + $this->carproof_fee + $this->buyer_fee;
}
public function getTaxableAmountAttribute()
{
if ($this->apply_sales_taxes_to_sale_price) {
return $this->subtotal;
} else {
return $this->subtotal - $this->sale_price;
}
}
public function getSalesTaxesAttribute()
{
$sales_taxes = [];
if ($seller = $this->seller) {
foreach ($seller->sales_tax_numbers as $tax_number) {
if ($tax_number->use) {
if ($sales_tax = $tax_number->sales_tax) {
$sales_taxes[] = [
'sales_tax' => $sales_tax,
'name' => $sales_tax->name,
'rate' => $sales_tax->rate,
'label' => $sales_tax->label,
'number' => $tax_number->number,
'amount' => round($this->taxable_amount * $sales_tax->rate, 2)
];
}
}
}
}
return $sales_taxes;
}
public function getSalesTaxesTotalAttribute()
{
$total = 0;
foreach ($this->sales_taxes as $sales_tax) {
$total += $sales_tax['amount'];
}
return $total;
}
public function getTotalAttribute()
{
return $this->subtotal + $this->sales_taxes_total;
}
public function getBalanceAttribute()
{
return $this->total - $this->deposit;
}
}
From controller:
$sales_contract = new SalesContract;
if ($request->has('sales_contract')) {
$sales_contract->fill($request->input('sales_contract'));
}
Result of dd($request->input()):
array:1 [▼
"sales_contract" => array:1 [▼
"asset_id" => "11754"
]
]
(Yes, Asset with ID 11754 does exist.)
by default Name of relation is depended on 'foreign_key'
if you want to set different name of relation than foreign key just provide foreign key and other_key along with relation declaration
public function asset()
{
return $this->belongsTo(Asset::class,related_asset,id);
}
Problem solved.
I had to remove the following code from my __construct() method as it was breaking the relationship somehow:
if (empty($this->number)) {
if ($asset = $this->asset) {
$this->number = $asset->external_file_number ?? $asset->internal_file_number;
}
}
I want to insert multiple records in my database using Laravel, however when i insert it, it only gives me one record in the database
Here's my Controller
public function postCreateAttendance()
{
$validate = Validator::make(Input::all(), array(
'status' => 'required'
));
if ($validate->fails())
{
return Redirect::route('viewStudent')->withErrors($validate)->withInput();
}
else
{
foreach(User::all() as $user):
foreach(User::whereRaw('isTeacher = "0" and isAdmin = "0"')->get() as $student)
foreach(User::whereRaw('isTeacher = "1" and isAdmin = "0"')->get() as $teacher)
//$users[$user->id]=$user->firstname;
$attendance = new Attendance();
$attendance->status = Input::get('status');
$attendance->comment = Input::get('comment');
$attendance->student_id = $student->id=$student->id;
$attendance->student_firstname = $student->id=$student->firstname;
$attendance->student_lastname = $student->id=$student->lastname;
$attendance->teacher_id = $teacher->id=$teacher->id;
$attendance->teacher_firstname = $teacher->id=$teacher->firstname;
$attendance->teacher_lastname = $teacher->id=$teacher->lastname;
if($attendance->save())
{
return Redirect::route('viewStudent')->with('success', 'ATTENDANCE HAS BEEN RECORDED!');
}
else
{
return Redirect::route('viewStudent')->with('fail', 'An error occured while creating the attendance.');
}
endforeach;
}
}
How can i save multiple records? Please help Thank You ^_^
The issue is that you are returning during the foreach loop - so only one record is processed. You need to process all the records, then return the route.
Here is some refactoring of your code
public function postCreateAttendance()
{
$validate = Validator::make(Input::all(), array(
'status' => 'required'
));
if ($validate->fails()) {
return Redirect::route('viewStudent')->withErrors($validate)->withInput();
}
foreach(User::where('isTeacher', '0')->where('isAdmin', '0')->get() as $student) {
foreach(User::where('isTeacher', '1')->where('isAdmin', '0')->get() as $teacher) {
$attendance = new Attendance();
$attendance->status = Input::get('status');
$attendance->comment = Input::get('comment');
$attendance->student_id = $student->id;
$attendance->student_firstname = $student->firstname;
$attendance->student_lastname = $student->lastname;
$attendance->teacher_id = $teacher->id;
$attendance->teacher_firstname = $teacher->firstname;
$attendance->teacher_lastname = $teacher->lastname;
$attendance->save();
}
}
return Redirect::route('viewStudent')->with('success', 'ATTENDANCE HAS BEEN RECORDED!');
}
Edit: I've removed the first foreach(User::all() as $user): - because at the moment, in your code, it does nothing...?