Codeigniter omit where clause for empty criterion - php

I have a page for browsing db records. The viewer can filter records by category, author, and tags. I'm using a form instead of url segments for filtering records (it feels more secure because I can validate inputs.)
For instance, when all form inputs are populated the query looks like this:
SELECT * FROM (`posts`) WHERE `category` = 'technolgy' AND `author` = 'lila' AND `tags` = 'ebook'
However if one input or more is empty, I get no results. For example:
SELECT * FROM (`posts`) WHERE `category` = '' AND `author` = 'lila' AND `tags` = ''
I want the inputs to be optional so for example if just author name is entered, I can return records made by that author regardless of category and tags. How can I omit the and where clause if empty?
Note: or_where clause is not the solution because it doesn't return a precise query if all filter inputs all filled.
My Model
function filter($form_values)
{
$query = $this->db->get('posts');
$this->db->where($form_values); //adds clause to all array items
return $query->result();
}
The function parameter is an array with input values from my view. Example,
$form_values = array('category' => $category, 'author' => $author, 'tags' => $tags);
and my View
$form_values = array (
'category' => $this->input->post('category'),
'author' => $this->input->post('author'),
'tags' => $this->input->post('tags')
);
$this->Records_model->filter($form_values);
I know that in Codeigniter if $_POST' are empty they are set to FALSE. Can that be used to achieve what I'm trying? I'm not sure if I'm on the right track

You are correct that $this->input->post() will return FALSE if the $_POST value is not set. Unless you specifically want IS NULL to be part of the query (which I believe will happen by passing FALSE to param 2 of where(), not 100% sure), just filter out the empty values:
function filter($form_values)
{
$form_values = array_filter($form_values);
// NOTE:
// where() needs to be called first, or your query won't use the WHERE clause
// You may need to make sure there is at least one value in $form_values
if ( ! empty($form_values)) // however you wish to check for a value
{
$this->db->where($form_values); //adds clause to all array items
}
$query = $this->db->get('posts');
return $query->result();
}
http://php.net/manual/en/function.array-filter.php
The important part to note on array_filter():
If no callback is supplied, all entries of input equal to FALSE (see converting to boolean) will be removed.

Related

Array to string conversion error in Code Igniter when inserting array of data into table in database

I'm trying to insert an array of data into a table in database but an error said Array to string conversion error
This is the post function in my controller, first i post an array of data. The values of the array will be the names, and numbers, they are not id. The id is only kodejdwl. This will be pass to my model
function index_post() {
$data = array(
'kodejdwl' => $this->post('kodejdwl'),
'tahun_akad' => $this->post('kode_tahun_akad'),
'semester' => $this->post('semester'),
'mk' => $this->post('mk'),
'ruangan' => $this->post('ruangan'),
'nama_dosen' => $this->post('nama_dosen'),
'namakelas' => $this->post('nama_kelas'),
'jam_mulai' => $this->post('jam_mulai'),
'jam_selesai' => $this->post('jam_selesai'),
);
}
After the data from above code is passed to the model. I created some new variables which are the id of each the name of the value in the array data. e.g if the value of data['mk'] is Website then the id will be 1 and that id will be stored in variable $kodemk and i do it to each value in the data. Then i created new_data which stores array of the id's which i previously made. Then i insert that array into one table in my database. I thought it would be fine but it said Array to string conversion error. What should i do so i could insert that array into the table in my database?
public function insert($data){
$this->db->select('thn_akad_id');
$tahunakad_id = $this->db->get_where('tik.thn_akad',array('tahun_akad'=>$data['tahun_akad'],'semester_semester_nm'=>$data['semester']))->result();
$this->db->flush_cache();
$this->db->select('kodemk');
$kode_mk = $this->db->get_where('tik.matakuliah',array('namamk'=>$data['mk']))->result();
$this->db->flush_cache();
$ruangan = $this->db->get_where('tik.ruangan', array('namaruang' => $data['ruangan']), 1)->result();
$this->db->flush_cache();
$this->db->select('nip');
$nip_dosen = $this->db->get_where('tik.staff',array('nama'=>$data['nama_dosen']))->result();
$this->db->flush_cache();
$this->db->select('kodeklas');
$kodeklas = $this->db->get_where('tik.kelas',array('namaklas'=>$data['namakelas']))->result();
$this->db->flush_cache();
$this->db->select('kode_jam');
$kode_mk = $this->db->get_where('tik.wkt_kuliah',array('jam_mulai'=>$data['jam_mulai'],'jam_selesai'=>$data['jam_selesai']))->result();
$this->db->flush_cache();
$new_data = array(
'kodejdwl' => $data['kodejdwl'],
'thn_akad_thn_akad_id' => $tahunakad_id,
'matakuliah_kodemk' => $kode_mk,
'ruangan_namaruang' => $ruangan,
'staff_nip' => $nip_dosen,
'kelas_kodeklas' => $kodeklas,
);
$insert = $this->db->insert('tik.jadwal_kul', $new_data);
return $this->db->affected_rows();
}
You probably want to use row() instead of result() because it'll contain only one result that you want. If you want to use result() and store multiple values then you'll have to use implode to concatenate them and store it as a string.
I've written a possible solution for your problem; Some things were missing, so I've mentioned them in the comments. See if this helps you.
public function insert($data){
$this->db->select('thn_akad_id');
$tahunakad_id = $this->db->get_where('tik.thn_akad',array('tahun_akad'=>$data['tahun_akad'],'semester_semester_nm'=>$data['semester']))->row(); // use row here
$this->db->flush_cache();
$this->db->select('kodemk');
$kode_mk = $this->db->get_where('tik.matakuliah',array('namamk'=>$data['mk']))->row();
$this->db->flush_cache();
// remove your_ruangan_column with your desired column name
$this->db->select('your_ruangan_column');
$ruangan = $this->db->get_where('tik.ruangan', array('namaruang' => $data['ruangan']), 1)->row();
$this->db->flush_cache();
$this->db->select('nip');
$nip_dosen = $this->db->get_where('tik.staff',array('nama'=>$data['nama_dosen']))->row();
$this->db->flush_cache();
$this->db->select('kodeklas');
$kodeklas = $this->db->get_where('tik.kelas',array('namaklas'=>$data['namakelas']))->row();
$this->db->flush_cache();
// Not sure where this ↓↓ is being used but you can use it the same way as others
$this->db->select('kode_jam');
// duplicate variable name here ↓↓ (fix this)
$kode_mk = $this->db->get_where('tik.wkt_kuliah',array('jam_mulai'=>$data['jam_mulai'],'jam_selesai'=>$data['jam_selesai']))->row();
$this->db->flush_cache();
$new_data = array(
'kodejdwl' => $data['kodejdwl'],
'thn_akad_thn_akad_id' => $tahunakad_id->thn_akad_id, // {$tahunakad_id} consists an object with the key {thn_akad_id}-- table_column_name
'matakuliah_kodemk' => $kode_mk->kodemk, // ...
'ruangan_namaruang' => $ruangan->your_ruangan_column, // ...
'staff_nip' => $nip_dosen->nip, // ...
'kelas_kodeklas' => $kodeklas->kodeklas // ...
);
$insert = $this->db->insert('tik.jadwal_kul', $new_data);
return $this->db->affected_rows();
}
Your are making a total of 7 separate trips to the database. Best practice recommends that you always minimize your trips to the database for best performance. The truth is that your task can be performed in a single trip to the database so long as you set up the correct INSERT query with SELECT subqueries.
I don't know what your non-English words are, so I will use generalized terms in my demo (I've tested this successfully in my own CI project). I am also going to reduce the total subqueries to 3 to reduce the redundance in my snippet.
$value1 = $this->db->select('columnA')->where('cond1', $val1)->get_compiled_select('childTableA');
$value2 = $this->db->select('columnB')->where('cond2', $val2)->get_compiled_select('childTableB');
$value3 = $this->db->select('columnC')->where('cond3', $val3)->get_compiled_select('childTableC');
return (int)$this->$db->query(
"INSERT INTO parentTable
(column1, column2, column1)
VALUES (
($value1),
($value2),
($value3)
)"
);
// to mirror your affected rows return... 1 will be returned on successful insert, or 0 on failure
Granted this isn't using the ActiveRecord technique to form the complete INSERT query, but this is because CI doesn't allow subqueries in the VALUES portion (say, if you were to use the set() method). I am guessing this is because different databases use differing syntax to form these kinds of INSERTs -- I don't know.
The bottom line is, so long as you are fetching a single column value from a single row on each of these sub-SELECTs, this single query will run faster and with far less code bloat than running N number of individual queries. Because all of the variables involved are injected into the sql string using get_compiled_select() the stability/security integrity should be the same.

Session data in Codeigniter

I have a simple program that manages documents' data. A document has a branch_id & subject_id.
Some documents have:
a) Only the branch_id & subject_id is null.
b) Only the subject_id & branch_id is null.
c) Both the branch_id & subject_id.
I need to separate all the files by the above criteria. In my project, I used the following code to do this
if ($this->session->userdata('branch_id'))
$this->db->where('tbl_documents.branch_id', $this->session->userdata('branch_id'));
if ($this->session->userdata('subject_id'))
$this->db->where('tbl_documents.subject_id', $this->session->userdata('subject_id'));
How can I modify above code to fulfill criteria c) mentioned above. Can anyone help me?
Try the Associative array method
if (($this->session->userdata('branch_id')) && ($this->session->userdata('subject_id')))
{
$where = array(
'branch_id' => $this->session->userdata('branch_id'),
'subject_id' => $this->session->userdata('subject_id')
);
}
else if($this->session->userdata('branch_id'))
{
$where = array('branch_id' => $this->session->userdata('branch_id'));
}
else if($this->session->userdata('subject_id'))
{
$where = array('subject_id' => $this->session->userdata('subject_id'));
}
else
{
$where = array('1' => '1'); //You probably don't need this case.
}
$this->db->where($where);
$this->db->get('tbl_documents');
I don't believe you need to do anything.
Let's assume you're asking for all fields from tbl_documents so the "base-line" query statement is
SELECT * FROM tbl_documents
That will not change unless one or both of the if statements are true.
If the first is true, then the query statement becomes
SELECT * FROM tbl_documents WHERE tbl_documents.branch_id = some_branch_id;
However, if the first were false and the second true then the statement would be
SELECT * FROM tbl_documents WHERE tbl_documents.subject_id = some_subject_id;
Should both if conditions be true the query statement would be
SELECT * FROM tbl_documents WHERE tbl_documents.branch_id = some_branch_id
AND tbl_documents.subject_id = some_subject_id;
Doesn't that satisfy the criteria "c"?
The question I have is, what if both conditions are false? Is SELECT * FROM tbl_documents (no WHERE conditions) a query you actually want to run?

Yii2 - Ignore where clause if variable is empty

I have yii2 query with conditional where clause. this is my query :
$query = new Query();
$query->select
(['pengeluaran.id'])
->from('surat_jalan, pengeluaran')
->where('surat_jalan.no_bus=:no_bus',['no_bus'=>$no_bus])
//this is my conditional query
->andWhere(['between', 'pengeluaran.tgl_pengeluaran', $awal, $akhir])
->andWhere('pengeluaran.nama_toko=:nama_toko',['nama_toko'=>$nama_toko])
->andWhere('pengeluaran.metode_pembayaran=:metode_pembayaran',['metode_pembayaran'=>$metode_pembayaran])
->andWhere('pengeluaran.waktu_pembayaran=:waktu_pembayaran',['waktu_pembayaran'=>$waktu_pembayaran])
//this is my conditional query
->andWhere('surat_jalan.id_surat_jalan=pengeluaran.id_surat_jalan');
$command = $query->createCommand();
$data_id_pengeluaran = $command->queryAll();
I read some question from others and what I found is for mysql table field :
->andWhere(['not', ['activated_at' => null]]);
what I want is if the variable is empty, the conditional where() clause is ignore. Is it possible in yii2??
The filterWhere is the perfect tool to achieve your goals.
For example,
// This will not appear in the finally statement if $val is empty.
$query->andFilterWhere(['activated_at' => $val])
Note: A value is considered empty if it is null, an empty array, an empty string or a string consisting of whitespaces only.

Return results when search parameters is null i Zend Lucene

I have multiple fields in search form.Every field could be empty.
I build query like this:
$search_title = trim($_POST["search_title"]);
$search_skill = trim($_POST["search_skill"]);
$search_company = trim($_POST["search_city"]);
$search_country_id = trim($_POST["search_county_id"]);
$hits = $index->find("title:$search_title and skill:$search_skill and city:$search_city and country_id:$country_id");
User can only fill title or skill or city etc. but if some field is empty i have no result.
I have result only if all fields filled and matched.
I wont results if only one field is filled,if is null ignore that field:
$hits = $index->find("title: and skill: and city: and country_id:$country_id");
you might try something like this:
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost)) {
//get filtered and valid values from search form.
//filter the array for set values
$data = array_filter($form->getValues());
//extract key => vaules as $variable = values
extract($data);
$query1 = new Zend_Search_Lucene_Search_Query_MultiTerm();
//test for variable isset and add term to query
if (isset($search_title)){
$query1->addTerm(new Zend_Search_Lucene_Index_Term($search_title, 'title'));
}
if (isset($search_skill)){
$query1->addTerm(new Zend_Search_Lucene_Index_Term($search_skill, 'skill'));
}
if (isset($search_city)){
$query1->addTerm(new Zend_Search_Lucene_Index_Term($search_city, 'city'));
}
if (isset($search_country_id)){
$query1->addTerm(new Zend_Search_Lucene_Index_Term($search_country_id, 'country_id'));
}
//This should give the AND you are looking for...I hope
$query= new Zend_Search_Lucene_Search_Query_Boolean(array($query1), array(TRUE));
//get result set from query
$hits = $index->find($query);
}
}
if you use the StringTrim filter in your forms you won't need to use the trim() function on your data. The $_POST array is dangerous with user supplied data, ZF provides the getValues() series of methods to provide data from the Request Object (POST and GET) the have had filters and validators you specify applied.
I used the extract() function in this instance because I used getValues() so the data has been filtered and validated. There are of course other valid ways to assign key => value pairs to variables. Use your favorite.

How to create php array from mysql result, perform calculation, resort array, present results

I have a photo website on which I am trying to perform a query against a MySQL database. The query is against a concatenated field of 'title' and 'keyword' called 'title_keyword'.
I want to take the search results and sort them by a newly formed variable called 'sort_priority' which is checking to see if the search word is in the 'title' field. If it is in the 'title' field then I want to assign a value of 1 and if not in the title field then a value of 2. The resulting array will be sorted by 'sort_priority' and output to the screen.
Here is the logic I am using with PHP and MySQL:
1) Query the MySQL database and assign variables. (This works just fine)
2) Take the results, assign each field to a variable, create a new variable that performs a calculation on one of the variables returned
$data_array=array();
// get each row
while($row = mysql_fetch_array($result))
{
//get data
$image_id = "{$row['image_id']}";
$title = "{$row['title']}";
$imageurl = "{$row['imageurl']}";
// Create sort_priority to identify if search word is in title field.
//If it is then set to 1 to force this higher in the result list after sorting
$sort_priority = 2;
if(stristr($title,$search))
{ $sort_priority = 1;}
Everything above this point works. Now for the part I'm stumped on. How to create and add data to the array and then sort on my new $sort_priority variable.
Here is what I've written but it just doesn't work**
// Create array and sort by title then keyword (tk_sort)
$data_array = array(
'image_id' => $image_id,
'title' => $title,
'imageurl' => $imageurl,
'sort_priority' => $sort_priority);
// Obtain a list of columns
foreach ($data_array as $key => $row) {
$image_id[$key] = $row['image_id'];
$title[$key] = $row['atitle'];
$imageurl[$key] = $row['imageurl'];
$sort_priority[$key] = $row['sort_priority'];
}
// Sort the data with volume descending, edition ascending
// Add $data as the last parameter, to sort by the common key
array_multisort($sort_priority, SORT_ASC);
// end of array creation and sort
3) Output the newly sorted array to a table
Not sure how to get the data out of it. Do I have to use a loop or something?
You could just let MySQL do the majority of the work. This should work (haven't tried it myself):
SELECT CONCAT_WS('-', `title`, `keyword`) AS search_term,
IF( INSTR(`search_term`, 'your_search_value_here') > 0, 1, 2 ) AS priority_key,
`image_id`, `imageurl`
FROM table_name_here
ORDER BY `priority_key`;
HTH.

Categories