Database class with filters - php

I'm building my own CMS and I used my own Database class for it.
In some frameworks there is a way to do a function on another function
$firstValues = $this-db->query('your query')->first();
What do I kind of class do I need for the ->first().
Is there a way in php to do this? Do I need to use an Abstract class? Does anybody has an example?
If you need any more information, please ask me!
Thanks for helping!
Tom

What do I kind of class do I need for the ->first().
Most frameworks provide a "Query Builder" class to generate and execute SQL statements without writing SQL manually.
Is there a way in php to do this?
Yes, just pick a query builder:
https://github.com/cakephp/database
https://github.com/illuminate/database
Do I need to use an Abstract class?
No
Does anybody has an example?
Illuminate Database (Laravel):
$userRow = Capsule::table('users')->where('votes', '>', 100)->get();
CakePHP:
$userRow = $connection->newQuery()
->from('users')
->select('*')
->where(['votes >' => 20])
->execute()
->fetch('assoc');
Under the hood the first() method just fetches the first row.
PDO example:
$statement = $pdo->prepare("SELECT * FROM users WHERE votes > :votes LIMIT 1");
$statement->execute(['votes' => 20]);
$userRow = $statement->fetch();

You have to pass $this between methods.
Here's some example:
Class Db {
private $_query_result;
public function query($query_string = '')
{
// make your query or smth
// save for example array of results
$this->_query_result = $your_query_result;
return $this;
}
public function first()
{
return array_shift($this->_query_result);
}
}

Related

MVC/PDO : how to build a model using PDO's prepared statements syntax?

I want to build a model class for my PHP application. It will have methods meant to select/update/insert/delete specific data from a database according to the method's parameters. I only want to use prepared statements.
Here is an overview of what the class should look like :
class Database {
private $_db;
// Stores a PDO object (the connection with the database) within the $_db property
public function __construct($host, $user, $password) {...}
public function select() {...}
public function update() {...}
public function insert() {...}
public function delete() {...}
}
The problem is that I don't really know how to do this. Let's say I want to select everything from the table "farm" where the animal is a dog. The syntax for this statement would be the following :
$animal = 'dog';
$query = $this->_db->prepare('SELECT * FROM farm WHERE animal = :animal');
$query->execute(array(':animal' => $animal));
$result_set = $query->fetchAll();
This is very complicated to implement within a class method. As you can see, I call the execute() method but I don't even know in advance if the WHERE clause will be used !
And even worse : what if I will want to use, let's say, the LIMIT x, y clause later on ?
Which parameters should I ask for and how to treat them ? Should I simply require the parameters to be one query + multiple variables that will be passed to the execute() method ?
Are these types methods reasonable for what I want to do ? Maybe I should to a dedicated method for each MySQL query the application will perform, but this is quite complicated because it's a big database and a big application.
What do you guys think ?
Thanks in advance :P
Your API looks pretty useless to me, because as I see it it's just a wrapper around PDO. What do you gain by wrapping PDO like that?
Instead it would probably make more sense to have your object actually representing things, e.g.:
namespace Project\Storage\Database;
class Farm
{
private $pdo;
public function __construct(\PDO $pdo)
{
$this->pdo = $pdo;
}
public function getAnimalsByType(string $animalType): AnimalCollection
{
$stmt = $this->pdo->prepare('SELECT * FROM farm WHERE animal = :animal');
$stmt->execute([
'animal' => $animalType,
]);
// alternatively use a factory to build this to prevent tight coupling
return new AnimalCollection($stmt->fetchAll());
}
}
On a side note: forget about MVC in PHP (it's not even possible). Just focus on the more important separation of concerns.
Maybe I should to a dedicated method for each MySQL query the application will
perform, but this is quite complicated because it's a big database and
a big application.
Yes, this is an easy way to organize your database access.
But you should not put ALL of them in the same class. You should separate your classes by their domain.
class animalRepository {
// ...
public function getAnimalByName($animal){
$query = $this->_db->prepare('SELECT * FROM farm WHERE animal = :animal');
$query->execute(array(':animal' => $animal));
$result_set = $query->fetchAll();
// ...
}
}
To make this communicate more clearly you could call those classes repositories, as they are storing the data for the specific domain.
Another common name would be mappers, because they are mapping the data to your objects.
Very opinionated answer. Anyway:
PDO's Prepared Statements are a little more capable than being created and calling execute on them. How you would usually do this is by first building your query and then binding the values:
$querystring = 'SELECT * FROM farm';
$args = array();
if($animal != '') {
$querystring .= 'WHERE animal = :animal';
$args[':animal'] = $animal;
}
$query = $this->_db->prepare($querystring);
$result = $query->execute($args)
if($result !== false) {
// fetch ...
} else {
// error output / return val
}
This is the general idea. Depending on your input parameters you build a query. It will probably become more sophisticated than that, for example filling a $where = array() and then you add to the $where[] = ... your where conditions and in the end you just join them all together with sql AND:
$this->_db->prepare($querystring.
( count($where) > 0 // the > 0 is redundant btw
? 'WHERE '.implode('AND',$where)
: '' )
);
You might similar things with joined tables, select statements and the like. It can get very complex. It's probably wise to mix this approach with separating at sensible points with Philipp's answer/approach.

How to create a query in Drupal 8

I am used to using db_select in drupal 7 but now it's deprecated in drupal 8
So, If I need to create a query to list all users from users_field_data table, What should I do?
Do I still use db_select or db_query even though they are deprecated functions? Or create a new controller to extend from "Select class" and make my query?
Depends on what you are trying to achieve.
Using the storage object
If you want to make a simple query about the users then you should use the loadByProperties of the storage object
$users = \Drupal::entityTypeManager()->getStorage('user')->loadByProperties([
'name' => 'bar'
]);
Using entity query & loadMultiple
If you need a more complex query with sorts, range, pager and OR/AND condition groups you should use entity query
$ids = \Drupal::entityQuery('user')->condition('name', 'foo')->execute();
$users = User::loadMultiple($ids);
As mentioned in the documentation you can query data by injecting Drupal's database connection class. For example:
use Drupal\Core\Database\Connection;
class DatabaseQueryExample {
protected $connection;
public function __construct(Connection $connection) {
$this->connection = $connection;
}
public function queryExamples() {
// db_query()
$this->connection->query(" ... ");
// db_select()
$this->connection->select(" ... ");
}
}
db_select, db_insert, db_update, etc... were deprecated in Drupal 8.0.x and will be removed in Drupal 9.0.0.
Instead get a database connection injected into your service from the container and call select() on it. For example, $injected_database->select($table, $alias, $options);.
eg:
$db = \Drupal::database();
$data = $db->select('table_name','t')->fields('t')->execute();
$db->insert();
$db->update();

CakePHP, Query from Model

How I can execute a SQL query in CakePHP.
I want to make some like this code
$employees = $this->Employee->find('all');
but introducing my own SQL statment.
Insert into your Model a function that executes your SQL statment,
public function get_employees() {
$sql = 'select * from employees';
$data = $this->query($sql);
return $data;
}
And call this function like this way:
$employee = new Employee();
$data = $employee->get_employees();
In model you can't write model name. Its already detected. Use only
$this->find('all');
Assuming your statement is inside EmployeesController.php
$employeeRows = $this->employee->find('all', array('conditions'=>array('id' => 100)));
if you are in another controller, you have to load the model before the find
$this->loadModel('employee');
if you are in a view, you can write a helper and use raw sql
The cakephp website also offers the following controller logic
$this->Picture->query("SELECT * FROM pictures LIMIT 2;");

Does get_where() allow multiple parameters?

I am passing a parameter from model to view like this
Model
class school_model extends CI_Model{
function employee_get($student_id){
$query = $this->db->get_where('students', array('student_id'=>$student_id));
return $query->row_array();
}
}
Controller
function bret($student_id){
$this->load->model('school_model');
$data = $this->school_model->employee_get($student_id);
echo $data['student_gender'];
}
This obviously translates to select * from students where id=id given for example and seen through the browser like http://example.com/env/at/index.php/frontpage/bret/306
I am wondering if the get_where() is suitable if i wanted to have this query
select student_gender,student_has_a_medical_condition from students where (student_gender = 'female' && student_has_a_medical_condition = 'no') LIMIT 40;
Will i need to extend get_where() for it to work?.
First,I suggest reading the excellent documentation for CodeIgniter on the ActiveRecord class.
You don't have to extend get_where() but just use the existing methods to define your query:
function employee_get($student_id){
$this->db->select('student_gender','student_has_a_medical_condition');
$query = $this->db->get_where('students', array('student_id'=>$student_id,'student_has_a_medical_condition'=>'no','student_gender'=>'female'),40);
return $query->row_array();
}
Of course you can pass in the additional parameters to the function so they are not hardcoded, and you can also pass in the desired columns as a paremeter, too. But start with the documentation.

Zend framework current method to get single row

i'm new to zend framework, in this simple function i want to get a single 'post' and then i want to find all the comments in the related table
public function getPost($idPost)
{
$db= Zend_Registry::get('db');
$select=$db->select()
->from($this->_name, '*')
->where("idPost= ".$db->quote($idPost, 'INTEGER'));
$stmt=$select->query();
$rowset=$stmt->fetchAll();
$post=$rowset->current();
//ora devo aggiungerci i commenti che questo post ha ricevuto
$comm=$post->findDependentRowset('commenti');
$ris=array($post, $comm);
return $ris;
}
in my index controller i i simply call this function, but i get this error:
Call to a member function current() on a non-object in C:\xampp\htdocs\...
where's the mistake?
I think you have a few misconceptions about how you're using Zend_Db.
1. You're not using the ORM, just the PDO wrapper
Which means, your queries won't return Zend rowsets and rows and therefore you can't use the methods of you can use on those.
2. The default fetch mode
The default fetch mode of the Zend_Db_Statement fetchAll() method is array, if you want it to return an object (stdClass), change the fetch mode before fetching the data:
$stmt->setFetchMode(Zend_Db::FETCH_OBJ);
3. Using fetchAll() when you actually want one row
If you just want one row, then don't fetch a whole table! With Zend_Db_Statement, use for example:
$row = $stmt->fetch();
or
$rowObj = $stmt->fetchObject();
... again, that's not a zend row object, just a stdClass instance, but you can do:
$rowObj->some_field;
on it.
On the other hand, if this is a method in your Post model, it should look something like:
public function getPost($idPost)
{
return $this->getRow($idPost);
}
This will return the post, then, if you've setup the table relationships correctly, you can also query for the dependent data or just get all comments with that id separately.
The problem is that unless you define a table class as was previously mentioned you can't uuse the dependent or parent rowsets.
To make your current function work would be best done with two functions, and keep it simple:
public function getPost($idPost)
{
$db= new Zend_Db_Table($this->_name);
$select=$db->select()
->where("idPost= ?", $idPost);
/*Fetch just the row you want, or use fetchAll() if you need to match return types*/
$row = $db->fetchRow($select);
return $row;
}
public function getComments($table='comments', $id) {
$db = new Zend_Db_table($table);
$select = $db->select()->where('post_id = ?', $id)->order('date ASC');
$rowset = $db->fetchAll($select);
return $rowset/* or you could return an array ->$rowset->toArray() */
}
Zend_Db_Table is going to attempt to use the current database adapter, so all you need to do is pass in the tablename.
One more note: you don't need to use any of the quote() function when using select() it's taken care of.
But it is really important, that if you are going to use Zend_Db, you need to learn about "Defining table classes". At least enough to use them in your own classes.
I hope this helps!
To get a rowset and dependent rowset you have to use Zend_Db_Table.
You only use the Zend_Db_Adapter with Zend_Db_Select.
Read from here.
So you have to define a class which extends from Zend_Db_Table_Abstract.
Example:
class Bugs extends Zend_Db_Table_Abstract
{
protected $_name = 'bugs';
protected $_primary = 'bug_id';
}
To get the Zend_Db_Table_Rowset object use:
$bugs = new Bugs();
$rowset = $bugs->fetchAll("bug_status = 'NEW'");
To find dependent rowsets you have to define the relation in your table class. Look here how to define relationships.

Categories