Can anyone help me with this?
I have this function in a singleton class. The error it is giving me back is that it cannot find the class.
First I thought it had something to do with the autoloader, but I did spl_autoload_unregister('libloader') and it still gives the same error?
The host is running php 5.
public static function getInstantie()
{
if (!self::$instantie)
{
$config = config::getInstantie();
$db_type = $config->config_waarden['database']['db_type'];
$hostnaam = $config->config_waarden['database']['db_hostnaam'];
$dbnaam = $config->config_waarden['database']['db_naam'];
$db_wachtwoord = $config->config_waarden['database']['db_wachtwoord'];
$db_gebruikersnaam = $config->config_waarden['database']['db_gebruikersnaam'];
$db_poort = $config->config_waarden['database']['db_poort'];
self::$instantie = new PDO("$db_type:host=$hostnaam;port=$db_poort;dbname=$dbnaam",$db_gebruikersnaam, $db_wachtwoord);
self::$instantie-> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return self::$instantie;
}
thanks, Richard
PDO is enabled by default with a set of database drivers:
http://au.php.net/manual/en/pdo.installation.php
But the build of PHP you are working with could have it disabled. Autoloading will have no effect on whether or not the PDO class will be found.
Create a PHP info file and check to see if the PDO section exists. If it doesn't, then your issue is most likely because it wasn't built into your php installation.
is that function inside of a class that extends PDO? If not, can you try to make that function inside of a class that extends PDO and instead of self call the functions using keyword parent?
Related
Currently trying to learn the "right" way to build a site with OOP and the MVC model, and obviously running into some stumbling blocks since I've been doing mostly procedural for years.
(I'm also using PHP 7 for the first time since I've been stuck with PHP 5 for years and years, so also trying to code the "right" way using mysqli_ instead of the old mysql_. Learning prepared statements for the first time also instead of just escaping all my variables, but that's a whole different discussion)
Right now I have a few different classes:
config.class.php -> Config -> set up the db connection and other site settings
leads.class.php -> Leads extends Config -> get lead info from the db upon request (when someone hits the site)
questions.class.php -> Questions extends Config -> get question info (it's a survey site)
leadsview.class.php -> -> LeadsView extends Leads -> display lead info if needs be
questionsview.class.php -> QuestionsView extends Questions -> display question info on the page after it's pulled from the db
So, let's say on my index.php I need to instantiate both QuestionsView and LeadsView so I can display questions and lead info on the page, respectively. So I do this:
session_start();
include_once 'lib/autoload.php'; // class autoloader
$l = new LeadsView();
$q = new QuestionsView();
Totally works fine so far. BUT - in my Config class I not only have a database connection, but a few site configuration settings inside a constructor that need to be set when someone first hits the page. Something like this so far:
class Config {
// set up db connection
private $db_host;
private $db_user;
private $db_password;
private $db_name;
protected $conn;
protected $flow_id;
protected $domain;
public function __construct() {
$this->flow_id = $_REQUEST['flow'];
$this->domain = $_SERVER['HTTP_HOST'];
$this->connect(); // open the db connection
print "hey<br>";
}
protected function connect($db = "default") {
switch ($db) {
// allow for different db connections in the future
case "default":
$this->db_host = "XXXX";
$this->db_user = "XXXX";
$this->db_password = "XXXX";
$this->db_name = "XXXX";
break;
}
$this->conn = new mysqli($this->db_host, $this->db_user, $this->db_password, $this->db_name);
$this->conn->set_charset("utf8mb4");
if ($this->conn->connect_error) {
die("Error connecting to db: " . $this->conn->connect_error);
}
}
}
I threw in that print "hey<br>"; just to make sure that constructor was being run. But now it's being run twice: once from my $l = new LeadsView(); and once from $q = new QuestionsView(); since they both extend Config. I don't need or want to run that constructor twice, for obvious reasons.
So my question is: what's the proper way to set up a configuration class in a scenario like this? Should I create a Dbh class separate from Config, and just have all my questions, leads, etc. classes extend Dbh instead so they don't all run the Config methods as well? Is there some other obvious way to do this that I'm completely missing?
Your classes should never extend from Config or Database class or anything like that. This is not how polymorphism works.
In fact, your Config class isn't very useful. To make use of such class you need methods that actually help you perform prepared statements. The connect() method is not needed and you definitely do not need all the properties.
If we were going to fix this class then we could do something like this:
class Database {
protected $conn;
protected $flow_id;
protected $domain;
public function __construct(string $db) {
$this->flow_id = $_REQUEST['flow'];
$this->domain = $_SERVER['HTTP_HOST'];
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
// Load the variable from the config file
$this->conn = new mysqli($db_host, $db_user, $db_password, $db_name);
$this->conn->set_charset("utf8mb4");
}
//
// The rest of your database abstraction methods. Some methods that help you write parameterized queries more easily
// Without other methods this class would be useless!
}
The name of the class doesn't make sense. It is not a config class. It is an abstraction around mysqli. The config details should be stored in a separate file.
When you need to use this class in another class, simply require it as a parameter.
$db = new Database();
$l = new LeadsView($db);
This is called dependency injection. You should use this pattern in your code when working with OOP as it will make a lot of interactions between your classes much simpler. You can also implement IoC container. Nette has a good tutorial, but you can also use their implementation.
I would strongly recommend to don't reinvent the wheel. There are already good libraries that provide abstraction around PDO. Yes, PDO not mysqli. Do not waste your time with mysqli unless you have an extremely good reason to use mysqli. Use PDO with an abstraction library such as EasyDB
You are using inheritance. You probably want to use composition instead. Concretely this means providing the Config to LeadsView or Questionsview.
$config = new Config();
$leadsview = new LeadsView( $config );
class Config {
__construct() {
// do whatever
}
}
class LeadsView {
private $config;
__construct( $config ) {
$this->config = $config;
}
// use this->config somewhere in Leadsview to get whatever you need
}
To prevent the usage of multiple instances of Config you can use a single reference (this requires your discipline to enforce).
Otherwise you can create config as a singleton, which guarantees only one version of Config exists. If you want to know more about Singletons you can look it up, it's a very well know pattern.
I have class, where i make connection to database and do some queries.
But i can't make query to this database from other class. Problem is that class Cd can't see db connection command -> can't make a query. Here is the code:
require_once('config.php');
class myClass
{
public $mysqli;
public $res;
function connect()
{
$database = new Database();
$this->mysqli = new mysqli($database->db_host, $database->db_user, $database->db_pass, $database->db_table);
}
function cd($id)
{
......
}
}
}
class Cd extends myClass
{
function cdname($id)
{
$get= new Scandiweb();
$get->mysqli;
$this->res = $get->mysqli->query("SELECT * FROM disk WHERE id=" . $id . "");
if ($this->res->num_rows > 0) {
.........
}
}
}
Your code is a bit messy, so it's hard to tell where exactly the problem lies:
Why do you require config?
Why do you create a Database (which is more like a DbConfig) in the constructor instead of passing it?
What is the Scandiweb-class?
Why do you call mysqli->query on that class instead of $this
The last one is your immediate mistake. You extend myClass which creates the mysqli-connection and stores it as class variable $this->mysqli. That means that the child class Cd will have access to it. When you extend a class you can call all it's public and protected properties and methods. Only those marked as private can't be accessed.
That means instead of accessing $get->mysqli->query(...) you can do $this->mysqli->query(...). What would make sense in OOP is to create a connection once (like you do in the constructor) and pass it around to the services requiring a database connection. This is called Dependency Inversion Principle and using a Dependency Container makes it easier (but is not mandatory).
There are so called design patterns that will make it easier to deal with performing sql queries like in your code above. The most common ones are the Active Record-pattern as used in Laravel's Eloquent and the Propel library, the Table Data Gateway-pattern as used in Zend Framework's DB-component and the Data Mapper-pattern as employed by Doctrine ORM. If you want to write OOP code you should look at their documentation and maybe use one of those instead of dealing with everything yourself.
So this is something I've been meaning to get to grips with for ages. Converting a few small (single-file) applications to PDO. I can use PDO, connect to a database and run queries, all working.
But each time I initialise a new PDO, I'm also having to run
setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Yeah it's only one line but one day I might need to add further stuff in there. To me it would seem better to somehow extend the PDO class in a way that can include that line so I can just start my DB connection with a single line. Creating my own class, even if only adding a single line of code at this stage, keeps me future-proofed if I ever decide to add anything else in the future.
I've found something like this...
class myPDO extends PDO {
public function __construct($dsn, $user=null, $pass=null, $options=null) {
parent::__construct($dsn, $user, $pass, $options);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
}
// THEN A SIMPLE 1 LINER TO CONNECT - USING TRY/CATCH AS WELL OF COURSE
$pdo_conn = new myPDO($cfg['pdo_dsn'], $cfg['pdo_user'], $cfg['pdo_pass'], $cfg['pdo_options']);
When extending the class I assume I don't actually need to re-create the constructor.
Is there a way I can integrate my $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); into my class without re-creating the constructor function?
I'm just getting started with PHP's class syntax so this will be a really basic question for someone but it will answer a few other questions for me at the same time.
You do not need to extend from PDO here. What you want is a central place in your application that is creating the PDO object. You can then do the changes you like over time (e.g. integrating some configuration file/system) and extend then centrally.
One thing is that you create a class for that, let's call it PdoFactory:
class PdoFactory
{
/**
* #return PDO
*/
public function buildPdo() {
$pdo = new PDO($dsn = 'xyz', $user = 'abc', $pass = '', $options = '');
if ($pdoException = true) {
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return $pdo;
}
}
Usage:
$factory = new PdoFactory();
$pdo = $factory->buildPdo();
As you can see, this is very easy to use. You can even put the place where you create the PdoFactory apart from the place where you invoke the buildPdo() function.
Also this makes it more clear that you are dealing with two different things here: First creating the Pdo object (encapsulated into a class of it's own) and the Pdo object itself which is just for accessing the database.
I hope this helps.
The problem, as I see it, is that you are hard-coding a particular error level into your application. What if you're in development and you want everything? What if you decide you want to change the level for a particular application? It would be much better to keep it as a parameter you set after the fact, or, if you're bent on subclassing it, pass an error level in as a constructor argument.
So I have a DB set up and I'm using a class to connect to it that extends Mysqli. Here are the relevant lines of code:
class Db extends Mysqli {
public $result = Array();
function __construct() {
parent::__construct(DB_HOST, DB_USER, DB_PASS, DB_DB);
}
I've checked the connection info, and it works fine with the mysql_connect() function.
My PHP version is 5.3, and I'm using MAMP 1.9.5 to run the environment.
So on to the issue I'm having - if I var_dump() the connection, it returns as NULL. Not false, but null. Now I've checked the specs and, just like it's predecessor mysql_connect(), it is supposed to return false in case of the connection failing. So what possible circumstance would return false?
You are not showing the complete code. This is what you have done:
class Db extends Mysqli {
function __construct() {
$r = parent::__construct(DB_HOST, DB_USER, DB_PASS, DB_DB);
var_dump($r);
}
}
And naturally this returns NULL. The parent constructor never returns anything. Constructers are not supposed to return anything. They fill up the freshly created object instance.
You will find the connection handle and other properties in the returned object, after your constructor is done.
I'm guessing it's because of your capitalization. Extending the nonexistent class Mysqli works, and its nonexistent method connect() seems to return NULL
class Db extends Mysqli
Should be
class Db extends mysqli
#Michael is likely right about the spelling issue, but there's another issue here:
Why are you not using PDO? PDO is installed by default on PHP 5.1 and newer.
PDO abstracts the database layer so you can write code against any database that supports PDO without having to make majorchanges.
is there any example how to setup an instance of zend log from application.ini? I have only found an example for logging to an file, but i want to log into an SQLITE database table?
Zend Log resource
Good question. I can't find a way to instantiate the Zend_Log_Writer_Db from a bootstrap config. The writer class requires a Zend_Db_Adapter object. It doesn't accept a string.
The ZF project needs to develop this use case further. They don't even have any unit tests for Zend_Application_Resource_Log that include a Db writer.
The best I can suggest until then is that you Bootstrap class needs to customize the Log resource in an _initLog() method.
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initDb()
{
if ($this->hasPluginResource("db")) {
$r = $this->getPluginResource("db");
$db = $r->getDbAdapter();
Zend_Registry::set("db", $db);
}
}
protected function _initLog()
{
if ($this->hasPluginResource("log")) {
$r = $this->getPluginResource("log");
$log = $r->getLog();
$db = Zend_Registry::get("db");
$writer = new Zend_Log_Writer($db, "log", ...columnMap...);
$log->addWriter($writer);
Zend_Registry::set("log", $log);
}
}
}
Here in the manual: you can find an example how to write your log file into the database.Is that what you mean?
This should work - I will test fully later (not at my dev machine now)
Zend_Application_Resource_Log can setup an instance of a Zend_Log from application.ini
resources.log.writerName = "db"
resources.log.writerParams.db.adapter = "PDO_SQLITE"
resources.log.writerParams.db.dbname = APPLICATION_PATH "/../db/logdb.sqlite"
resources.log.writerParams.db.table = "log"
Since ZF 1.10alpha (at least), the following has been true.
// e.g. 1 - works
resources.log.firebug.writerName = "Firebug"
// e.g. 2 - fails
resources.log.writerName = "Firebug"
NOTE: the arbitrary array key 'firebug'. When the Zend_Log factory churns over the resource's log config, example 1 will be passed as an array to Zend_Log->addWriter() (triggering the _constructWriterFromConfig() method), whilst example 2 will simply pass a string (triggering an exception).
(I know this is old, and I'm using a Firebug logger example, but the same applies to all log writers)