Why can't i use an attribute containing mysqli object? - php

i kinda faced a problem recently that i wasn't able to figure out its solution .
I have a core class that contains the follow code in its constructor:
public function __construct()
{
$this->runDatabaseConnection();
$this->fetchSettings();
}
private function runDatabaseConnection()
{
global $config;
$this->db = new mysqli($config['db']['server'], $config['db']['user'], $config['db']['password'], $config['db']['name']);
$this->db->set_charset($config['db']['charset']);
}
As you can see i stored the object in an attribute called "db"
After that , I made a method in the same class that runs a given query:
public function query($queryStr)
{
return $this->db->query($queryStr) or die($this->db->error.($this->debugMode ? '<br><b>Query: </b><i>'.$queryStr.'</i>' : ''));
}
Now outside class, When i use something like:
$studentsQuery = $core->query("SELECT * FROM ".TP."students");
$studentsQuery variable seems to be a boolean value and not the ressource that i was expecting , So what am i missing ? Thanks in advance .

You are returning a result of boolean expression.
return $this->db->query($queryStr) or die());
So what I assume you wanted to do was
public function query($queryString)
{
$result = $this->db->query($queryString);
if (!$result) {
die(...);
}
return $result;
}

Related

PHP equivalent to C++ Templates

In C++, I can create template classes like this:
<template class l> class foo {
private:
l myVar;
foo::foo(l var) {
myVar = var
}
l getVar() {
return myVar
}
// etc...
}
Can I do something similar in PHP?
Reason I'm asking:
Let's say I have a class in PHP that conceptualizes a MySQL table:
class Table {
private $conn;
private $name;
function __construct($connection, $tablename) {
$this->conn = $connection;
$this->name = $tablename;
}
// etc..
}
I can make class functions that handle certain types of queries:
function GetAll() {
$sql = "SELECT * FROM " . $this->name;
$data = $this->conn->query($sql);
return $data;
}
Of course, this is just an example, but hopefully you get the picture.
What I'm looking to do is let's say I have a class called "Users". Before I return $data, I would like to put it in a User object. Of course, to be generic, I'd like to be able to put it into ANY class I like. Just like a C++ template.
Note: A PHP interface will not work for this because I'd need to instantiate the class, not just use a given set of functions.
Edit:
So, I found a workaround for MY problem.
However, I'd still like an answer to whether there is a PHP equivalent.
So, I figured out a work around, but I would still appreciate other answers. I would still like to know if there is a PHP equivalent. However, this is what I've got:
class Table {
private $conn;
private $name;
private filter; // a callback
function __construct($connection, $tablename, $callback) {
$this->conn = $connection;
$this->name = $tablename;
$this->filter = $callback;
}
// etc..
}
And then in GetAll:
function GetAll() {
$sql = "SELECT * FROM " . $this->name;
$data = $this->conn->query($sql);
$data = $this->filter($data);
return $data;
}
Then, I could pass a callback that filters the data how I want it.
I think that will work.

Instance of PDO in class connector

I'm working on a project today and i've been working for a while now and i don't see what i do wrong here. Can someone give me the right example.
Thnx a lot!
Connector:
class Repository
{
private $connector;
public function __construct(Config $connector)
{
$this->connector = $connector;
}
public function events()
{
$query = 'SELECT * FROM digi_gz_parties';
$dbh_query = $this->connector->getDatabase()->prepare($query);
$dbh_query->execute();
$dbh_querys = $dbh_query->fetchAll();
return $dbh_querys;
}
}
Getter:
class REST
{
public function getEvents()
{
require 'logic/Repository.php';
$event = new Repository();
$events = $event->events();
return $events;
}
}
Error:
Argument 1 passed to Repository::__construct() must be an instance of Config.
I know i need to give a paramater to the repository but i don't want it, i want only to call the repository without give some paramter.
Thanks a lot!
You can change your Repository::__construct() to have a default $connector to null:
public function __construct(Config $connector = null)
{
$this->connector = $connector;
}
That way, if you instanciate your object without any parameter, like you do here, it will default to null. The only downside of that is that, now, you have to be extra careful when using $this->connector inside your Repository class and remember it could be null.
For exemple, here, the second line of your events() method is not going to work, because you lack the proper configuration to connect to your database.

PDO fetch single class not working

i am making a database abstraction class that binds objects like an ORM. I'm having issue with a particular case, fetching a single row and binding to a class. While the same is working well with fetchAll() i can't figure out why using fetch(PDO::FETCH_CLASS) the object returns null.
if i use PDO::FETCH_LAZY it works, but isn't a correct binding to the passed class.
Here the code.
The Database() class is connects to db using PDO. Products() is a class made of public attributes with same name of tables.
The controller:
public function editProducts($params) {
$products = new Products();
$db = new Database ();
$id = array_keys($params);
$products = $db->findById($products, $id[0]); // auto Bind object fetched=no and POST params?
$this->template = new Template();
$this->template->renderArgs("product", $products);
$this->template->renderArgs("page_title", "Edit product " . $products->title);
$this->template->render(get_class($this), "editProducts");
}
The DB class:
public function findById($object,$id) {
try {
$table = $this->objectInjector($object);
} catch (Exception $e) {
if (APP_DEBUG) {
d($e->getTrace());
}
return;
}
$statement = "SELECT * FROM $table WHERE id=:id";
$this->stm = $this->pdo->prepare($statement);
$this->bindValue(":id",$id);
return $this->fetchSingleObject($object);
}
the method that abstract fetch:
public function fetchSingleObject($object) {
$this->execute();
$this->stm->setFetchMode(PDO::FETCH_CLASS, get_class($object));
return $this->stm->fetch(PDO::FETCH_CLASS);
//return $this->stm->fetch(PDO::FETCH_LAZY); this works!
}
I missed something? the fetchAll() works nicely in this way:
public function fetchObjectSet($object) {
$this->execute();
$this->stm->setFetchMode(PDO::FETCH_CLASS, get_class($object));
return $this->stm->fetchAll(PDO::FETCH_CLASS);
}
Thank you so much.
PS: some methods like $this->execute() are just abastractions to pdo->statment method since pdo and stm are db class instance variables.
I found the answer to the question by myself, i post the answer for everyone.
Instead of using directly PDO::FETCH_CLASS, $Class, i switched using setFetchMode() passing PDO_FETCH_INTO, new $Object instance.
This return correctly new instance of given object (with object methods and fields). Works well with public attributes and overloaded constructors.
The previously statement "findAll() works" wasn't true, i was returning somehow like FETCH_OBJ, an object representation of the database table.
Here the solution:
public function fetchSingleObject($object) {
$this->stm->setFetchMode(PDO::FETCH_INTO, new $object());
$this->execute();
return $this->stm->fetch();
}
Return a new instance of passed in object.
Works also as fetchAll()
EDIT:
public function fetchObjectSet($object) {
$this->execute();
return $this->stm->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, get_class($object));
}
The manual states:
bool PDOStatement::setFetchMode ( int $PDO::FETCH_CLASS , string
$classname , array $ctorargs )
so perhaps try:
$this->stm->setFetchMode(PDO::FETCH_CLASS, 'get_class', $object );/* is $object an array ? */
or, without
$this->stm->setFetchMode(PDO::FETCH_CLASS, 'get_class' );

Attempt to assign property of non-object error

I am getting this error and i can't see what i am doing wrong. I have done the same thing with other objects from other classes which are built in the exact same way and i can't see why i am getting this error now.
The code in which i create the object is this one:
$consulta2 = "SELECT * FROM TiposDireccion WHERE Cliente_CIF='$cif' and Direccion_Direccion='$direccion' and Direccion_CP=$cp ";
echo($consulta2."</br>");
if ($resultado2 = $conexion->query($consulta2)){
while($fila2 = $resultado2->fetch_object()){
$tipodireccion78=$fila2->TipoDireccion_Tipo;
//we see here that the select is returning a correct string with a correct value
echo($tipodireccion78);
//we try to instantiate and it fails =(
$unTipoDireccion=TipoDireccion::constructor1($tipodireccion78);
This is the class TipoDireccion:
<?php
class TipoDireccion{
private $tipo;
private $descripcion;
//Construct auxiliar
function __construct() {
}
//Constructor 1 : completo
function constructor1($tipo) {
$tipoDireccion = new TipoDireccion();
$tipoDireccion->tipo = $tipo;
return $tipoDireccion;
}
function ponTipo($tipo) {
$this->tipo = $tipo;
}
function devuelveTipo() {
return $this->tipo;
}
function ponDescripcion($descripcion) {
$this->descripcion = $descripcion;
}
function devuelveDescripcion() {
return $this->descripcion;
}
}
?>
Thank you a lot in advance!
Don't know if this is still relevant to you, but in case anyone else comes on here for an answer. The problem is in this function:
function constructor1($tipo) {
$tipoDireccion = new TipoDireccion();
$tipoDireccion->tipo = $tipo;
return $tipoDireccion;
}
Because in the class definition, you define private $tipo; and then you try and assign $tipoDireccion->tipo to what was passed through the function. However, you aren't trying to access that variable through the scope of the class, you are trying to assign it from the 'public' scope as far as the class is concerned.
The fix for this has two options, the first one would be to change private $tipo; to public $tipo;. But that isn't a good solution as you have an assignment function for it.
Instead, use your functions that you made, which would make the function look like:
function constructor1($tipo) {
$tipoDireccion = new TipoDireccion();
$tipoDireccion->ponTipo($tipo);
return $tipoDireccion;
}
That's how you need to access it from the public scope, which you are doing after you initiate a new one.
function constructor1($tipo) {}
should be
static function constructor1($tipo) {}

PDO: Fetch class option to send fields to constructor as array

I am wondering whether or not it is possible to elegantly map the results of a PDO query to an array member in a class rather than have them floating about as public properties of that object.
Say I have the (condensed) following:
class DBObject {
protected
$record = array();
function __construct(array $record) {
if(!empty($record)) {
$this->loadRecord($record);
}
}
}
Ideally, I want to call the constructor with an array of values passed from the database, rather than use __set or any other weird methods. So using PDO's existing API would be great.
My rough get_all function at the moment has got this far:
static function get_all() {
$class = get_called_class();
$results = DB::factory()->query('SELECT * FROM ' . $class . ' ORDER BY ID');
$results->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, $class);
return $results;
}
NB: I'm running PHP 5.3 and MySQL through PDO, and already know this problem is solveable using __set, but I explicitly want to avoid using it in favour of something more performant.
You don't need to pass arguments to a constructor to make a class with private members using PDO::FETCH_CLASS. You can do something like this:
<?php
class Songs
{
private $artist;
private $title;
public function __construct()
{
}
public function get_artist()
{
return $this->artist;
}
public function get_title()
{
return $this->title;
}
private function set_artist($artist)
{
$this->artist = $artist;
}
private function set_title($title)
{
$this->title = $title;
}
}
I'm actually doing that on a demo site that I built. It works just fine with PDO::FETCH_CLASS. By default, FETCH_CLASS creates objects by populating the fields BEFORE the constructor. Think of it as bypassing the constructor. And it will do this with private members.
If you'd rather pass arguments to the constructor you can do your query like this:
$obj = $statement->fetchALL(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'Songs', $params);
In that case your constructor would look like this:
public function __construct($params)
{
$this->artist = $params[0]['artist'];
$this->title= $params[0]['title'];
}
Removed previous code
Right, can't you do something like this:
class DBObject {
protected $record = array();
function __construct($record = null) {
if(null === $record){
$obj_vars = get_object_vars($this);
$cls_vars = get_class_vars(get_class($this));
$this->$record = array_diff_key($obj_vars, $cls_vars);
}else{
$this->record = $record;
}
}
}
The problem with this however is that the values are still available as public members.
But what it will do is compare 'pre-defined' (class) members to the actual (object) members.
Since PDO will create new members in the object you can use array_diff_key to get the 'new' members.
Yes, this will still not pass them through your constructor.
How about using magic __set() method:
<?php
class MyClass
{
protected $record = array();
function __set($name, $value) {
$this->record[$name] = $value;
}
}
$pdo = new PDO("mysql:host=localhost;dbname=db", 'user', 'password');
$results = $pdo->query('SELECT * FROM table');
$results->setFetchMode(PDO::FETCH_CLASS, 'MyClass');
PHP will call this magic method for every non-existent property passing in its name and value.

Categories