Making PDO Database Connection available in controllers and models - mysql

right now, I am kinda frustrated and I hope someone can help me and point me into the right direction.
I have an "old" project which uses the mysql statements for connection to database, etc.
Within this project I have the following:
An index file containing
*
* load configuration and connect to database
*/
$projectConfiguration = new projectConfiguration();
$dbconnect = $projectConfiguration->connect($projectConfiguration->databaseHost, $projectConfiguration->databaseName, $projectConfiguration->databaseUser, $projectConfiguration->databasePass);
// load controller
$ReqMod = FatFramework\Functions::getRequestParameter("mod");
if (!$ReqMod) {
$ReqMod = FatFramework\Functions::getRequestParameter("controller");
}
$module = ($ReqMod) ? $ReqMod : 'default';
In this style I call the views and actions in classes, like SaveAction()
Using mysql always made it very simple to use this database connection in the models called by the controllers like
public function loadCustomersList($sAdditionalWhere = false)
{
$sQuery = "SELECT * FROM customers WHERE 1 ";
if ($sAdditionalWhere) {
$sQuery .= "AND " . $sAdditionalWhere . " ";
}
$sQuery .= "ORDER BY company";
$sql = mysql_query($sQuery);
while (($customer = mysql_fetch_object($sql)) != false) {
$aCustomers[] = $customer;
}
return $aCustomers;
}
I want to totally refractor this project and use PDO. I tried for the last 4 hours to find a solution, but I can't figure out how to make it work.
I think I don't need an extra dbconnect class since PDO is a class itself, am I right?
In the new index file I tried the following:
$db = new database();
try{
$dbc = new PDO($db->get_DbConSettings());
$dbc->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}catch(PDOException $e)
{
echo 'Verbindung fehlgeschlagen: '.$e->getMessage();
}
But with this $dbc will not available in controllers or models. It there a way to make it available there? If not, what is the best solution?
Do I have to make a database connection in every model?
An other issue I have with this is:
$db->get_DbConSettings()
in
$dbc = new PDO
gives back
'mysql:host=127.0.0.1; dbname=c1virtbkk', 'root', '123'
($dbc = new PDO('mysql:host=127.0.0.1; dbname=c1virtbkk', 'root', '123');)
I cannot connect to the database. I get the following:
Verbindung fehlgeschlagen: could not find driver
If I don't use $db->get_DbConSettings and put the required information manually in, I don't get any error and can do queries. Any hints?
Help is really appreciated.
Thanks in advance!
Mark

Definitely don't create a new PDO connection in each model. Creating MySQL database connections is fairly quick, but there's still some overhead to doing so. You want to reuse a connection throughout your request. If nothing else, it allows you to share a transaction across multiple models.
Some frameworks store shared resource objects in a "registry" class which is a singleton key-value store. It's not really much more than a global hash array, but making it a class makes the registry itself more easily tested with PHPUnit. See https://framework.zend.com/manual/1.12/en/zend.registry.using.html for an example of a registry.
You're right that PDO is a class, even though it's implemented as a C extension instead of a PHP class. But it's a class, and new PDO(...) returns an object of that class.
One reason to create a db class of your own is to help you in unit-testing, because you could create a mock object for your db class so you can test your other classes (even model classes) without needing a live database connection. Your db class could extend or else contain a PDO object.
Your issue about the error "could not find driver" is probably because the PDO driver for mysql is not installed. PDO is one PHP extension, and then there's a separate extension for each brand of SQL database. You can confirm this with:
$ php -i
...lots of output...
PDO
PDO support => enabled
PDO drivers => mysql, odbc, sqlite
pdo_mysql
PDO Driver for MySQL => enabled
Client API version => mysqlnd 5.0.11-dev - 20120503 - $Id: 76b08b24596e12d4553bd41fc93cccd5bac2fe7a $
...more output for other extensions...
Note that PDO tells me which drivers I have installed: mysql, odbc, and sqlite.
So you need to install pdo_mysql. I'm not sure what OS you're on, but I'm often on CentOS Linux or Ubuntu Linux. The pdo_mysql is available as a separate package via yum or apt.
Re your comment:
Okay, here's an example of a registry:
class registry {
protected static $items = array();
public static get($key) {
return isset(self::$items[$key])?
self::$items[$key] : null;
}
public static set($key, $object) {
self::$items[$key] = $object;
}
}
In your controller initial code, you'd create a database object and store it in the registry:
$projectConfiguration = new projectConfiguration();
$dbconnect = $projectConfiguration->connect(
$projectConfiguration->databaseHost,
$projectConfiguration->databaseName,
$projectConfiguration->databaseUser,
$projectConfiguration->databasePass);
registry::set('db', $dbconnect);
Then in your model class methods (or anywhere you need the database), get the db object from the registry and use it:
public function loadCustomersList($sAdditionalWhere = false)
{
$sQuery = "SELECT * FROM customers WHERE 1 ";
if ($sAdditionalWhere) {
$sQuery .= "AND " . $sAdditionalWhere . " ";
}
$sQuery .= "ORDER BY company";
$db = registry::get('db');
$stmt = $db->query($sQuery);
$aCustomers = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $aCustomers;
}

Related

How to conditionally use different database in CodeIgniter

Here is my scenario.
A user will login to the system. Based on the username, I need to set the database in codeigniter configuration.
I know that the line $this->load->database() in each model loads the default database.
So, after checking the username in session(assuming that the user has successfully logged in), how can I dynamically load a database?
Below is something that I am looking for:
if(username == 'foo'){
$this->load->database('database_name');
}
An example of a model function that I have written is as follows:
public function check_valid_login($username, $password){
$this->db->from('tbl_user_details');
$this->db->where('email_address', $username);
$this->db->where('password', md5($password));
$query = $this->db->get();
$rowcount = $query->num_rows();
return $rowcount ;
}
On selecting the database, how can I still use statements like $this->db->from('tbl_user_details'); and so on. i.e., I want to use $this->db itself. Is it possible to do that?
I think I found a solution.
This is the strategy that I followed: When the user tries to login, a session variable $_SESSION['dynamic_db_username'] is set with the username that is provided by the user.
The following logic is used for selecting the database dynamically. The below code is written in config/database.php
/*Dynamic database selection - begins*/
if(!empty($_SESSION['dynamic_db_username'])){
$dynamic_db_username = $_SESSION['dynamic_db_username'];
if($dynamic_db_username == 'sample#domain.com')
{
$db['default']['database'] = 'database_1';
}
elseif($dynamic_db_username == 'sample2#domain.com')
{
$db['default']['database'] = 'database_2';
}
else
{
$db['default']['database'] = 'database_1';
}
}
else
{
$db['default']['database'] = 'database_1';
}
/*End*/
Kindly review this strategy and please let me know if this is right.
in the config folder there was a file named autoload.php
open the file
find first this code below
$autoload['libraries'] = array('');
you have to put "database" in the array , changed code will be like
$autoload['libraries'] = array('database');
after that you can use your database anytime and anywhere without loading it manually .

Symfony2 execute SQL file in Doctrine Fixtures Load

I'm migrating an old web app based on SQL Server and ASP to Symfony2 and MySQL. I made some queries and export old data to individual SQL files.
How can I execute thoses files in my fixtures, when I run the command
$php app/console doctrine:fixtures:load
Now I have some fixtures that works directly with Doctrine ORM and entities, but I have a lot of data to import.
I find a good solution. I didn't find an exec method in class ObjectManager, so... this work very well for me.
public function load(ObjectManager $manager)
{
// Bundle to manage file and directories
$finder = new Finder();
$finder->in('web/sql');
$finder->name('categories.sql');
foreach( $finder as $file ){
$content = $file->getContents();
$stmt = $this->container->get('doctrine.orm.entity_manager')->getConnection()->prepare($content);
$stmt->execute();
}
}
In this solution your fixture class has to implement the ContainerAwareInterface with the method
public function setContainer( ContainerInterface $container = null )
{
$this->container = $container;
}
You can load the file contents as a string, and execute native SQL using the EntityManager:
class SQLFixtures extends AbstractFixture implements OrderedFixtureInterface
{
$filename = '/path/to/sql/file.sql';
public function load(ObjectManager $manager) {
$sql = file_get_contents($filename); // Read file contents
$manager->getConnection()->exec($sql); // Execute native SQL
$manager->flush();
}
public function getOrder() {
return 99; // Order in which this fixture will be executed
}
}
Answer for Zend Framework 2.5.3 using Doctrine Data-Fixtures.
Not sure if this applies to the given answers, but they are trying a bit too hard. If you inspect the given $manager object, you'll find that it already is the EntityManager (of interface ObjectManager) (at least, in ZF2). As such you're able to get the Connection directly and it's possible to execute without using $this->container->get('doctrine.orm.entity_manager')
Below a snippet which I use for creating the first user "system", with a createdBy FK reference to itself.
public function load(ObjectManager $manager)
{
$sql = 'INSERT INTO users (
id, username, email, display_name, `password`, created_by)
VALUES (:id, :username, :email, :display_name, :password, :created_by)';
$password = $this->createSuperDuperEncryptedPassword();
// $manager === `EntityManager|ObjectManager`, `->getConnection()` is available
$stmt = $manager->getConnection()->prepare($sql);
$stmt->bindValue(':id', 1);
$stmt->bindValue(':username', 'system');
$stmt->bindValue(':email', 'system#system.test');
$stmt->bindValue(':display_name', 'system');
$stmt->bindValue(':password', password );
$stmt->bindValue(':created_by', 1); // Self reference
$stmt->execute();
}

How can i make a SQL query from actionscript?

How can i make a SQL query from actionscript? and render all the results
You have to call a serverside script (for example php) and then retrieve the output of that script
private var _loader:URLLoader;
private var _request:URLRequest;
private function loadData():void {
_loader = new URLLoader();
_request = new URLRequest("path/to/your/phpscript");
_request.method = URLRequestMethod.POST;
_loader.addEventListener(Event.COMPLETE, onLoadData);
_loader.addEventListener(IOErrorEvent.IO_ERROR, onDataFailedToLoad);
_loader.addEventListener(IOErrorEvent.NETWORK_ERROR, onDataFailedToLoad);
_loader.addEventListener(IOErrorEvent.VERIFY_ERROR, onDataFailedToLoad);
_loader.addEventListener(IOErrorEvent.DISK_ERROR, onDataFailedToLoad);
_loader.load(_request);
}
private function onLoadData(e:Event):void {
trace("onLoadData",e.target.data);
}
private function onDataFailedToLoad(e:IOErrorEvent):void {
trace("onDataFailedToLoad:",e.text);
}
an example php script:
<?php
// defining main variables
$dbHost = "localhost";
$dbUser = "root";
$dbPass = "";
$dbName = "test";
$dbTable = "data";
// connecting and selecting database
#mysql_connect($dbHost, $dbUser, $dbPass) or die(mysql_error());
#mysql_select_db($dbName) or die(mysql_error());
// getting data
$data = "";
$res = mysql_query("SELECT * FROM ".$dbTable." ORDER BY id") or die(mysql_error());
while($row = mysql_fetch_object($res)) {
$data .= "nname=".$row->name.", ";
$data .= "city=".$row->city;
}
echo $data;
?>
For a better workflow, I suggest looking into AMF...
Here's a tutorial on AMF
There's no real equivalent to JDBC or ODBC for working in Flex that I'm aware of. Most likely this just wasn't really explored as something to attempt to deliver since Flex/Flash is generally client side and the DB is generally server side (shared). Generally speaking you'd use Java, PHP, C#, ASP .NET, Python, C++, or some other server side program to establish the connection to a DB and run queries. The closest thing to what your question is asking that I've seen is this: http://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118676a5497-7fb4.html but only applies to AIR and not for remote SQL connections. I'm not entirely sure how much work is involved in writing up a JDBC like interface/implementation to connect to any given DB I suppose in part it depends on how well documented the DBMS is... either way my guess is it'd be a ton of work.
EDIT
Okay so actually eating my words to some degree, apparently it is somewhat feasible: http://groups.google.com/group/flex_india/browse_thread/thread/d89bb5120fad7369?pli=1
You -really- don't want to do SQL query connections from Flex, especially if the application is distributed to users. Flash/Flex applications can be easily decompiled into readable source code, and if you're SQL connection string is in the source, you're going to have all kinds of security problems. It's a significantly better idea to have Flex use a restful web API to server-side languages like PHP, Python, Perl, or Node to do the SQL data processing for you.
Even if your application is internal, it's still a better concept "on paper" to keep Flex away from directly manipulating the database.

Solving "MySQL server has gone away" errors

I have written some code in PHP that returns the html content from .edu domains. A brief introduction is given here: Errors regarding Web Crawler in PHP
The crawler works fine when the number of links to crawl are small (something around 40 URLS) but I am getting "MySQL server has gone away" error after this number.
I am storing html content as longtext in MySQL tables and I am not getting why the error arrives after at least 40-50 insertions.
Any help in this regard is highly appreciated.
Please note that I have already altered the wait_timeout and max_allowed_packet to accomodate my queries and the php code and now I don't know what to do. Please help me in this regard.
You might be inclined to handle this problem by "pinging" the mysql server before a query. This is a bad idea. For more on why, check this SO post: Should I ping mysql server before each query?
The best way to handle the issue is by wrapping queries inside try/catch blocks and catching any database exceptions so that you can handle them appropriately. This is especially important in long running and/or daemon type scripts. So, here's a very basic example using a "connection manager" to control access to DB connections:
class DbPool {
private $connections = array();
function addConnection($id, $dsn) {
$this->connections[$id] = array(
'dsn' => $dsn,
'conn' => null
);
}
function getConnection($id) {
if (!isset($this->connections[$id])) {
throw new Exception('Invalid DB connection requested');
} elseif (isset($this->connections[$id]['conn'])) {
return $this->connections[$id]['conn'];
} else {
try {
// for mysql you need to supply user/pass as well
$conn = new PDO($dsn);
// Tell PDO to throw an exception on error
// (like "MySQL server has gone away")
$conn->setAttribute(
PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION
);
$this->connections[$id]['conn'] = $conn;
return $conn;
} catch (PDOException $e) {
return false;
}
}
}
function close($id) {
if (!isset($this->connections[$id])) {
throw new Exception('Invalid DB connection requested');
}
$this->connections[$id]['conn'] = null;
}
}
class Crawler {
private $dbPool;
function __construct(DbPool $dbPool) {
$this->dbPool = $dbPool;
}
function crawl() {
// craw and store data in $crawledData variable
$this->save($crawledData);
}
function saveData($crawledData) {
if (!$conn = $this->dbPool->getConnection('write_conn') {
// doh! couldn't retrieve DB connection ... handle it
} else {
try {
// perform query on the $conn database connection
} catch (Exception $e) {
$msg = $e->getMessage();
if (strstr($msg, 'MySQL server has gone away') {
$this->dbPool->close('write_conn');
$this->saveData($val);
} else {
// some other error occurred
}
}
}
}
}
I have another answer that deals with what I think is a similar problem, and it would require a similar answer. Basically, you can use the mysql_ping() function to test the connection before your insert. Before MySQL 5.0.14, mysql_ping() would automatically reconnect the server, but now you have to build your own reconnect logic. Something similar to this should work for you:
function check_dbconn($connection) {
if (!mysql_ping($connection)) {
mysql_close($connection);
$connection = mysql_connect('server', 'username', 'password');
mysql_select_db('db',$connection);
}
return $connection;
}
foreach($array as $value) {
$dbconn = check_dbconn($dbconn);
$sql="insert into collected values('".$value."')";
$res=mysql_query($sql, $dbconn);
//then some extra code.
}
I was facing "Mysql server has gone away" error while using Mysql connector 5.X, replacing dll to the last version solved the problem.
Are you opening a single DB connection and reusing it? Is it possible that its a simple timeout? You might be better served by opening a new DB connection for each of your read/write operations (IE contact .edu, get text, open DB, write text, close db, repeat).
Also how are you using the handle? Is it possible that it has hit an error and has 'gone away' for that reason?
Well This is what I am doing now based on rdlowrey's suggestion and I guess this is also right.
public function url_db_html($sourceLink = NULL, $source) {
$source = mysql_real_escape_string($source);
$query = "INSERT INTO html (id, sourceLink, sourceCode)
VALUES (NULL,('$sourceLink') , ('$source'))";
try {
if(mysql_query($query, $this->connection)==FALSE) {
$msg = mysql_errno($this->connection) . ": " . mysql_error($this->connection);
throw new DbException($msg);
}
} catch (DbException $e) {
echo "<br><br>Catched!!!<br><br>";
if(strstr($e->getMessage(), 'MySQL server has gone away')) {
$this->connection = mysql_connect("localhost", "root", "");
mysql_select_db("crawler1", $this->connection);
}
}
}
So once the query has failed to execute, the script will skip it but will make sure the connection is re-established.
However, my web crawler is crashing when files such as .jpg, .bmp, .pdf, etc are encountered. Is there a way to skip those urls containing these extensions. I am using preg_match and has given pdf and doc to match. Yet I want the function to skip all links containing extensions such as mp3, pdf, etc. Is this possible??

Doctrine and MySQL

I have few questions about Doctrine and MySQL working together. I don't understand it in 100%
I read somewhere that Doctrine can cooperate with MySQL DB. How it happens?
How do I load my DB?
How do I operate on my MySQL tables via doctrine (I'm no thinking about creating new ones)?
Does Doctrine save automatically changes to database?, if not then how to?
Some sample of code would be great. I don’t care too much about language can be in PHP, Yaml and others.
a) please specify more what you maen with "load DB". Doctrine is an ORM.
check here docs:
http://www.doctrine-project.org/projects/orm/1.2/docs/hu (check cookbook)
b) operations with tables with Doctrine are with DQL, example:
$q = Doctrine_Query::create()
->from('User u')
->leftJoin('u.Phonenumbers p');
$q->execute(); //you get a doctrine collection to iterate results of query
c)NO you need to save the object
$account = new Account();
$account->name = 'test 1';
$account->amount = '100.00';
$account->save();
here is account class
class Account extends Doctrine_Record
{
public function setTableDefinition()
{
$this->hasColumn('name', 'string', 255);
$this->hasColumn('amount', 'decimal');
}
}