Codeigniter Update Batch Error - php

I tried to find solutions
but i always get this error
You must specify an index to match on for batch updates.
public function editcompanionship()
{
$companionship_id = $this->input->post('companionship_id[]');
$missionary_one_id = $this->input->post('missionary_one_id[]');
$missionary_two_id = $this->input->post('missionary_two_id[]');
$missionary_three_id = $this->input->post('missionary_three_id[]');
$value_batch_update = array();
for($i=0; $i<count($companionship_id); $i++):
$value_batch_update[$i] = array(
'missionary_one_id' => $missionary_one_id[$i],
'missionary_two_id' => $missionary_two_id[$i],
'missionary_three_id' => $missionary_three_id[$i],
'modified' => date('Y-m-d H:i:s', time()),
);
endfor;
$this->db->where('companionship_id',$companionship_id[$i]);
$this->db->update_batch('pcdom_companionship',$value_batch_update);
$this->session->set_flashdata("success",alert("alert-success","Updated Successfully!"));
redirect(base_url('mrec/companionship'));
exit();
}
Can Any body knows?

The 3rd param of method update_batch() is required.
public function update_batch($table, $set = NULL, $index = NULL, $batch_size = 100)
{
....
if ($index === NULL)
{
return ($this->db_debug) ? $this->display_error('db_must_use_index') : FALSE;
}
...

Related

Updating multiple records in database using Codeigniter

Am trying to update multiple records in the database but my case I have a column total, which I want to update to different values. I haven't tried much here but hope I could get a clue on how to go about this.
My controller
public function update_record()
{
$id = ["19821", "19923", "19966", "19967"];
$total = ["8", "118", "90", "100"];
if ($this->some_model->batch_data('records', $total, $id) == true) {
echo "yes";
} else {
echo "no";
}
}
The Model
public function batch_data($table, $data, $where)
{
$this->db->where_in('id',$where);
$this->db->set('total',$data);
$this->db->update($table);
return true;
}
I have not tested this yet but currently looking for a more and efficient way of doing this.
If you still want to update multiple records using the update_batch method, you could first assign the id and total as key-value arrays, then use the update_batch method.
Controller :
public function update_record()
{
$id = ["19821", "19923", "19966", "19967"];
$total = ["8", "118", "90", "100"];
$update_data = [];
foreach ($id as $key => $value) {
$update_data[] = [
'id' => $value,
'total' => $total[$key]
];
}
if ($this->some_model->batch_data('records', $update_data) == true) {
echo "yes";
} else {
echo "no";
}
}
Model :
public function batch_data($table, $data)
{
$this->db->update_batch($table, $data, 'id'); // this will set the id column as the condition field
return true;
}
Output :
// preview query output :
// UPDATE `records`
// SET
// `total` =
// CASE
// WHEN `id` = '19821' THEN 8
// WHEN `id` = '19923' THEN 118
// WHEN `id` = '19966' THEN 90
// WHEN `id` = '19967' THEN 100
// ELSE `total`
// END
// WHERE `id` IN ('19821', '19923', '19966', '19967')
As per my comment. This is a method that combines the array in to key/value pairs and updates them 1x1 wrapped in a transaction (so if one query fails nothing changes).
This is the method I would personally use as I don't like update_batchs internal workings (cases).
$id = ["19821", "19923", "19966", "19967"];
$total = ["8", "118", "90", "100"];
$combined = array_combine($id, $total);
if (count($combined) > 0) {
$this->db->trans_start();
foreach ($combined as $id => $total) {
$this->db->set('total', $total);
$this->db->where('id', $id);
$this->db->update('sometable');
}
$this->db->trans_complete();
return $this->db->trans_status();
}
return true;
Try this, Only for single where condition
Controller:
public function update_record()
{
$tableName = "records";
$id = ["19821", "19923", "19966", "19967"];
$total = ["8", "118", "90", "100"];
$update_data = [];
foreach ($id as $key => $value) {
$update_data[] = [
'id' => $value,
'total' => $total[$key]
];
}
$whereKey = 'id';
$this->$this->some_model->batch_data($tableName, $updateData, $whereKey);
}
Model:
public function batch_data($tableName, $updateData, $whereKey)
{
$this->db->update_batch($tableName, $updateData, $whereKey);
}

How to filter based on I18n content with pagination component?

I have comeup with strange problem in cakephp 3.4. I am running filter query on i18n content like this.
if($this->request->query("q")){
$this->paginate["conditions"][$this->ContractTypes->translationField('title').' LIKE'] = '%'.$this->request->query("q").'%';
}
but following call is ending up in Database error
$records = $this->paginate($this->ContractTypes);
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'ContractTypes_title_translation.content' in 'where clause' SELECT (COUNT(*)) AS `count` FROM contract_types ContractTypes WHERE ContractTypes_title_translation.content like :c0
The paginator's count query is not joing i18n table. What is the best approach to solve this problem.
Thanks in advance,
I have solved this by creating my custom paginator component by editing the paginate function. My paginator contains following code incase somebody else is facing the same problem.
namespace Console\Controller\Component;
use Cake\Controller\Component\PaginatorComponent as BasePaginator;
class PaginatorComponent extends BasePaginator
{
public function paginate($object, array $settings = [])
{
$query = null;
if ($object instanceof QueryInterface) {
$query = $object;
$object = $query->repository();
}
$alias = $object->alias();
$options = $this->mergeOptions($alias, $settings);
$options = $this->validateSort($object, $options);
$options = $this->checkLimit($options);
$options += ['page' => 1, 'scope' => null];
$options['page'] = (int)$options['page'] < 1 ? 1 : (int)$options['page'];
list($finder, $options) = $this->_extractFinder($options);
if (empty($query)) {
$query = $object->find($finder, $options);
} else {
$query->applyOptions($options);
}
$cleanQuery = clone $query;
// My Modification Starts Here
$table = $cleanQuery->repository();
$results = $query->all();
$numResults = count($results);
$count = $numResults ? $cleanQuery->select([
"count"=>$cleanQuery
->func()
->count($table->alias().'.'.$table->primaryKey())
])->first()->count : 0;
// My Modification ends Here
$defaults = $this->getDefaults($alias, $settings);
unset($defaults[0]);
$page = $options['page'];
$limit = $options['limit'];
$pageCount = (int)ceil($count / $limit);
$requestedPage = $page;
$page = max(min($page, $pageCount), 1);
$request = $this->_registry->getController()->request;
$order = (array)$options['order'];
$sortDefault = $directionDefault = false;
if (!empty($defaults['order']) && count($defaults['order']) == 1) {
$sortDefault = key($defaults['order']);
$directionDefault = current($defaults['order']);
}
$paging = [
'finder' => $finder,
'page' => $page,
'current' => $numResults,
'count' => $count,
'perPage' => $limit,
'prevPage' => $page > 1,
'nextPage' => $count > ($page * $limit),
'pageCount' => $pageCount,
'sort' => key($order),
'direction' => current($order),
'limit' => $defaults['limit'] != $limit ? $limit : null,
'sortDefault' => $sortDefault,
'directionDefault' => $directionDefault,
'scope' => $options['scope'],
];
if (!$request->getParam('paging')) {
$request->params['paging'] = [];
}
$request->params['paging'] = [$alias => $paging] + (array)$request->getParam('paging');
if ($requestedPage > $page) {
throw new NotFoundException();
}
return $results;
}
}

Cakephp pagination custom order

I need to set the pagination order of my register based on field ($results[$key]['Movimento']['status']) created in afterFind callback.
afterFind:
public function afterFind($results, $primary = false) {
foreach ($results as $key => $val) {
if(isset($val['Movimento']['data_vencimento'])) {
$data = $val['Movimento']['data_vencimento'];
$dtVc = strtotime($data);
$dtHj = strtotime(date('Y-m-d'));
$dtVencendo = strtotime("+7 day", $dtHj);
if ($dtVc < $dtHj) {
$results[$key]['Movimento']['status'] = 'vencido';
} elseif ($dtVc <= $dtVencendo) {
$results[$key]['Movimento']['status'] = 'vc15dias';
} else {
$results[$key]['Movimento']['status'] = 'aberto';
}
}
if(isset($val['Movimento']['data_pagamento'])) {
$results[$key]['Movimento']['status'] = 'quitado';
}
}
return $results;
Pagination:
$options = array(
...
'order' => array('Movimento.status' => 'ASC')
);
$this->controller->paginate = $options;
$movimentos = $this->controller->paginate('Movimento');
I know this does not work because the field is created after the paginator call.
Can I make it work?
as I understand, you want to sort by data_pagamento and than by data_vencimento (has it the mysql-type date?)
so you don't need your afterFind-function for ordering, simply use:
'order' => array(
'Movimento.data_pagamento DESC',//first all rows with not-empty data_pagamento
'Movimento.data_vencimento DESC',// first all dates in the furthest future
)

Using json encode

I am trying to use json encode for the first time and need some insight to what I am doing wrong.
It should look like this:
{ teams : [ ["2147483647", "9"],["2147483647", "6"],["2147483647", "4"],["11", "2147483647"],["5", "2147483647"],["12", "8"],["10", "3"],["2147483647", "7"], ], results : [ [ [[0, 1],[0, 1],[0, 1],[1, 0],[1, 0],[0, 0],[0, 0],[0, 1],], [[0, 0],[0, 0],[0, 0],[0, 0],], [[0, 0],[0, 0],], [[0, 0],[0, 0]] ] ] }
But the data being returned looks like this:-
{"teams":[["2147483647","10","5","12","11","2147483647","2147483647","2147483647"],["7","3","2147483647","8","2147483647","4","6","9"]],"results":[["0","0","0","0","0","0","0","0"],["0","0","0","0","0","0","0","0"]]}
Code:
public function getAutoCompleteData($tournID, $db)
{
$max = $this->max($tournID);
$one = $this->tourn_info("1on1", $tournID);
$total_matches = $max;
$after_matches = $max / 2;
$matches = $db->query($this->select("*", "matches", "leagueID='{$tournID}' AND league='tourn'"));
while ($row = $db->fetchAssoc($matches)) {
$clan1 = $this->getname($row['clan1'], $tournID, "tourn", $ac = NULL, 1, 1, $wc2 = 0);
$clan2 = $this->getname($row['clan2'], $tournID, "tourn", $ac = NULL, 1, 1, $wc2 = 1);
if ($row['matchno'] <= $after_matches) {
$clan_one[] = $row['clan1'];
$clan_two[] = $row['clan2'];
$score_one[] = $row['score1'];
$score_two[] = $row['score2'];
}
}
$data = array(
'teams' => array(
$clan_one,
$clan_two
),
'results' => array(
$score_one,
$score_two
)
);
return $data;
}
Where it shows teams, it should close the bracket ] every two teams?
Hope someone can help.
Not saying this will fix your problem, but it may help you to understand PHP.
class mustBeAClass{
protected function max($tnid){
// must have this function - can be public for outside method use
}
protected function tourn_info($typ, $tnid){
// must have this function - can be public for outside method use
}
protected function getname($arg0, $arg1, $arg2, $arg3, $arg4, $arg5, $arg6 = 0){
/* must have this function - can be public for outside method use
notice that $arg6 is how you assign default to arguments */
}
public function getAutoCompleteData($tournID, $db){
$db->open();
$max = $this->max($tournID); $one = $this->tourn_info("1on1", $tournID);
// what is the point of this ---->>>> $total_matches = $max;
$after_matches = $max / 2;
// notice query issue below
$matches = $db->query("SELECT * FROM matches WHERE leagueID ='$tournID' && league='tourn'"));
// while loop has problems
if($matches->num_rows < 1){
die('You have no matches');
}
else{
while($row = $db->fetch_assoc()){
$clan1 = $this->getname($row['clan1'], $tournID, 'tourn', null, 1, 1, 0);
$clan2 = $this->getname($row['clan2'], $tournID, 'tourn', null, 1, 1, 1);
if($row['matchno'] <= $after_matches) {
$clan_one[] = $row['clan1'];
$clan_two[] = $row['clan2'];
$score_one[] = $row['score1'];
$score_two[] = $row['score2'];
}
}
$data = array(
'teams' => array($clan_one, $clan_two),
'results' => array($score_one, $score_two)
);
}
$matches->free(); $db->close();
return $data;
}
}
$cls = new mustBeAClass;
echo json_encode($cls->getAutoCompleteData($tournId, $db));
Of course use the correct values for $tournId and your new mysqli(/*args*/) for $db.

Cant pass array value from codeigniter controller to view

Inside my controller, I have a line that needs to pass $content['pass_check'] to the view. It is inside an if statement that checks for validation. This I have found causes it to break. Once I move the $content['pass_check'] outside of any if statement, it works just fine passing to the view. All of the other values are passed (accounts, expense_accounts, vendors, terms). What must I do to get it to pass within this if statement. I've even tried moving it outside of the validation and it still wont set.
function create() {
require_permission("INVOICE_EDIT");
$this->load->library("form_validation");
$this->form_validation->set_rules("invoice_number", "Invoice Number", "required");
if($this->form_validation->run() !== false) {
$post = $this->input->post();
$this->session->set_userdata("create_invoice_vendor", $post['vendor_id']);
$this->session->set_userdata("create_invoice_date", $post['invoice_date']);
$invoice_number_exists = $this->invoices->count(array("invoice_number" => $post['invoice_number'])) > 0;
$post['invoice_date'] = date("Y-m-d", strtotime($post['invoice_date']));
$post['due_date'] = date("Y-m-d", strtotime($post['due_date']));
$post['date_entered'] = "now()";
$id = $this->invoices->insert_invoice($post);
$this->load->model("vendors");
if(isset($post['invoice_number'])){
$string_check= $post['invoice_number'];
$string_check= preg_replace('/\d/', '#', $string_check);
$string_check= preg_replace('/\w/', '#', $string_check);
$invoice_pattern=array();
$invoice_pattern = $this->db->select("invoice_pattern")->where("vendor_id",
$post['vendor_id'])->get("vendors")->result();
$invoice_pattern=$invoice_pattern[0]->invoice_pattern;
* //// THIS IS WHERE I NEED HELP ///////
if($invoice_pattern == $string_check){
***$content['post_check'] = 1;***
$this->invoices->flag_invoice($id);
};
};
$history = array(
"type" => "invoice_entered",
"comments" => "Invoice was entered",
"link" => $id,
"admin_id" => $this->user->admin_id,
"date" => "now()",
);
$this->vendors->insert_history($post['vendor_id'], $history);
if($post['flagged'] == 1) {
$this->invoices->flag_invoice($id);
}
if($invoice_number_exists) {
redirect("invoices/confirm_invoice/".$id);
} else {
// redirect("invoices/view/".$id);
redirect("invoices/create");
}
}
$content['accounts'] = $this->db->get("acct_chart_of_accounts")->result();
$content['expense_accounts'] = $this->db->get("invoice_expense_accounts")->result();
$content['vendors'] = $this->db->select("vendor_id, name, terms, override, invoice_pattern")
->order_by("name ASC")->get("vendors")->result();
$content['terms'] = $this->db->query("SELECT DISTINCT(terms) FROM vendors")->result();
}
}
$this->template['sub_heading'] = "Create";
$this->template['content'] = $this->load->view("invoices/create", $content, true);
$this->template['sidebar'] = $this->load->view("invoices/sidebar", array(), true);
$this->template['scripts'] = array("codeigniter/javascript/invoices/create.js");
$this->template['styles'][] = "codeigniter/styles/invoices/create.css";
$this->display();
}
Obviously it won't pass it to the view if the condition doesn't match, because you're only declaring the variable within the condition if it matches.
Just create $content['pass_check'] with an initial value of 0 or whatever before the conditional check first.
function create() {
...snip...
$content['pass_check'] = 0;
if($invoice_pattern == $string_check) {
$content['post_check'] = 1;
$this->invoices->flag_invoice($id);
};
...snip...
}
Let me know if this works or not please.

Categories