Cakephp Querybuilder : update rows with an identical field as selected one - mysql

My app's goal is to schedule posts through a franchise to its franchised.
The HQ schedules a post for a certain date and time, with text and potential image.
It creates the post with all necessary information in the database for each franchised(id, franchise_id, user_id, text, image, network, post_id)
post_id contains an id that is the same for each row that are completely identical besides the franchise_id.
When I add a post, it works well. But when editing, since it gets the ID of the post, it'll only edit the post that matches the id.
And that is fine when it is a franchised, it will then change the post_id to a custom value, and will be independent to the others.
But when it's the HQ(superadmin)logged in, I want him to edit all that matches the selected one by post_id.
Query builder is not something I'm used to and sometimes I thought about dropping it for standard SQL, but if it's there it's for a reason, so I would like your help in solving this with Cakephp's query builder.
public function edit($id = null){
$event = $this->Events->get($id);
if ($this->request->is(['post', 'put'])) {
$event = $this->Events->patchEntity($event, $this->request->data,['associated' => ['Networks'], ]);
if($isuper == 'true'){//if logged in user is superadmin
}else{
$event->user_id = $this->Auth->user('id');
}
if ($this->Events->save($event)) {
$this->Flash->success(__('your post has been updated'));
return $this->redirect(
[
'action' => 'index',
date('Y', $event->date->getTimestamp()),
date('m', $event->date->getTimestamp()),
$event->company_id
]
);
}
$this->Flash->error(__('unable to update your post'));
}
$this->set('event', $event);
$this->layout = 'ajax';
}

You could try making bulk updates using updateAll
Something like:
$this->Events->updateAll(
['field' => true], // whatever fields you are updating
['post_id' => 'some_id'] // the selected post_id
);

Related

How do I update multiple columns with their respective values in laravel?

I have a database record that I would like to update base on certain conditions. This condition is: when the pay_day is reached, I want to send the user that owns that record an email and then update the pay_day column to another date in the future using the interval_day column on the users' table. interval_day is just a number selected by the user.
Below is an illustration:
$now = Carbon::now();
User::where('approved', true)
->where('pay_day', '<', $now)
->chunkById(1000, function($users){
foreach ($users as $user) {
$interval = $user->interval;
$payDay = $now()->addDays($interval);
// update the user...
$user->update([
'pay_day' => $payDay,
]);
// if the user was updated, send an email next...
}
});
Now, let's say I have 100 different users with different interval values. I want their respective values in their interval columns to be what would be updated to their pay_day column and NOT the same date for all 100 users.
But when I run the above query it didn't update, neither the pay_day nor send email to the respective users. When I dd($interval & $payDay) it returns nothing.
Please what am I doing wrong? I need your suggestions. Thanks for your time in advance.
use like this
$updates = ([
'pay_day' => $payDay,
//other columns
]);
$x = User::where('approved', true)
->where('pay_day', '<', $now)->->update($updates);
if($x){
//succeed case
}
Not sure if $payDay = $now()->addDays($interval); is a typo or you've actually done that in your code, but $now is a variable not a function. Additionally you need to tell the closure in your chunkById function to use $now:
\App\Models\User::where('approved', true)
->where('pay_day', '<', \Carbon\Carbon::today())
->chunkById(1000, function ($users) {
$users->each(function ($user) {
$success = $user->update([
'pay_day' => \Carbon\Carbon::today()->addDays($user->interval)
]);
if ($success) {
// send email
}
});
});
The above finds all approved Users where their pay_day is before today then processes the results in chunks of 1000 and updates the pay_day for each of them to be today + the interval value.

CakePHP 3.x - Saving associated data and form inputs of those tables

I have 3 tables:
Bookings
Payments
Sessions
In my form which is part of the Bookings table, while I have several attributes exclusive to Payments (eg. Amount, Depositpaid, Status), only one has a form input - everything else is Sessions related:
echo $this->Form->hidden('payments.amount',['type'=>'number', 'value'=>'0', 'step'=>'0.01', 'class'=>'currency form-control']);
In the BookingsController, I have the following:
$booking = $this->Bookings->newEntity([
'associated' => ['Payments', 'Sessions']
]]);
if ($this->request->is('post')) {
$data = $this->request->data;
$booking = $this->Bookings->patchEntity($booking, $data, [
'associated' => ['Payments', 'Sessions']
]);
...
$save = $this->Bookings->save($booking);
...
Upon clicking submit on the form, data in both Bookings and Sessions is saved. In the post data, there are two arrays: Session array and Payments array. In the variables data inside the Booking array, there is an Associated array with two elements: 0 Payments, 1 Sessions.
However, in the SQL log, there is no Insert Into for Payments table. When doing a debug of $booking (the patchEntity one), Payments is an empty array as follows:
'payments' => [],
I also did a debug of $save that comes after patchEntity, and obtained the same result for 'payments'.
I checked my Payments table model and the corresponding structure in MySQL when it came to not nulls and validation.
Below is the Payments model (PaymentsTable) regarding validation:
public function validationDefault(Validator $validator)
{
$validator
->integer('id')
->allowEmpty('id', 'create');
$validator
->allowEmpty('paymentmethod','create');
$validator
->decimal('amount')
->requirePresence('amount', 'create')
->notEmpty('amount');
$validator
->requirePresence('status', 'create')
->notEmpty('status');
$validator
->integer('depositpaid')
->allowEmpty('depositpaid', 'create');
$validator
->allowEmpty('uniqid', 'create');
return $validator;
}
In my MySQL database, I set attribute 'status' to automatically be set to 'notpaid' upon the creation of a new data entry, and also set attribute 'amount' to have a default value of '0.00'. The only not null fields are 'id', 'booking_id' (foreign key that links to the Booking table's id), 'amount' and 'status'.
So I guess my question is: Is the reason I'm not getting this associated table saved because I did not put in form inputs (hidden or otherwise) for the remainder of the Payments attributes or is there something I'm missing?
Update:
Okay I added a 0 to the form input (payments.0.amount), and this time the submit did not succeed. Upon debugging patchEntity - 'debug($booking)' once more, I find this error in the payments array:
'[errors]' => [
'status' => [
'_required' => 'This field is required'
]
This is even though I stated status to be set to automatically put in a default string. Do I need to do something like $this->request->data['status'] in the controller? And if so, how does it vary from an attribute for non-associated data (eg. $this->request->data['attribute'] is used for non-associated data)?
I've already tried:
$this->request->data['status'] = 'notpaid';
$this->request->data['payments']['status'] = 'notpaid';
$this->request->data['payments'][0]['status'] = 'notpaid';
$this->request->data['payments']['0']['status'] = 'notpaid';
All without success and receiving the same error in the patchEntity debug. The method that does work is adding in another form input for 'status' (the attribute that says it is required), but although I've solved my issue, I'm still left wondering how to input associated data from the controller.
I fixed it by just adding in another hidden form input, although I would still like to know how to input association data through the controller instead of the view.

Yii 2 Active Query joinWith issue

I have a Active Record model "Event" with a hasOne relation 'getUser'.
Now, if I do :
$eventModels = Event::find()->joinWith([
'user' => function($q){
return $q;
}])->all();
----------------------------------------------------
foreach($eventModels as $m){
var_dump($m->user); //Everything good as $m->user returns the related user object
die('skdw');
}
But, if I add the "select" in the joinWith query, then related "user" object becomes null. Here is the issue :
$eventModels = Event::find()->joinWith([
'user' => function($q){
$q->select('email');// or, ['email'] or ['user.email'] etc. fields.
return $q;
}])->all();
----------------------------------------------------
foreach($eventModels as $m){
var_dump($m->user); // Returns NULL
die('skdw');
}
But, if I make it $q->select('*'), then $m->user working .
I believe it used to work in some previous versions of Yii 2 (Right now, I am working on Yii 2.0.9)
Is this expected behavior ? If yes, then what is the solution to fetch only some select fields for the related joinWith model ? I don't want to fetch all the related fields as some of the related fields might contain "TEXT" data type.
You need to select the primary key column for the relation for Yii to build them.
e.g. assuming your column is called id
$eventModels = Event::find()->joinWith(['user' => function($q){
$q->select(['id', 'email']);
}])->all();
Also, you don't need to return the $q variable.

Multi-select Filter Search in Laravel 4

I need help/guidance in developing a multi-select filter search for my Laravel 4 app.
I have a table in my database called 'accounts'. This table is linked to other tables in the database via the following relationships:
'users' via belongs to (User model has a has many relationship to accounts)
'account_types' via belongs to (AccountType model has a has one relationship to accounts)
In my view I would like 3 multi-select boxes, company names (taken from the accounts table 'company_name' field), account managers (taken from the account_managers table, 'first_name' and 'last_name' fields) and account type (taken from the account_types table, 'type' field).
When a user selects values from these multi-select boxes and submits the form, I need to search the relevant tables and bring back the results. I don't want to use joins for this, as it is very slow. Especially, when bringing back values for the multi-select boxes.
If possible I would like to use Eloquent relationships in a way that brings back the results quickly.
I have this working with joins and query strings but it is very slow, up to 10 to 15 seconds.
I hope someone can help me out with this. Cheers.
OK, I have this working like a charm now by implementing select2, rather than simply loading all contacts in one go. Works much nicer too.
Here's my index method in AdminContactsController.php:
public function index()
{
$contact_names_value = explode(',', Input::get('contact_names_value'));
$accounts_value = explode(',', Input::get('accounts_value'));
$account_managers_value = explode(',', Input::get('account_managers_value'));
// In the view, there is a dropdown box, that allows the user to select the amount of records to show per page. Retrive that value or set a default.
$perPage = Input::get('perPage', 10);
// This code retrieves the order from that has been selected by the user by clicking on table ciolumn titles. The value is placed in the session and is used later in the Eloquent query and joins.
$order = Session::get('contact.order', 'cname.asc');
$order = explode('.', $order);
$message = Session::get('message');
$default = ($perPage === null ? 10 : $perPage);
$contacts_trash = Contact::contactsTrash($order)->get();
$this->layout->content = View::make('admin.contacts.index', array(
'contacts' => Contact::contacts($order, $contact_names_value, $accounts_value, $account_managers_value, $perPage)->paginate($perPage)->appends(array('accounts_value' => Input::get('accounts_value'), 'account_managers_value' => Input::get('account_managers_value'))),
'contacts_trash' => $contacts_trash,
'perPage' => $perPage,
'message' => $message,
'default' => $default
));
}
My scopeContacts method in my Contact.php model:
public function scopeContacts($query, $order, $contact_names_value, $accounts_value, $account_managers_value, $perPage)
{
$query->leftJoin('accounts', 'accounts.id', '=', 'contacts.account_id')
->leftJoin('users', 'users.id', '=', 'accounts.user_id')
->orderBy($order[0], $order[1])
->select(array('contacts.*', DB::raw('contacts.id as cid'), DB::raw('CONCAT(contacts.first_name," ",contacts.last_name) as cname'), DB::raw('CONCAT(users.first_name," ",users.last_name) as amname')));
if (empty($contact_names_value[0])) {
//
} else {
$query = $query->whereIn('contacts.id', $contact_names_value);
}
if (empty($accounts_value[0])) {
//
} else {
$query = $query->whereIn('accounts.id', $accounts_value);
}
if (empty($account_managers_value[0])) {
//
} else {
$query->whereIn('users.id', $account_managers_value);
}
}
Here's my JS code:
$('#contact_names_value').select2({
placeholder: 'Search contacts',
minimumInputLength: 3,
ajax: {
url: '/admin/get-contact',
dataType: 'json',
data: function (term, page) {
return {
contact_names_value: term
};
},
results: function (data, page) {
return {results: data};
}
},
tags: true
});
Here's my method getContactByName implemented in my AdminContactsController.php (similar methods implemented for users and accounts) code:
public function getContactByName()
{
$name = Input::get('contact_names_value');
return Contact::select(array('id', DB::raw('concat(first_name," ",last_name) as text')))->where(DB::raw('concat(first_name," ",last_name)'), 'like', "%$name%")->get();
}
Notice during my select statement, I do a DB::raw and set the 'first_name' and 'last_name' fields to be selected as 'text'. I think this was one of the major issues, as the plugin requires 'id' and 'text' to function.
My route was simply:
Route::get('admin/get-contact', 'AdminContactsController#getContactByName');

Retrieve session data Codeigniter

I'm working on a messaging system and want the user's userid to be posted to the database along with the message. Right now, the message is posting to the database, but with a user ID of 0.
How can I get the user ID from the session data to post to the database along with the message? Sidenote: I'm using Tank Auth for authentication. (From the mysql side, user_id in the message table is a foreign key referencing id in the users table).
Controller
function index() {
if ($this->input->post('submit')) {
$id = $this->input->post('user_id');
$message = $this->input->post('message');
$this->load->model('message_model');
$this->message_model->addPost($id, $message);
}
}
Model
function addMessage($id, $message) {
$data = array(
'user_id' => $id,
'message' => $message
);
$this->db->insert('message', $data);
}
For tank_auth, get the user_id using the following, and then assign that to your sessions
$user_id = $this->tank_auth->get_user_id();
Taken directly from CI's documentation:
Retrieving Session Data
Any piece of information from the session array is available using the
following function:
$this->session->userdata('item');
Where item is the array index
corresponding to the item you wish to fetch. For example, to fetch the
session ID you will do this:
$session_id = $this->session->userdata('session_id');
Note: The
function returns FALSE (boolean) if the item you are trying to access
does not exist.
So, if you have a piece of session data named user_id, you would access it like this:
$user_id = $this->session->userdata('user_id');