CakePHP how to add data from another field of a related model - php

This is one of my first applications out of tutorials so I don't know how to express my issue well.
Well I have these 2 tables:
User ( id, code )
Hours ( id, user_id, created)
I want to know how I can add an entry to the Hours table using the user_code.
I tried to grab the data of the User table with the code value and then findBy and pass for the patchEntity but it did not work.

I don't have a whole lot of information to work with, but I'll give it a go.
I want to know how I can add an entry to the Hours table using the
user_code
You mention using patchEntity, so that's updating information that's already there. Assuming user_code is the 'code' column you're talking about there, first find the user by his code:
$users_tbl = TableRegistry::get('Users');
// find the user
$user = $users_tbl->findByCode($user_code)->first();
if ($user) {
// replace '$this->request->data() with whatever patch data you wanted
$users_tbl->patchEntity($user, $this->request->data(), [
'associated' => ['Hours']
]
if ($users_tbl->save($user)) {
// success!
} else {
// error!
}
} else {
// error!
}
It will also depend on how you have the data you passed in (where my '$this->request->data() is, or whatever your array might be) - it needs to match the right column names and be in the correct format listed here.
However, this is updating the data. Just adding the data, you can load the hours table and add a new entry with the user_id acquired from the user search:
$hours_tbl = TableRegistry::get('Hours');
$hours = $hours_tbl->newEntity([
'user_id' => $user->id // $user populated from same method earlier
]);
/* assumed 'id' was autoincrementing and 'created' was populated
through Timestamp behavior */
if ($hours_tbl->save($hours)) {
// yay!
} else {
// boo
}

Related

How to Check Value if Exists in laravel array?

I need to check if the value in the Table is existed skip it otherwise save it in the table below is the code.
else if(!empty($checkActivity))
{
//dd($checkActivity);
foreach($activitydetails->acb as $ac){
$acd=new ActivityFinance();
$acd->project_id=$project_id;
$acd->account_code=$ac->account_code;
$acd->activity_budget=$ac->activity_budget;
$acd->exact_title=$ac->exact_title;
$acd->created_by=Auth::user()->id;
$acd->save();
}
}
if we dd($activity->acb);
and if we dd the $checkActivity it shows the following data
in simple words, there is two arrays, one came from the database and the other from View how to check if the view sent array is in Database?
Thanks
i have use the laravel function updateOrCreate() it will check if the entry exist it will ignore or create new , if already in database table then it will update not ID below are the codes
ProjectFinance::updateOrCreate([
'project_id'=>$project_id,
],[
'finance_budget'=>$finance->finance_budget,
'finance_currency'=>$finance->finance_currency,
'created_by'=>Auth::user()->id
]);
$upsertActvity=$activitydetails->acb;
foreach($upsertActvity as $up)
{
ActivityFinance::updateOrCreate([
'id'=>$up->id,
'project_id'=>$project_id,
],[
'account_code'=>$up->account_code,
'activity_budget'=>$up->activity_budget,
'exact_title'=>$up->exact_title,
'created_by'=>Auth::user()->id
]);

Duplicate data on multiple clicks using random token check Laravel

I have a form where I am adding some data to db, but I want to avoid duplicate records if user clicks multiple times on the button, I can disable the button using JS but I want to have some checking on server side as well.
Currently on form I am setting a session variable with random number and sending it to controller using textbox (hidden) and then in controller I check if session variable is equal to textbox then add to db - but still the data adds multiple time in db, would appreciate if someone could help. Thanks.
Controller:
if ($request->token == session('test')){
session()->forget('test');
sleep(20); (this i added in order to test)
TableName::create([
'code' => 'test',
'name' => 'testing',
]);
return "done";
} else {
return "stopped";
}
Blade:
{{session(['test'=> rand()])}}
<input type="text" value="{{session('test')}}" name="token">
There are two methods in Laravel firstOrCreate or firstOrNew.
Refer https://laravel.com/docs/5.8/eloquent
The firstOrNew method, like firstOrCreate will attempt to locate a record in the database matching the given attributes. However, if a model is not found, a new model instance will be returned
// Retrieve flight by name, or create it with the name, delayed, and arrival_time attributes...
$flight = App\Flight::firstOrCreate(
['name' => 'Flight 10'],
['delayed' => 1, 'arrival_time' => '11:30']
);
You can check with not exist in MYSQL, check Below
INSERT INTO table_listnames (name, address, tele)
SELECT * FROM (SELECT 'Rupert', 'Somewhere', '022') AS tmp
WHERE NOT EXISTS (
SELECT name FROM table_listnames WHERE name = 'Rupert'
) LIMIT 1;

Yiiframework First time login

I'm currently busy with a project that needs users to go to a specific page to create a profile when they log in for the first time (and haven't created one yet). Honestly, I don't know where to start. I would like to do it in a good way.
So in short:
User signs up -> logs in -> needs to fill in form before anything else is allowed -> continue to rest of application
Question: What is a neat way to do this? A solution that isn't going to give me problems in the future development of the application.
I suggest you to use filters. In every controller where the completed profile is neeeded add this code:
public function filters() {
return array(
'completedProfile + method1, method2, method3', // Replace your actions here
);
}
In your base controller (if you don't use base controller, in any controllers) you need to create the filter named completedProfile with the simular code:
public function filterCompletedProfile($filterChain) {
$criteria = new CDBCriteria(array(
'condition' => 'id = :id AND firstname IS NOT NULL AND lastname IS NOT NULL',
'params' => array(':id' => Yii::app()->user->getId())
));
$count = User::model()->count($criteria);
if ($count == 1) {
$filterChain->run();
} else {
$this->redirect(array('user/profile'));
}
}
Possibly add a field to the user profile database table which denotes if they have filled out their profile information. Something like profile_complete. Then you can do a test on pages to see if profile_complete is true and display the page if so, and display the profile page if not.

how to use Native sessions and MySQL to join information

I have never used sessions before and I am trying to figure out the best way to handle this. I basically am trying to do:
1 step selecting a service
2 step selecting a time
3 step review and book
I can get it to work with no problems using mysql. What I would usually do is save the information into the database after each step and by the time I get to the review part I would have all the information saved and was OK.
However I don't think this is the best way to approach this and might cause problems down the road (what if they stopped at step 2 blah blah)
I decided to try the Laravel 4 sessions and it was super easy to save the session and move on to the next step. However, when I get to the final step I need to join mysql tables to fully show the information about their booking. Can I use the session information to join the information? Can I use the Sessions Database to save this information? Or use different tables?
My controller that POST after reviewing the information:
public function getReview() {
//sets id of user
$user = User::find(Auth::user()->id);
//gets the time and date that they booked from #getSchedule
$scheduler = Session::get('schedule');
//formats time to put in db
$date = strtotime($scheduler['date']);
//same thing as the line above
$dateFormat = date('Y-m-d',$date);
//model to save the schedule
$schedule = new Schedule();
$schedule->userID = $user->id;
$schedule->date = $dateFormat;
$schedule->block = $scheduler['timeslot'];
$schedule->status = "1";
$schedule->save();
//gets the services the user picked from #getServices
$service = Session::get('service');
//saves the services as individual rows in db table
foreach($service as $services)
{
if(!empty($services)) {
$service = new Service();
$service->userID = $user->id;
$service->services = $services;
$service->save();
}
}
return Redirect::to('dashboard');
}
This is the GET review page (where I am having the issues with all the JOINS)
public function showReview() {
$user = User::find(Auth::user()->id);
//show the information and confirm that they want all this crap...if they do..save it and return them to their dashboard
$time = DB::table('bk_schedule')
->leftJoin('bk_timeslot', 'bk_schedule.block', '=', 'bk_timeslot.id')
->where('bk_schedule.id', Auth::user()->id)->first();
$date = strtotime($time->date);
$dateFormat = date('D: F d, Y',$date);
$service = Session::get('service');
$serviceSummary = DB::table('bk_service')
->leftJoin('pr_service', 'pr_service.id', '=', 'bk_service.services')
->where('bk_service.userID', Auth::user()->id)
->get();
$total = DB::table('bk_service')
->leftJoin('pr_service', 'pr_service.id', '=', 'bk_service.services')
->where('bk_service.userID', Auth::user()->id)
->sum('pr_service.price');
return View::make('book.review', array('pageTitle' => 'Booking Appointment Review and Finalize', 'service' => $service, 'date' => $dateFormat,
'time' => $time, 'email' => $user->email, 'serviceSummary' => $serviceSummary, 'total' => $total));
}
Is it possible to save the information at the GET and delete it if they don't submit to POST? Could I maybe use my session data to and use the MySQL queries I have?
You don't understand what the session is, with you approach users will not be able to fill several forms (open in several tabs) simultaneously.
So, general way to do this is:
First page shows just HTML code with some fields
User selects them and POST data back to server
Server validates data and open ANOTHER HTML page with new fields AND adds several "hidden" field with values selected in step 1 (of course server can present page1 with error messages)
Users posts this form, server can open THIRD form where new visible fields and ALL previous fields are stored in hidden inputs
Finally user posts form to last page, where you have all data from all previous pages.
Just to notice: another approach is to store "temporary" data in session, for this you will need to obtain some generated ID on 2nd step and pass it through pages as described before

Comparing two multi-dimensional arrays in CakePHP - struggling to get logic correct

Scenario
I am developing an internal CakePHP company application that has a despatch screen, which has three lists:
Available items for despatch (Shown below on the left - "Items Available for Packing")
Already packed items pulled from the database (Shown below on the right - "Packed Items")
Changes to the packed items list (Form submission after changes have been made)
The user can drag items from the left list to the right list and vice versa. Once the click the Save button, the form is submitted with the items on the right list.
Desired Result
As part of the save, I need to compare (using PHP) the updated list with the saved list from the database.
With any additions, I need to update the items record with the despatch ID.
With any removals, I need to update the items record to sell the despatch ID to NULL.
This would allow users to drag and drop items in both directions, then click Save and expect the page to load with the state they left the page in.
Current State
I am able to save items to be added to the list and, separately, save items being removed. However, I cannot get them working together. When I try this, one item being added to the list completely replace all the other items on the "Packed Items" list.
Code so far...
function edit() {
$this->Despatch->recursive = -1;
if (!empty($this->data)) {
if($this->Despatch->save($this->data)) {
/* NEED TO RETRIEVE CURRENT REPAIR IDs ASSOCIATED
WITH THE DESPATCH ID AND COMPARE WITH FORM SUBMISSION LIST TO
REMOVE THE DIFFERENCES */
# Retrieve current repair records where despatch_id = $this->id.
$this->Despatch->Repair->recursive = -1;
$current_associated_repairs = $this->Despatch->Repair->find('all', array(
'fields' => array('id', 'despatch_date', 'despatch_id'),
'conditions' => array('Repair.despatch_id =' => $this->data['Despatch']['id'])));
# Create array with repair IDs
$repairs = explode(",", $this->data['Repair']['ids']);
$i = 0;
foreach($repairs as $repair) {
$repairupdates[$i]['Repair']['id'] = $repair;
$i++;
}
# Delete array index to prevent it interfering with form saving later
unset($this->data['Repair']['ids']);
# 2. Find unmatched IDs between current records and form submission list of repairs
$length1 = sizeof($current_associated_repairs);
$length2 = sizeof($this->data['Repair']);
for ($i = 0; $i < $length1; $i++) {
for ($j = 0; $j < $length2; $j++) {
### LOGIC NOT CORRECT HERE !!! ###
### THIS WORKS FOR REMOVING PACKED INSTRUMENTS - FROM RIGHT TO LEFT ###
### BUT ACTUALLY BEING TRIGGERED WHEN ADDING FROM LEFT TO RIGHT TOO ###
if ($current_associated_repairs[$i]['Repair']['id'] == $this->data['Repair'][$j]['id']
&& !in_array($current_associated_repairs[$i]['Repair']['id'], $this->data['Repair'][$j])) {
# if it's in current repairs and not in form submission, set to null...
# otherwise, it must be an addition if there's no matches
# 3. Set the despatch_date and despatch_id fields of those records to NULL
$this->data['Repair'][$j+1]['id'] = $current_associated_repairs[$i]['Repair']['id'];
$this->data['Repair'][$j+1]['despatch_date'] = null;
$this->data['Repair'][$j+1]['despatch_id'] = null;
}
}
}
# 4. Save the new list of repairs to the current despatch
if($this->Despatch->save($this->data) && $this->Despatch->Repair->saveAll($this->data['Repair'])) {
$this->Session->setFlash(__('The despatch has been saved.', true), 'default', array('class' => 'success-scheme message'));
} else {
$this->Session->setFlash(__('The repair could not be updated with the despatch number. Please try again.', true), 'default', array('class' => 'error-scheme message'));
}
} else {
$this->Session->setFlash(__('The despatch could not be saved. Please try again.', true), 'default', array('class' => 'error-scheme message'));
}
$this->redirect($this->referer(array('action' => 'view', $this->data['Despatch']['id'])));
}
}
I think I've included all the detail anyone should need, but just ask if you need to know more. The main problem I'm having is understanding the logic the code for achieving this.
Many thanks in advance.
PS - JavaScript Code
// click handler for saving despatch - required to save sortable lists properly
$('#save_despatch').click(function(e) {
e.preventDefault();
// gives comma-separated array of instrument IDs, e.g. 12345, 56789...
var result = $('#sortable2').sortable('toArray');
$('#RepairIds').val(result);
$('form').submit();
});
I can not really figure out what you are doing now in your logic, but I will suggest an approach that should work without a doubt.
You have two lists, for simplicity: left and right. This code is sort of pseudocode because I do not fully understand what you need, but this way, the lists should remain updated, and it cant go wrong.
Logic before displaying the lists (in PHP):
//Retrieve records from mysql into two arrays->aLeft and aRight
//Create an MD5 hash to easily compare current en future lists.
$sCheckSum = md5(implode(",",$aLeft));
$_SESSION['checkSum'] = $sCheckSum;
//Generate your lists now
//Display output
JS:
$('#save_despatch').click(function(e) {
e.preventDefault();
// gives comma-separated array of instrument IDs, e.g. 12345, 56789...
var leftResult = $('#sortable2').sortable('toArray');
var rightResult = $('#sortableX').sortable('toArray'); //Make sure this matches your lists, as I have not seen your HTML
$('#Left').val(leftResult);
$('#Right').val(rightResult);
$('form').submit();
});
Then on the receiving end:
//Get the values of the #Left and #Right inputs in to $aLeft and $aRight
$sNewCheckSum = md5($aLeft);
if($sNewCheckSum != $_SESSION['checkSum'] ) //Left list is not the same, so the right is neither
{
foreach(explode(",",$aLeft) as $iRepairId){
//Not sure what should happen here, but thats up to you.
//Mysql update table SET ID = NULL WHERE repairdId = $iRepairId
}
foreach(explode(",",$aRight) as $iRepairId){
//Not sure what should happen here, but thats up to you.
//Mysql update table SET ID = xxx WHERE repairdId = $iRepairId
}
}

Categories