I have mysql database of products with id, p_name(FULL TEXT), country, company, price. i need to make dynamic search on website. for now i have such problem when i query the result i have to type exact match of name in database. i tried to put %:query% but when i execute the result is empty
Model:
public function getSearchResult($query){
$params = [
'query' => $query,
];
// Prepare statement
$search = $this->db->row("SELECT id, p_name FROM product WHERE p_name LIKE :query", $params);
return $search;
}
Controller:
public function indexAction(){
$result = $this->model->getSearchResult($_POST['search']);
$vars = [
'result' => $result,
];
$this->view->render('Search', $this->vars + $vars);
}
DB Class:
public function query($sql, $params = []){
$stmt = $this->db->prepare($sql);
if(!empty($params)){
foreach ($params as $key => $val) {
if (is_int($val)) {
$type = PDO::PARAM_INT;
} else {
$type = PDO::PARAM_STR;
}
$stmt->bindValue(':'.$key, $val, $type);
}
}
$stmt->execute();
return $stmt;
}
public function row($sql, $params = []){
$result = $this->query($sql, $params);
return $result->fetchAll(PDO::FETCH_ASSOC);
}
You can add % in your array value. Change your model code like below:
public function getSearchResult($query){
$params = [
':query' => '%'.$query.'%', // change this line
];
// Prepare statement
$search = $this->db->row("SELECT id, p_name FROM product WHERE p_name LIKE :query", $params);
return $search;
}
Related
Here is my code
$bindParams = [
'name1' => 'Law',
'name2' => 'King'
];
$sql = "INSERT INTO users (name) VALUES (:name1),(:name2);";
$db->prepared_query($sql,$bindParams);
class Database
{
public function __construct
(
public \PDO $PDO
)
{}
public function prepared_query(string $sql='',$bindParams=[]): bool
{
$stmt = $this->PDO->prepare($sql);
if(count(value:$bindParams) !=0)
{
foreach ($bindParams as $k => $v)
{
$stmt->bindParam(param:":$k",var:$v);
}
}
$x = $stmt->execute();
if($x)
{
return true;
}else{
return false;
}
}
}
The problem I am facing is that in the foreach loop the second value from array $bindParams having key name2 and value king is overriding $stmt->bindParam and only name2 king is inserted in the database. And for every insert I am getting king in database. Here is screen shot of database. How can I insert both records from array sucessfully without repetition.
You can simply pass the parameter in execute(). There is no need to use bindParam() which binds by reference and will overwrite your values inside a loop.
Replace your code with this:
public function prepared_query(string $sql, array $bindParams=[]): void
{
$stmt = $this->PDO->prepare($sql);
$stmt->execute($bindParams);
}
If you really want to have a loop, which you really do not need, then you have to bind by value and not by reference. e.g.
public function prepared_query(string $sql, array $bindParams = []): void
{
$stmt = $this->PDO->prepare($sql);
foreach ($bindParams as $param => $var) {
$stmt->bindValue($param, $var);
}
$stmt->execute();
}
I have two controller functions both need one model function but when I pass parameters to single model function it shows me an error, I need help if there is another method to pass parameters
Controller
public function view_files()
{
$assignment_id='1255';
$data['files'] = $this->AdminModel->getRows111();
$this->load->view('admin/view_files', $data);
}
function download_test1(){
$id = $this->uri->segment(3);
if (empty($id)){
redirect(base_url());
}
$data = $this->AdminModel->getRows111($id);
$filename =$data['assignment_file_name'];
$fileContents = file_get_contents(base_url('upload/'.
$data['assignment_file_name']));
force_download($filename, $fileContents);
}
Model
public function getRows111($id=''){
$this->db->select('*');
$this->db->where('assignment_id','1255');
$this->db->from('tbl_assignments_files');
if($id){
$this->db->where('assignment_file_id',$id);
$query = $this->db->get();
$result = $query->row_array();
}else{
$query = $this->db->get();
$result = $query->result_array();
}
return !empty($result)?$result:false;
}
}
function 1
$data['files'] = $this->AdminModel->getRows111(assignment_id);
function 2
$data = $this->AdminModel->getRows111($id);
model by doing this, shows error
public function getRows111($id='',$assignment_id){
public function getRows111($id='',$assignment_id=""){
$this->db->select('*');
$this->db->from('tbl_assignments_files');
//if assignment_id is not empty it will add where clause to statement
if($assignment_id != ""){
$this->db->where('assignment_id',$assignment_id);
}
//if id is not empty it will add where clause to statement
if($id != ""){
$this->db->where('assignment_file_id',$id);
}
$query = $this->db->get();
$result = $query->result_array();
return !empty($result)?$result:false;
}
}
To call model function first parameter will be $id and second will be $assignment_id
To call model function by $id
$data = $this->AdminModel->getRows111($id);
OR
$data = $this->AdminModel->getRows111($id,'');
To call function by $assignment_id
$data = $this->AdminModel->getRows111("",$assignment_id);
To call function by both $id and $assignment_id
$data = $this->AdminModel->getRows111($id,$assignment_id);
Hope this helps!
you are using your function wrong,
base on the function getRows111 it does have 2 parameters need the $id and $assignment_id
proper used would be like this,
$this->AdminModel->getRows111($id, $assignment_id);
I suggest for your function to make it more flexible is this.
public function getRows111($array){
$id = $array[0];
$assignment_id = $array[1];
}
then call the function using with array parameter
$this->AdminModel->getRows111([$id, $assignment_id]);
to handle the array and you want it to be more flexible.
public function getRows111($array){
$id = isset($array['id']) ? $array['id'] : "";
$assignment_id = isset($array['assignment_id']) ? $array['assignment_id'] : "";
}
call the function like this
$this->AdminModel->getRows111(
['id' => $id,
'assignment_id' => $assignment_id
]);
// if you want just the id
$this->AdminModel->getRows111(['id' => $id]);
// or the the assignment id
$this->AdminModel->getRows111(['assignment_id' => $assignment_id]);
This is my model function:
public function getAllArticles(){
$stmt = $this->mysqli->prepare("select * from articles where 1 = 1");
$stmt->execute();
$stmt->bind_result($id, $name, $title, $excerpt, $content, $created_at, $updated_at);
return $stmt;
}
I'm trying to return the mysqli statement as my function return to assign it as a function call value to a variable inside this function:
public function index(){
$model = new IndexModel();
$out = $model->getAllArticles();
Template::render('index', THEME_FOLDER, ['results' => $out]);
}
And this is the render function which tries to return the correct theme:
public static function render($theme, $base_folder = THEME_FOLDER, $var = null){
$theme = str_replace('.php', '', $theme);
if(!self::theme_exists($theme, $base_folder))
die("Template {$theme}.php could not be found in the {$base_folder} Directory.");
require_once ($base_folder . $theme . '.php');
}
And this is index.php, where I try to loop over $var['results']->fetch() but O got this every time:
Notice: Undefined variable: name in C:\xampp\htdocs\wiche\theme\index.php on line 15
And this is index.php:
<?php
$statement = $var['results'];
while ($statement->fetch()){
echo $name;
}
?>
PS: When I use $stmt->fetch() in IndexModel.php (getAllArticles()) I could get the proper results. but when I return $stmt as function call value, I could not use the returned mysqli statement with fetch() function:
public function getAllArticles(){
$stmt = $this->mysqli->prepare("select * from articles where 1 = 1");
$stmt->execute();
$stmt->bind_result($id, $name, $title, $excerpt, $content, $created_at, $updated_at);
//return $stmt;
while ($stmt->fetch()){
echo $name;
}
}
Thanks in advance.
bind_result sets the variables in the local scope of the function. You are not returning the variables correctly. You are only returning $stmt. You need to fetch the results in the function and then to return the result. An example:
$results = [];
while ($stmt->fetch()){
$results[] = [
'name': $name,
];
}
return $results;
So you are currently trying to access a variable outside of the function in which the variable is defined. (bind_results is setting the variables).
Here is a link to the PHP docs about scopes: http://php.net/manual/en/language.variables.scope.php.
$db->select("users")->where(array("username", "=", "username"));
$db->update("users", array("username" => "username", "password" => "12345"))->where(array("id", "=", "14"));
Ok, I want to write the statements like above, by chain the where() method onto select, update and delete.
My problem is; how to determine if I used the select, update or delete before the where, so I can bind the right values onto the right statement.
I want something like this:
public function where() {
if($this->select()) {
// so if $db->select("users")->where(array("username", "=", "username"));
// save the where data in the select variable.
}
elseif($this->update()) {
// so if $db->update("users", array("username" => "username", "password" => "12345"))->where(array("id", "=", "14"));
// save the where data in the update variable.
}
elseif($this->delete()) {
// so if $db->delete("users")->where(array("username", "=", "username"));
// save the where data in the delete variable.
}
}
But the code above is of course not valid, and I dont use any frameworks.
public function select($table, $what = null) {
$what == null ? $what = "*" : $what;
$this->_select = "SELECT {$what} FROM {$table}";
return $this;
}
You would have to maintain that state. It's not about telling whether the previous call was a select() or an update(), that's the wrong way to think about the problem. You just need each of select/update/delete to modify $this, so that $this, always knows what kind of query it's building.
A dead simple example:
public function select() {
$this->kind == 'select';
return $this;
}
public function where() {
if ($this->kind == 'select') {
...
return $this;
}
The only thing that your chained methods share is that they each return $this, so that a subsequent method can be chained onto the end. It's all about storing up state in $this until some final method call actually evalates the built-up query.
Something like:
public function select($table, $fields = '*')
{
$this->query = "SELECT {$fields} FROM `{$table}`";
return $this;
}
public function where($conditions = [])
{
if ($this->query)
{
if ($conditions)
{
foreach ($conditions as $key => &$val)
$val = "`{$key}` = '{$val}'";
$this->query .= ' WHERE ' . implode(' AND ', $conditions);
}
$db->query($this->query);
$this->query = '';
return $this;
}
}
This would work, however, you have to notice that this structure would allow you to do things like:
$db->where();
This is perfectly valid even though doesn't make sence to call where() in the database directly.
Also, queries that don't require a WHERE clause would not run, because only where() actually makes the call.
How to solve this?
We can actually use a very interesting mechanic of OOP: The destructor method. PHP destroys objects immediately after they are no longer in use, and we can explore this feature here as a trigger to run the query. We only have to separate the query to a new object.
class dbQuery
{
private $db;
private $conditions = [];
function where($conditions = [])
{
$this->conditions = array_merge($this->conditions, $conditions);
return $this;
}
function __construct($db, $query)
{
$this->db = $db;
$this->query = $query;
}
function __destruct()
{
if ($this->conditions)
{
foreach ($this->conditions as $key => &$val)
$val = "`{$key}` = '{$val}'";
$this->query .= ' WHERE ' . implode(' AND ', $this->conditions);
}
$this->db->result = $db->query($this->query);
}
}
class Database
{
public $result = null;
protected static $instance;
function __construct()
{
if (!self::$instance)
self::$instance = new mysqli('localhost', 'user', 'password', 'dbname');
}
public function query($query)
{
return self::$instance->query($query);
}
public function select($table, $fields = '*')
{
return new dbQuery($this, "SELECT {$fields} FROM `{$table}`");
}
}
This way $db->where() won't work as it doesnt exist, and using $db->select('table') or $db->select('table')->where([...]) will both give results, and even allows extending the syntax to use where() multiple times like:
$db->select('table')->where(['id' => 100])->where(['price' => 1.99]);
I have a form filter with few custom search fields.
In the addXXXQuery functions, I have to use join on a table which is the same for some fields.
Can I check if innerJoin for that particular table is already set in another addXXXQuery?
[EDIT] example:
public function addIsPaidColumnQuery(Doctrine_Query $query, $field, $values)
{
if ($values) {
$rootAlias = $query->getRootAlias();
$query->leftJoin($rootAlias.".Inscription i");
->andWhere("i.is_paid = ?", $values);
}
}
public function addActTypeColumnQuery(Doctrine_Query $query, $field, $values)
{
if ($values) {
$rootAlias = $query->getRootAlias();
$query->leftJoin($rootAlias.".Inscription i")
->leftJoin("i.Act a")
$query->addWhere("a.act_type_id = ?", $values);
}
}
Well, you can retrieve the $params from the query, and check if the join is already there, something like this:
public function addIsPaidColumnQuery(Doctrine_Query $query, $field, $values)
{
if ($values)
{
$rootAlias = $query->getRootAlias();
$leftjoin = $rootAlias.".Inscription i";
$params = $query->getParams();
if (!isset($params['join']) || (isset($params['join']) && !in_array($leftjoin, $params)))
{
$query->leftJoin($leftjoin);
}
$query->andWhere("i.is_paid = ?", $values);
}
}
You can see in the code, how a leftJoin in added.
I couldn't find a method, that would tell me if a join for a table is set. However the more I thought about the existence of such method, the less sence it made for it. So to check if I already used a join in the filter query I set a class variable $leftJoinInscriptionSet.
private $leftJoinInscriptionSet = false;
...
public function addIsPaidColumnQuery(Doctrine_Query $query, $field, $values)
{
if ($values) {
$this->setLeftJoinInscription($query);
$query->andWhere("i.is_paid = ?", $values);
}
}
...
private function setLeftJoinInscription(Doctrine_Query $query) {
if (!$this->leftJoinInscriptionSet) {
$rootAlias = $query->getRootAlias();
$query->leftJoin($rootAlias.".Inscription i");
$this->leftJoinInscriptionSet = true;
}
}