Cakephp custom query pagination - php

I'm trying to use custom query in Cake then paginate the results with the code below:
$query = $this->Petition->query($sql);
I tried:
$petitions = $this->paginate($query);
and it doesn't work. Is there a way we can do this?
OK I wasn't clear enough: I need to use variable array fetched from custom query on pagination so I can use this for pagination in the view. Is there an easy way of doing this?
Below is my code:
function index() {
if ($this->Session->read('Auth.User.group_id') != 1) {
$commune_id = $this->Session->read('Auth.User.commune_id');
$commune_id = $this->Petition->Commune->findbyId($commune_id);
$commune_id = $this->Petition->Commune->find('all',array('conditions' => array('group' => $commune_id['Commune']['group'])));
$count = count($commune_id);
$i=1;
$sql = "SELECT * FROM `petitions` WHERE `commune_id` = ";
foreach($commune_id as $commune_ids){
if($i==1){
$sql .= $commune_ids['Commune']['id'];
}else{
$sql .= " OR `commune_id` = ".$commune_ids['Commune']['id'];
}
/*if($i != $count){
$this->paginate = array(
'or' => array(
array('Petition.commune_id LIKE' => $commune_ids['Commune']['id'] . ","),
//array('Petition.commune_id LIKE' => "," . $commune_ids['Commune']['id'] . ",")
),
'limit' => 10
);
}*/
$i++;
}
$query = $this->Petition->query($sql);
}
$this->Petition->recursive = 0;
$petitions = $this->paginate();
$this->set('petitions', $petitions);
}

you seriously need to read the pagination part in the cake book:
function index() {
$conditions = array();
if ($this->Auth->user('group_id') != 1) {
$commune_id = $this->Petition->Commune->findById($this->Auth->user('commune_id'));
$conditions['Petition.id'] = $this->Petition->Commune->find('list',array(
'fields'=>array('id','id')
'conditions' => array('group' => $commune_id['Commune']['group'])
));
}
$this->Petition->recursive = 0;
$petitions = $this->paginate('Petition',$conditions);
$this->set('petitions', $petitions);
}
something like that.

this is not how pagination works
you need to fill $this->validate with your conditions etc
and then use $this->paginate() plainly
see
http://book.cakephp.org/view/1232/Controller-Setup
also note the chapter about the custom query part if it is really(!) necessary.

Related

Problem in duplication after clicking submit button multiple times

My main problem is with that code in which when I click on submit buttons many times, it inserts duplication many times in the database in which I need to avoid that. Please help me to solve this problem. These are the two tables in which I am trying to insert. mat_ans_options_choose and mat_answer.
$val = $this->input->post(null, true);
$val['id'] = $this->input->post('id');
$val['sub_type'] = $this->input->post('sub_type');
$val['timeout'] = $this->input->post('timeout');
$val['level'] = $this->input->post('level');
$val['mat_category'] = $this->input->post('mat_category');
$option = $val['option'] = $this->input->post('option');
$type = $this->input->post('type');
$marks = [];
$uid = $this->session->userdata('id');
if (isset($val['id']) && isset($option)) {
$query = $this->db->query("SELECT * FROM mat_ans_options WHERE deleted=0 AND active=1 AND question=" . $val['id']);
$result = $query->result_array();
if ($query->num_rows() > 0) {
$count1 = 1;
foreach ($result as $res) {
if ($res['marks'] == 1) {
break;
} else {
$count1++;
}
}
}
// MAT answers options choose
$query1 = $this->db->query("SELECT * FROM mat_ans_options_choose WHERE deleted=0 AND active=1 AND uid=$uid AND q=" . $val['id']);
$result1 = $query1->result_array();
if ($query1->num_rows() > 0) {} else {
$data1 = [
'uid' => $uid,
'q' => $val['id'],
'option_chose' => $option,
'createdon' => $this->general_model->server_time(),
];
$this->db->insert('mat_ans_options_choose', $data1);
}
if ($count1 == $option) {
$marks = 1;
} else {
$marks = 0;
}
// if($marks==1 || $marks==0)
// {
// MAT answers
$query2 = $this->db->query("SELECT * FROM mat_answers WHERE deleted=0 AND active=1 AND uid=$uid AND q=" . $val['id'] . " AND type=" . $type . " AND sub_type=" . $val['sub_type'] . " AND level=" . $val['level']);
$result2 = $query2->result_array();
if ($query2->num_rows() > 0) {} else {
$data = [
'uid' => $uid,
'q' => $val['id'],
'type' => $type,
'level' => $val['level'],
'sub_type' => $val['sub_type'],
'mat_category' => $val['mat_category'],
'marks' => $marks,
'timeoutstatus' => $val['timeout'],
'createdon' => $this->general_model->server_time(),
];
$this->db->insert('mat_answers', $data);
}
// }
return 1;
} else {
return 0;
}
Use JS in which you disable the button after first click - it will work no matter if you are using AJAX or not.
You can use JS/jQuery to limit the number of requests made on the client side. For example by disabling the button on submit:
$("#my-button").prop("disabled", true);
But if the data is sensitive for duplicates (orders, user registration etc) you should make the request limit server side with PHP. You can achieve this by adding a unique index to the tables, either on user id or on a unique token that is submitted with the html form.
Create UNIQUE index in database for uid and q. The database will not insert same question's id from same user's id mulitple times.

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;
}
}

Auto increment Invoice ID in Code-igniter

i am very new to code igniter /php .
Before i was using randomly generated invoice number like
$invoice_no = rand(9999,9999999999);
But now i wanted to increment invoice number and add current year as a prefix to it . But somewhere i am doing wrong as this code failed execute . Can some one point me in the right direction .
My model is ...
function insertInvoice($data)
{
$this->db->trans_begin();
$invoice = array();
if(!empty($data['client_id']))
{
$invoice['invoice_client_id'] = $data['client_id'];
}else{
$client_data = array(
'client_name' => $data['customername'],
'client_address1' => $data['address1']
);
$this->db->insert('client_details', $client_data);
$insert_id = $this->db->insert_id();
$invoice['invoice_client_id'] = $insert_id;
}
$query = $this->db->query("SELECT * FROM invoice ORDER BY invoice_id DESC LIMIT 1");
$result = $query->result_array(0);
$result ++;
$curYear = date('Y');
$invoice_no = $curYear . '-' .$result;
$invoice['invoice_no'] = $invoice_no;
$invoice['invoice_subtotal'] = $data['subTotal'];
$invoice['invoice_tax'] = $data['tax'];
$invoice['invoice_tax_amount'] = $data['taxAmount'];
$invoice['invoice_total'] = $data['totalAftertax'];
$invoice['invoice_total_extra'] = $data['totalextra'];
$invoice['invoice_rent'] = $data['rent'];
$invoice['invoice_paid'] = $data['amountPaid'];
$invoice['invoice_due'] = $data['amountDue'];
$invoice['invoice_desc'] = $data['notes'];
$invoice['invoice_items_count'] = $data['item_count'];
$invoice['invoice_extra_count'] = $data['extra_count'];
$invoice['invoice_miscellaneous'] = $data['miscellaneous'];
$this->db->insert('invoice', $invoice);
$i=1;
do {
$items = array(
'invoice_no' => $invoice_no,
'item_name' => $data['invoice']['product_name'][$i],
'item_price' => $data['invoice']['product_price'][$i],
'item_qty' => $data['invoice']['product_qty'][$i],
'item_total' => $data['invoice']['total'][$i],
'item_noof_crate_wait' => $data['invoice']['noof_crate_wait'][$i],
'item_crate_wait' => $data['invoice']['crate_wait'][$i],
'item_choot' => $data['invoice']['choot'][$i],
'item_net_quantity' => $data['invoice']['net_qty'][$i]
);
$this->db->insert('invoice_items',$items);
$i++;
} while($i<$data['item_count']);
$j=1;
do {
$extraitems = array(
'invoice_no' => $invoice_no,
'extra_item_name' => $data['extra']['name'][$j],
'extra_item_qunatity' => $data['extra']['qty'][$j],
'extra_item_price' => $data['extra']['price'][$j],
'extra_item_total' => $data['extra']['total'][$j]
);
$this->db->insert('extra_items',$extraitems);
$j++;
} while($j<$data['extra_count']);
if ($this->db->trans_status() === FALSE)
{
$this->db->trans_rollback();
return FALSE;
}
else
{
$this->db->trans_commit();
return TRUE;
}
}
invoice_id is primary key in DB .
You're attempting to increment the result array but what you really need is to acquire and increment a field value.
//you only need one field so ask only for that
$query = $this->db->query("SELECT invoice_id FROM invoice ORDER BY invoice_id DESC LIMIT 1");
//you really should check to make sure $query is set
// before trying to get a value from it.
//You can add that yourself
//Asked for only one row, so only retrieve one row -> and its contents
$result = $query->row()->invoice_id;
$result ++;
...
I'm guessing you're getting an "Object conversion to String error" on line $invoice_no = $curYear . '-' .$result;
Since $result contains an object and you're using it as a string. Print the $result variable to check how to use the data assigned to it.

Constructing large PHP query

I'm working with WordPress with custom fields and trying to convert a query which was initially written for pjjtextbase (textfile database) to search a csv file for matching properties for rent/sale.
I understand that to query a custom posts in WP with custom fields I would write something like;
$location = preg_replace('/^-|-$|[^-a-zA-Z0-9]/', '', $_GET['location']);
$type = preg_replace('/^-|-$|[^-a-zA-Z0-9]/', '', $_GET['type']);
$buyrent = preg_replace('/^-|-$|[^-a-zA-Z0-9]/', '', $_GET['buyrent']);
$min_val =preg_replace('/[^0-9]/', '', $_GET['min_val']);
$room_no_min = preg_replace('/[^0-9]/', '', $_GET['room_no_min']);
// This replaces characters in the input string if need be for security reasons
$args =
array(
'post_type' => 'properties',
'meta_query' =>
array(
'key' => 'wp_location',
'value' => $location,
'compare' => '=',
)
);
$results = new WP_Query($args);
But when I look at the code the programmer wrote
/***** THESE VALUES NEEDED FOR SELECT BOX *****/
$locations = ptb_listUnique($info, 'Property_Location');
$property_type = ptb_listUnique($info, 'Property_Type');
$property_buy_rent = ptb_listUnique($info, 'Buy_Rent');
//check property
$query = Array();
if(!empty($_GET['location'])) {
$query[] = "'Property_Location' == '".$_GET['location']."'";
}
if(!empty($_GET['type'])) {
$query[] = "'Property_Type' == '".$_GET['type']."'";
}
if(!empty($_GET['buyrent'])) {
$query[] = "'Buy_Rent' == '".$_GET['buyrent']."'";
}
//check price
if(empty($_GET['buyrent']) || $_GET['buyrent']=="Buy"){
if(!empty($_GET["min_val_buy"]) && is_numeric($_GET["min_val_buy"])){
$min_val_buy = $_GET["min_val_buy"];
}
if(!empty($_GET["max_val_buy"]) && is_numeric($_GET["max_val_buy"])){
$max_val_buy = $_GET["max_val_buy"];
}
$min_val_buy = min($_GET["min_val_buy"], $_GET["max_val_buy"]);
$max_val_buy = max($_GET["min_val_buy"], $_GET["max_val_buy"]);
$query[] = "'Price_Rent' >= '".$min_val_buy."'";
$query[] = "'Price_Rent' <= '".$max_val_buy."'";
}else{
if(!empty($_GET["min_val_rent"]) && is_numeric($_GET["min_val_rent"])){
$min_val = $_GET["min_val_rent"];
}
if(!empty($_GET["max_val_rent"]) && is_numeric($_GET["max_val_rent"])){
$max_val = $_GET["max_val_rent"];
}
$min_val_rent = min($_GET["min_val_rent"], $_GET["max_val_rent"]);
$max_val_rent = max($_GET["min_val_rent"], $_GET["max_val_rent"]);
$query[] = "'Price_Rent' >= '".$min_val_rent."'";
$query[] = "'Price_Rent' <= '".$max_val_rent."'";
}
//check bedrooms
if(!empty($_GET["room_no_min"]) && is_numeric($_GET["room_no_min"])){
$room_min_val = $_GET["room_no_min"];
}
if(!empty($_GET["room_no_max"]) && is_numeric($_GET["room_no_max"])){
$room_max_val = $_GET["room_no_max"];
}
$room_min_val = min($_GET["room_no_min"], $_GET["room_no_max"]);
$room_max_val = max($_GET["room_no_min"], $_GET["room_no_max"]);
$query[] = "'No_Bedrooms' >= '".$room_min_val."'";
$query[] = "'No_Bedrooms' <= '".$room_max_val."'";
//Now build the query to search
$query = implode(' AND ', $query);
It dawned on me that he is not creating multiple queries and then using IMPLODE to combine them but rather creating one whole string then using IMPLODE to add the AND to create the actual query.
The custom fields I have in WP are exactly the same as the large code variable except they are preceded with wp_.
So my question is how do I go about converting his code into a WordPress query?

How to insert multidimentional array to mysql in codeigniter

i have a mysql table with field id,meta_key,meta_value. i want to add multiple metavalue and metakeys when i add any listing, here is my controller code
$listingid=145;
$metakey=array();
$metavalue=array();
if($data['submitlisting'])
{
if($vehicle_make != "")
{
$metakey[]="vehicle_make";
$metavalue[]=$vehicle_make;
}
if($vehicle_mileage != "")
{
$metakey[]="vehicle_mileage";
$metavalue[]=$vehicle_mileage;
}
if($vehicle_year != "")
{
$metakey[]="vehicle_year";
$metavalue[]=$vehicle_year;
}
$data['listingmeta']=$this->Classifieds_model->addmeta($listingid,$metakey,$metavalue,$data);
here is the model code
function addmeta($listingid,$metakey,$metavalue,$data2)
{
$this->load->database();
$data = array(
'classifieds_id' => $listingid ,
'meta_key' => 'location' ,
'meta_value' => 'mangalore'
);
foreach($data2['listingmeta'] as $meta)
$this->db->insert('classifieds_meta',
array(
'classifieds_id' => $listingid ,
'meta_key' => 'location' ,
'meta_value' => 'mangalore'
)
);
}
but the above code doesnt work, please can someone help?
The propest way, it's better to avoid SQL commands in loops :
$insert_batch = array();
for($i=0; $i<count($); $i++)
{
$insert['classifieds_id'] = $listingid;
$insert['meta_key'] = $metakey[$i];
$insert['meta_value'] = $metavalue[$i];
$insert_batch []= $insert;
}
$this->db->insert_batch('classifieds_meta', $insert_batch);
1) Create a simple model function just to insert data array. (always try to frame your model functions such that they can be re-used)
function addmeta($data)
(
$this->db->insert('classifieds_meta', $data);
)
2) Now send the required array to the model through the Controller below
array(
'classifieds_id' => $listingid ,
'meta_key' => 'location' ,
'meta_value' => 'mangalore'
)
$listingid=145;
$metakey=array();
$metavalue=array();
if($data['submitlisting'])
{
if($vehicle_make != "")
{
$metakey[]="vehicle_make";
$metavalue[]=$vehicle_make;
}
if($vehicle_mileage != "")
{
$metakey[]="vehicle_mileage";
$metavalue[]=$vehicle_mileage;
}
if($vehicle_year != "")
{
$metakey[]="vehicle_year";
$metavalue[]=$vehicle_year;
}
$insert = array();
for($i=0; $i<count($metakey); $i++)
{
$insert['classifieds_id'] = $listingid;
$insert['meta_key'] = $metakey[$i];
$insert['meta_value'] = $metavalue[$i];
$this->Classifieds_model->addmeta($insert);
}
}
can try this code into controller:
$ex=count($this->input->post('ex'));
$count =count($this->input->post('ex'));
$data2 =array();
for($i=0; $i<$count; $i++)
{
$data2[] = array(
'ex' => $ex[$i],
);
}
$this->db->insert_batch('table', $data2);

Categories