CodeIgniter delete query does not work in foreach loop? - codeigniter

I have the following code to remove user accounts that have not verified their email address within one week. The query works as I expect, but the delete function only deletes the first record, and I cant figure out why. The print_r generates the full results as I expect, but the delete function is somehow ignored. Any ideas on how to make it so it deletes all relevant records?
public function databaseupdate () //REMOVES ALL UNVERIFIED EMAIL ACCOUNTS OLDER THAN 1 WEEK - REQUIRES MANUAL BUTTON PRESS BY ADMIN
{
$verified = 'no';
$tables = array('register', 'profiles', 'profilesmember');
$deletedate = date('Y-m-d', strtotime('-7 days'));
$this->db->select('email');
$this->db->where('is_email_verified', $verified);
$this->db->where("DATE_FORMAT(created_date,'%Y-%m-%d') <='$deletedate'");
$this->db->from('register');
$query = $this->db->get();
foreach($query->result() as $row)
{
$email = $row->email;
$this->db->where('email', $email);
$this->db->delete($tables);
// print_r($email);
}
}

You are looping on the WHERE statement which will work for the first instance as you have observed, but subsequent ones, it will not, as you are adding WHERE statements like
Loop 1: WHERE email = email1
Loop 2: WHERE email = email1 AND email = email2
Loop n: WHERE email = email1 AND email = email2 AND ..... email = emailn
and it will just keep on building. Its the very same behaviour as you have used in your query above with the multiple WHERE statements.
So you need to perform a reset on the query.
$this->db->reset_query();
So your loop might look like...
foreach($query->result() as $row)
{
$this->db->where('email', $row->email);
$this->db->delete($tables);
$this->db->reset_query();
}
Then you will get what you are expecting.
Loop 1: WHERE email = email1
Loop 2: WHERE email = email2
Loop n: WHERE email = emailn
While the above "Works" you should be considering what is you are trying to achieve here...
You want to create a list of Emails that you want to delete from a number of tables.
Just NOTE: We have no idea on how these tables are related etc so just be aware of the possibility of leaving "orphan" records. There are many ways to deal with this but its way outside this discussion.
An Option is to check you have some results, build the where query then perform the delete. So it's only "1 Trip" to the Database" and not "n Trips".
// Did we get any results to delete?
if($query AND $query->num_rows()) {
foreach($query->result() as $row)
{
// Build the WHERE Statement
$this->db->or_where('email', $row->email);
}
$this->db->delete($tables); // Execute the Delete.
}
So it's important to understand the various ways to do this... I.E there are others. But for this case, it should be fine (famous last words).

Further to TimBrownlaw's answer using or_where also works:
foreach($query->result() as $row)
{
$this->db->or_where('email', $row->email);
$this->db->delete($tables);
}

Related

In laravel livewire, I want to get the user only if it's value changed from specific value to another specific value

Here is the code in which I get the user if it's g10_eng_unwh is equal to 1.
public function purchased(User $user)
{
if ($user->g10_eng_unwh == 1) {
$token = "g10_eng_unwh";
}
if ($user->g7_eng_unwh == 1) {
$token = "g7_eng_unwh";
}
$time = Carbon::now()->format('Y-m-d');
dd($user->email, $time, $token);
}
Instead, I want to get the user only when it's g10_eng_unwh value changes from 0 to 1.
Is there any way?
You need to get the past value at the beginning so that you can apply the condition, it will have to be stored somewhere. Most likely you will need to create g10_eng_unwh_old or something like that. I assume that g10_eng_unwh is a column in the database, in this case create g10_eng_unwh_old and store the old value in it.
In this case, you could get it even on request. For example
DB::query()
->where('g10_eng_unwh', 1)
->where('g10_eng_unwh_old', 0)
->get();

how can i increment 6 months selecting from database to_date field?

I'm making my project,and want to increment date from fetching to_date filed with 6 months if last to_date is gone then add more 6 months and so on what can i do for this?
$abc=(Session::get('email'));
$email= $request->input('email');
if (Maintenance::where('email', '=', $email)) {
$users=Carbon::create(2019,0,30)->addMonths(6)->toDatestring();
if (Maintenance::where('maintenance_status', '=', 'PAID')->orderBy('todate','DESC')) {
$check = Maintenance::select('to_date')->where('maintenance_status', '=', 'PAID')->orderBy('to_date','DESC')->get();
// $users= Carbon($check[0])->addmoths(6);
$users = Carbon::addMonths(6)->toDatestring();
i expect the output of 30-06-2019,30-12-2019 and so on but the actual output is only increment one time using Carbon and i want to increment fetching from database date
It looks like you are overwriting your variable instead of adding to it.
$users = Carbon\Carbon::create(2019,0,30)->addMonths(6)->toDatestring();
returns 2019-06-30.
$users = Carbon\Carbon::addMonths(6)->toDatestring(); would overwrite it, but it actually breaks "PHP Error: Call to a member function addMonths() on string".
Don't store the string as your variable. Instead, keep it as a instance of Carbon so that you can call functions on it. Then when you need to use it call toDatestring().
It would look something like this:
$date_to_increment = Carbon\Carbon::create(2019,0,30)->addMonths(6);
echo($date_to_increment->toDatestring()); // 2019-06-30
if ($your_condition) {
$date_to_increment->addMonths(6);
echo($date_to_increment->toDatestring()); // 2019-12-30
}
As far as applying it to your case, there are a few issues. Your first condition is invalid. I believe it will always return true as you never execute the query. I'm also assuming since you are matching an email that there will only be one result. So lets use the query builder method first() to save a step as this will return a single entry instead of an array.
$maintenance = Maintenance::where('email', '=', $email)->first();
if ($maintenance) {
// do stuff
}
Then you have a few more conditions that have similar issues, but more importantly, they are re-querying so you are losing the restrictions in your collection each time.
Instead:
$maintenance = Maintenance::where('email', '=', $email)->first();
if ($maintenance) {
if ($maintenance->maintenance_status === 'PAID') {
// do something
}
}
Finally, to use the value from the database:
if ($maintenance->maintenance_status === 'PAID') {
$date = Carbon\Carbon::parse($maintenance->to_date)->addMonths(6);
$maintenance>to_date = $date->toDatestring();
$maintenance->save();
}

Execute Multiple query if needed in Maatwebsite Excel package, Laravel

I am trying to export excel from database in laravel. What i want to do is, there is a form by which admin can select "From" , "To" , "Bookingtype" and "Usertype" . From and To's are date, bookingtype is like Booked or Cancelled and userype is Normal or agent.
When admin select any kind of needs from this, for example when admin selects a date from , from and to then selects cancelled and Agent and press export button, they should get excel. And like wise they can execute different different queries.
So far , i have accomplished to get excel by using three parameters like from, to and bookingtype. But how to use fourth parameter also which is user type ?
This is my code:
public function query()
{
$from = $this->from;
$to = $this->to;
$bookingtype = $this->bookingtype;
$usertype = $this->usertype;
return Booking::query()->whereBetween('createdAt',[$from, $to])->where('status', '=', $bookingtype);
}
And the important is , some time admin can only select from and to and they dont need other two options. So in that situation how to execute only that with one query function ? I am passing these from a from to controller and then class of maatwebsite. So what i am asking is, how to make a query which executes only what are been sent ?
If we send from and to alone, then that should only execute and if we sent three parameters then that should execute like wise ! hope all understands. Do let me know if anything needed.
hope this will help you if not the let me know
$bokingQuery = Booking::query();
$from = $this->from;
$to = $this->to;
if(isset($from) && isset($to))
$bokingQuery->whereBetween('createdAt',[$from, $to]);
$bookingtype = $this->bookingtype;
if(isset($bookingtype ))
$bokingQuery->where('status',$bookingtype);
$usertype = $this->usertype;
if(isset($usertype)) //
$bokingQuery->whereHas('usertype',, function($query) use ($usertype) {
$query->whereUserType($usertype);
});
$bokingQuery->get();
You must be create your conditions due to the input parameters.
public function query(){
$conditions=[];
if(isset($this->from) && $this->from){
$conditions[]=['createdAt', '>=', $this->from];
}
if(isset($this->to) && $this->to){
$conditions[]=['createdAt', '<=', $this->to];
}
if(isset($this->bookingtype) && $this->bookingtype){
$conditions[]=['status', $this->bookingtype];
}
if(isset($this->usertype) && $this->usertype){
$conditions[]=['usertype', $this->usertype];
}
return Booking::where($conditions)->get();
}

Laravel - can't get model after deleting related model records

I have a function postShippingmethods in which I delete, update or create new shipping methods depending what the user specified in the form. It works like it should , except that if any methods are deleted, I get empty result when trying to retrieve the user model with the updated methods.
To delete methods, I first get the user:
$user = \App\User::where('id',$id)->with(['shipping_profiles' => function($query) {
$query->where('default', 1);
}, 'shipping_profiles.methods' ])->first();
I compare the stored methods to the ones in the request; if any are missing , they should be deleted.
This code does the deletion:
foreach($non_included_ids as $id){
$method = \App\ShippingMethod::find($id);
$method->suppliers()->detach();
$method->delete();
}
Then I get the user once again, to get the updated data:
$user = \App\User::where('id',$id)->with(['shipping_profiles' => function($query) {
$query->where('default', 1);
}, 'shipping_profiles.methods' ])->first();
^^ this works well if nothing was deleted, but for some reason if something was deleted, the above code will return nothing. And when I try to use the $user to retrieve data I of course get "Trying to get property of non object".
So can anyone explain why this happen and what I should do to get the user with the updated data?
Use a different variable name in the loop:
foreach($non_included_ids as $non_included_id){
Otherwise, the loop changes the value of $id and \App\User::where('id',$id) fetches the wrong user.

codeigniter count_all_results

I'm working with the latest codeIgniter released, and i'm also working with jquery datatables from datatables.net
I've written this function: https://gist.github.com/4478424 which, as is works fine. Except when I filter by using the text box typing something in. The filter itself happens, but my count is completely off.
I tried to add in $res = $this->db->count_all_results() before my get, and it stops the get from working at all. What I need to accomplish, if ($data['sSearch'] != '') then to utilize the entire query without the limit to see how many total rows with the search filter exists.
If you need to see any other code other than whats in my gist, just ask and I will go ahead and post it.
$this->db->count_all_results() replaces $this->db->get() in a database call.
I.E. you can call either count_all_results() or get(), but not both.
You need to do two seperate active record calls. One to assign the results #, and one to get the actual results.
Something like this for the count:
$this->db->select('id');
$this->db->from('table');
$this->db->where($your_conditions);
$num_results = $this->db->count_all_results();
And for the actual query (which you should already have):
$this->db->select($your_columns);
$this->db->from('table');
$this->db->where($your_conditions);
$this->db->limit($limit);
$query = $this->db->get();
Have you read up on https://www.codeigniter.com/userguide2/database/active_record.html#caching ?
I see you are trying to do some pagination where you need the "real" total results and at the same time limiting.
This is my practice in most of my codes I do in CI.
$this->db->start_cache();
// All your conditions without limit
$this->db->from();
$this->db->where(); // and etc...
$this->db->stop_cache();
$total_rows = $this->db->count_all_results(); // This will get the real total rows
// Limit the rows now so to return per page result
$this->db->limit($per_page, $offset);
$result = $this->db->get();
return array(
'total_rows' => $total_rows,
'result' => $result,
); // Return this back to the controller.
I typed the codes above without testing but it should work something like this. I do this in all of my projects.
You dont actually have to have the from either, you can include the table name in the count_all_results like so.
$this->db->count_all_results('table_name');
Count first with no_reset_flag.
$this->db->count_all_results('', FALSE);
$rows = $this->db->get()->result_array();
system/database/DB_query_builder.php
public function count_all_results($table = '', $reset = TRUE) { ... }
The
$this->db->count_all_results();
actually replaces the:
$this->db->get();
So you can't actually have both.
If you want to do have both get and to calculate the num rows at the same query you can easily do this:
$this->db->from(....);
$this->db->where(....);
$db_results = $this->get();
$results = $db_results->result();
$num_rows = $db_results->num_rows();
Try this
/**
* #param $column_name : Use In Choosing Column name
* #param $where : Use In Condition Statement
* #param $table_name : Name of Database Table
* Description : Count all results
*/
function count_all_results($column_name = array(),$where=array(), $table_name = array())
{
$this->db->select($column_name);
// If Where is not NULL
if(!empty($where) && count($where) > 0 )
{
$this->db->where($where);
}
// Return Count Column
return $this->db->count_all_results($table_name[0]);//table_name array sub 0
}
Then Simple Call the Method
Like this
$this->my_model->count_all_results(['column_name'],['where'],['table name']);
If your queries contain a group by, using count_all_results fails. I wrote a simple method to work around this. The key to preventing writing your queries twice is to put them all inside a private method that can be called twice. Here is some sample code:
class Report extends CI_Model {
...
public function get($page=0){
$this->_complex_query();
$this->db->limit($this->results_per_page, $page*$this->results_per_page);
$sales = $this->db->get()->result(); //no table needed in get()
$this->_complex_query();
$num_results = $this->_count_results();
$num_pages = ceil($num_results/$this->results_per_page);
//return data to your controller
}
private function _complex_query(){
$this->db->where('a', $value);
$this->db->join('(subquery) as s', 's.id = table.s_id');
$this->db->group_by('table.column_a');
$this->db->from('table'); //crucial - we specify all tables here
}
private function _count_results(){
$query = $this->db->get_compiled_select();
$count_query = "SELECT count(*) as num_rows FROM (".$query.") count_wrap";
$r = $this->db->query($count_query)->row();
return $r->num_rows;
}
}

Resources