Trying to add Doctrine DBAL into my own project to use it to access my db etc. I don't have composer and i never used it. This is what i am trying to do according to the docu:
use Doctrine\Common\ClassLoader;
class Connection
{
var $connection;
//Constructor
public function __construct()
{
require_once "doctrine/Common/ClassLoader.php";
$classLoader = new ClassLoader('Doctrine', 'doctrine');
$classLoader->register();
$config = new Configuration();
$connectionParams = array(
'dbname' => 'mydb',
'user' => 'root',
'password' => "",
'host' => 'localhost',
'driver' => 'pdo_mysql',
);
$this->connection = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config);
}
}
This is taken from here:
-http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html
and:
- http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/introduction.html
I have the Common and DBAL folder added into my project
My folder structure looks like this:
root
doctrine
DBAL
Common
php stuff
index.php (where connection.php) is executed
So what happens is that i either get "Cannot find class XY" or something similar, based upon what i change on the code. I never am able to execute it as it should following the tutorial.
What am i doing wrong here?
I just want to have the connection object, where i can start doing my stuff like useing the query builder etc...
I am completely lost here...
UPDATE: Installed composer as requested and have this Code now:
use Doctrine\DBAL\Configuration;
class Connection
{
var $connection;
//Constructor
public function __construct()
{
$config = new Configuration();
$connectionParams = array(
'url' => 'mysql://root:secret#localhost/mydb',
);
$this->connection = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config);
}
Which is the 2nd code example in my 1st link. Tells me " Class 'Doctrine\DBAL\Configuration' not found ". Funny thing is, that IntelliJ can perfectly autocomplete the path (suggests me Configuration when finishing DBAL in the path) but PHP doesn't find it. If i remove the new Configuration PHP just tells me, that it doesn't find the DriverManager...
I installed it correctly via composer though, at least composer tells me it is installed correctly now (Where does composer save the libs?)
You now need to require composers autoload file.
require __DIR__.'/vendor/autoload.php';
use Doctrine\DBAL\Configuration;
class Connection
{
var $connection;
//Constructor
public function __construct()
{
$config = new Configuration();
$connectionParams = array(
'url' => 'mysql://root:secret#localhost/mydb',
);
$this->connection = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config);
}
Please note, depending on your directory structure, the autoload file might be somewhere else, but usually this should work.
Pay attention to the use of namespaces: if the Doctrine namespace for its loader is Doctrine\Common\ClassLoader, you have to put the files inside the Doctrine\Common folder ("Doctrine" with a capital "D").
See the code snippet shown inside the Introduction chapter of the Doctrine DBAL documentations.
Related
We are using Doctrine 2 in our app, but due to our infrastructure, we do not have a static configuration for database connections. Instead, we have a collection of singletons in a service provider for each database we need to connect to, and we select a random database host for then when we connect.
Unfortunately, we are seeing some performance degradation in Doctrine's getRepository() function. I believe the issue is that Doctrine needs to generate its proxy classes at runtime (even in production) because we cannot figure out how to configure the CLI tools in order to create them at build time.
We are using the Laravel framework for the application.
Here's an example of our Laravel service provider which makes the repositories available for dependency injection.
<?php
use App\Database\Doctrine\Manager as DoctrineManager;
use Proprietary\ConnectionFactory;
use App\Database\Entities;
use App\Database\Repositories;
use App\Database\Constants\EntityConstants;
class DoctrineServiceProvider extends ServiceProvider
{
// Create a singleton for the Doctrine Manager. This class will handle entity manager generation.
$this->app->singleton(DoctrineManager::class, function ($app)
{
return new DoctrineManager(
$app->make(ConnectionFactory::class),
[
EntityConstants::ENTITY_CLASS_DATABASE1 => [app_path('Database/Entities/Database1')],
EntityConstants::ENTITY_CLASS_DATABASE2 => [app_path('Database/Entities/Database2')],
],
config('app.debug'),
$this->app->make(LoggerInterface::class)
);
});
// Register the first repository
$this->app->singleton(Repositories\Database1\RepositoryA1::class, function ($app)
{
return $app[DoctrineManager::class]
->getEntityManager(EntityConstants::ENTITY_CLASS_DATABASE1)
->getRepository(Entities\Database1\RepositoryA1::class);
});
// Register the second repository
$this->app->singleton(Repositories\Database1\RepositoryA2::class, function ($app)
{
return $app[DoctrineManager::class]
->getEntityManager(EntityConstants::ENTITY_CLASS_DATABASE1)
->getRepository(Entities\Database1\RepositoryA2::class);
});
// Register a repository for the second database
$this->app->singleton(Repositories\Database2\RepositoryB1::class, function ($app)
{
return $app[DoctrineManager::class]
->getEntityManager(EntityConstants::ENTITY_CLASS_DATABASE2)
->getRepository(Entities\Database2\RepositoryB1::class);
});
}
Here's the class that generates EntityManagers for Doctrine:
<?php
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Connections\MasterSlaveConnection;
use Proprietary\ConnectionFactory;
class Manager
{
private $c_factory;
private $paths;
private $connections = [];
private $entity_managers = [];
public function __construct(
ConnectionFactory $cf,
array $paths
)
{
$this->c_factory = $cf;
$this->paths = $paths;
}
public function getConnection($name, $partition = false, $region = false)
{
// Get a list of servers for this database and format them for use with Doctrine
$servers = self::formatServers($name, $this->c_factory->getServers($name, true, $partition, $region));
// Generate a connection for the entity manager using the servers we have.
$connection = DriverManager::getConnection(
array_merge([
'wrapperClass' => MasterSlaveConnection::class,
'driver' => 'pdo_mysql',
], $servers)
);
return $connection;
}
public function getEntityManager($name, $partition = false, $region = false)
{
// Should these things be cached somehow at build time?
$config = Setup::createAnnotationMetadataConfiguration($this->paths[$name], false);
$config->setAutoGenerateProxyClasses(true);
// Set up the connection
$connection = $this->getConnection($name, $partition, $region);
$entity_manager = EntityManager::create($connection, $config);
return $entity_manager;
}
// Converts servers from a format provided by our proprietary code to a format Doctrine can use.
private static function formatServers($db_name, array $servers)
{
$doctrine_servers = [
'slaves' => [],
];
foreach ($servers as $server)
{
// Format for Doctrine
$server = [
'user' => $server['username'],
'password' => $server['password'],
'host' => $server['hostname'],
'dbname' => $db_name,
'charset' => 'utf8',
];
// Masters can also be used as slaves.
$doctrine_servers['slaves'][] = $server;
// Servers are ordered by which is closest, and Doctrine only allows a
// single master, so if we already set one, don't overwrite it.
if ($server['is_master'] && !isset($doctrine_servers['master']))
{
$doctrine_servers['master'] = $server;
}
}
return $doctrine_servers;
}
}
Our service classes use dependency injection to get the repository singletons defined in the service provider. When we use the singletons for the first time, Doctrine will use the entity class defined in the service provider and get the connection associated with the repository.
Is there any way we can enable the CLI tools with this configuration? Are there any other ways that we can optimize this for use in production?
Thanks.
I was able to solve the problem thanks to a suggestion from the Doctrine IRC channel. Since the CLI tools can only handle a single database, I created a doctrine-cli directory containing a base-config.php file and a subdirectory for each of the databases we use.
Here's an example file structure:
doctrine-cli/
|- database1/
| |- cli-config.php
|- database2/
| |- cli-config.php
|- base-config.php
The base-config.php file looks like this:
<?php
use Symfony\Component\Console\Helper\HelperSet;
use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper;
use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper;
use App\Database\Doctrine\Manager as DoctrineManager;
use Proprietary\ConnectionFactory;
require __DIR__ . '/../bootstrap/autoload.php';
class DoctrineCLIBaseConfig
{
private $helper_set;
public function __construct($entity_constant, $entity_namespace)
{
$app = require_once __DIR__ . '/../bootstrap/app.php';
// Proprietary factory for getting our databse details
$connection_factory = new ConnectionFactory(...);
// Our class that parses the results from above and handles our Doctrine connection.
$manager = new DoctrineManager(
$connection_factory,
[$entity_constant => [app_path('Database/Entities/' . $entity_namespace)]],
false,
null,
null
);
$em = $manager->getEntityManager($entity_constant);
$this->helper_set = new HelperSet([
'db' => new ConnectionHelper($em->getConnection()),
'em' => new EntityManagerHelper($em),
]);
}
public function getHelperSet()
{
return $this->helper_set;
}
}
Here's an example cli-config.php from the database directory:
<?php
use App\Database\Constants\EntityConstants;
require __DIR__ . "/../base-config.php";
$config = new DoctrineCLIBaseConfig(
EntityConstants::ENTITY_CLASS_DATABASE1,
"database1"
);
return $config->getHelperSet();
Now, I'm able to cycle through each of the directories and run commands like so:
php ../../vendor/bin/doctrine orm:generate-proxies
For our build process, I wrote a simple shell script that cycles through the directories and runs the orm:generate-proxies command.
So, I'm trying to get around in Silex. Just learn the way it works and I'm trying to use Doctrine in it. I can use it on the index.php, but I'd also like to use it in my classes. These lines are used in the normal root file (index.php):
$images = $app['db']->prepare("SELECT * FROM images");
$images->execute();
$images = $images->fetchAll(\PDO::FETCH_CLASS, \AI\Models\Image::class);
So that would give me the ability to do something with the images. But I don't want to work this way. I'd like classes to do it all for me, so that I just script some methods which do all the hard work for me. That would let me just run one line for each Route in index.php
The problem is that I don't know how to connect with Doctrine from inside my classes. Because there is no '$app' in there. I think it would be weird to start the app inside of a class.
So let's say I wanted to create a user class. This SQL would give me all the users: "SELECT * FROM users". But how would I use Doctrine inside the User class?
<?php
namespace Models;
class User {
public function find($user){
if($user) {
$field = (is_numeric($user)) ? 'id' : 'username';
$sql = "SELECT * FROM users";
$data = // RUN QUERY $SQL
if($data->count()) {
$this->_data = $data->all();
return true;
}
}
return false;
}
}
In your index.php follow these steps.
Create instance of the silex application:
$app = new Silex\Application();
$app->register(new Silex\Provider\ServiceControllerServiceProvider());
Set the database configuration:
$config = new \Doctrine\DBAL\Configuration();
$connParams = array(
'driver' => 'driver',
'dbname' => 'dbname',
'host' => 'host',
'user' => 'user',
'password' => 'pass',
'charset' => 'charset',
'port' => 'port'
);
Connect to database:
$conn = \Doctrine\DBAL\DriverManager::getConnection($connParams, $config);
Now you have different ways to make this db instance accessible throughout your app. You can whether make a global variable adding the instance in it:
global $dbcon;
$dbcon = $conn;
Or simply add it to the $app itself:
$app['dbcon'] = $conn;
Furthermore you might want to add a constructor to your models like this:
public function __construct($db)
{
$this->db = $db;
}
You would need to inject those instances in your controller.
I looked through the docs real quick and think I found what you need.
Here is a link to the documentation page : http://silex.sensiolabs.org/doc/2.0/providers/service_controller.html.
the documentation page explains everything you need to know to get what you want to achieve.
As a total php and phalcon newbie, I'm trying to use the recommended universal class loader using this code:
$loader = new \Phalcon\Loader();
// Register some directories
$loader->registerDirs(
array(
"php/assistants/"
)
);
// register autoloader
$loader->register();
$test = new dbAssistant();
as I understand I have to reffer to the php file as a class what I have inside of php/assistants/dbAssistant.php is the following code, trying to connect to a database:
<?php
function connect() {
$connection = new Phalcon\Db\Adapter\Pdo\Mysql(array(
'host' => 'localhost',
'username' => 'root',
'password' => 'tt',
'dbname' => 'testdb',
'port' => '3306'
));
echo 'Connected!!!';
}
again what I understand is that I have to refer to dbAssistant.php as a class and that's why I'm using $test = new dbAssistant();, but it gives me the following error:
Fatal error: Class 'dbAssistant' not found in /var/www/html/test/test.php on line 18
I know that it seeme normal, but the strange thing is that if I remove the connect() function and place the code out of it, I can see the Connected!!! echo, but it is followed by the same(above) error. I know that I'm missing something really small here, but as a complete php newbie, I really can't spot the problem.
Can you give me a push?
php/assistants/dbAssistant.php is not a class but a plain Php file. There should be a class in there with the name dbAssistant.
class dbConnect {
public function connect() {
///Do your stuff
}
}
I am working on a project based on Zend 1.12. There is a new requirement in which we have to encode all of our files to prevent hacking. We used ioncube encoder which encode all of the .php file but not application.ini where it store db information username, password, secret key etc. There are two approach :
1) Have configuration reside in .php file such as config.php instead of application.ini
2) have ioncube encode application.ini
With the first approach I found Zend Config Introduction where you could have configuration store in array. I need a concrete example with setup in Bootstrap.php where it could utilize these configuration. Right now all of our model extends from Zend_Db_Table_Abstract. I really want when i migrate all the application.ini db configuration into config.php all the db operation works and there are several instance in front controller make use of $this->applicationOptions. I hope my putting configuration this will work as well. Please help
With second approach I did not found much resolution on ioncube be able to encode application.ini
This is my configuration file
return $configArray = array(
'db' => array(
'adapter' => 'pdo_mysql',
'params' => array(
'host' => 'localhost',
'username' => 'root',
'password' => 'root',
'dbname' => 'test'
)
)
);
When i do this in Bootstrap.php and it work
$config = new Zend_Config(require APPLICATION_PATH .'/configs/config.php');
$db = Zend_Db::factory($config->db->adapter,
$config->dv->params->toArray());
$db = Zend_Db::factory($config->db);
Zend_Db_Table::setDefaultAdapter($db);
but when i do
protected function _initDatabase(){
$config = new Zend_Config(require APPLICATION_PATH .'/configs/config.php');
$resource = $this->getPluginResource('db');
var_dump($this->getPluginResource('db')); // this will be null.
My question is is should i do anything different in configuration so it will mimic resources.db.adapter, resources.db.params.host etc and it will be picking up by the pluginResources or getoptions
Normally it is expected that users would use one of the adapter classes such as Zend_Config_Ini or Zend_Config_Xml, but if configuration data are available in a PHP array, one may simply pass the data to the Zend_Config constructor in order to utilize a simple object-oriented interface.
Basically, you first create a PHP file that contains the configuration :
// config.php
return array(
...
...
);
And, then, from another file, use than configuration file :
$config = new Zend_Config(require 'config.php');
In your Bootstrap.php try getting the configuration like this
protected function _initDb()
{
$resource = $bootstrap->getPluginResource('db');
$db = $resource->getDbAdapter();
Zend_Registry::set("db", $db);
}
After registering the db variable in your Bootstrap.php you can access it like this
$dbAdapter = Zend_Registry::get("db");
You use getPluginResource() hence you need to have your configuration keys in the following way:
resources.db.adapter = ...
resources.db.params.host = ...
...
or your config.php should look like this:
// config.php
return array(
'resources' => array(
'db' => array(
...
),
),
...
);
This page could be helpful.
I've been using Doctrine in my project without explicitly namespacing any of my classes. This led to some problems with trying to organise my code into separate sub directories (or at least it seemed to). As such I've tried to implement namespaces in my code but I'm struggling and having tried the numerous solutions on here to no avail, I need to ask.
I've got the standard project structure:
application/
--models/
--services/
--controllers/
..etc
In my Bootstrap I've got the following (without namespaces in my code which works fine):
/**
* Initialize Doctrine
* #return Doctrine_Manager
*/
public function _initDoctrine() {
// include and register Doctrine's class loader
require_once('doctrine/Doctrine/Common/ClassLoader.php');
$autoloader = \Zend_Loader_Autoloader::getInstance();
require_once('doctrine/Doctrine/Common/ClassLoader.php');
$commonLoader = new \Doctrine\Common\ClassLoader('Doctrine\Common', 'doctrine');
$autoloader->pushAutoloader(array($commonLoader, 'loadClass'), 'Doctrine\Common');
$dbalLoader = new \Doctrine\Common\ClassLoader('Doctrine\DBAL', 'doctrine');
$autoloader->pushAutoloader(array($dbalLoader, 'loadClass'), 'Doctrine\DBAL');
$ormLoader = new \Doctrine\Common\ClassLoader('Doctrine\ORM', 'doctrine');
$autoloader->pushAutoloader(array($ormLoader, 'loadClass'), 'Doctrine\ORM');
$modelLoader = new \Doctrine\Common\ClassLoader(NULL, APPLICATION_PATH . "/models");
$autoloader->pushAutoloader(array($modelLoader, 'loadClass'), '');
// create the Doctrine configuration
$config = new \Doctrine\ORM\Configuration();
// setting the cache ( to ArrayCache. Take a look at
// the Doctrine manual for different options ! )
$cache = new \Doctrine\Common\Cache\ArrayCache;
$config->setMetadataCacheImpl($cache);
$config->setQueryCacheImpl($cache);
// choosing the driver for our database schema
// we'll use annotations
$driver = $config->newDefaultAnnotationDriver(
APPLICATION_PATH . '/models'
);
$config->setMetadataDriverImpl($driver);
// set the proxy dir and set some options
$config->setProxyDir(APPLICATION_PATH . '/models/Proxies');
$config->setAutoGenerateProxyClasses(true);
//$config->setAutoGenerateProxyClasses(false);
$config->setProxyNamespace('App\Proxies');
// now create the entity manager and use the connection
// settings we defined in our application.ini
$connectionSettings = $this->getOption('doctrine');
$conn = array(
'driver' => $connectionSettings['conn']['driv'],
'user' => $connectionSettings['conn']['user'],
'password' => $connectionSettings['conn']['pass'],
'dbname' => $connectionSettings['conn']['dbname'],
'host' => $connectionSettings['conn']['host']
);
$entityManager = \Doctrine\ORM\EntityManager::create($conn, $config);
// push the entity manager into our registry for later use
$registry = Zend_Registry::getInstance();
$registry->entitymanager = $entityManager;
return $entityManager;
}
When I add
namespace models;
to each of my model classes and update the Bootstrap to be as follows I get an Exception "Class Application does not exist" (Application is one of my models):
$modelLoader = new \Doctrine\Common\ClassLoader('models', APPLICATION_PATH . "/models");
$autoloader->pushAutoloader(array($modelLoader, 'loadClass'), 'models');
Just for completeness, I reference that model in my controller as follows:
public function indexAction()
{
$this->_helper->layout()->title = "Your applications";
$this->_helper->layout()->description = "Create, edit and view all applications you have registered with us.";
$this->view->applicationList = $this->entityManager->getRepository("Application")->findAll();
}
What am I missing? I'm sure it's obvious but really am pulling out my hair now.
After much futher searching, I stumbled across this video (login required).
Basically, the way I solved (as per the webinar) was to namespace my entities and save them under the /library directory. Then whenever I need to use them from the actual app, I access via their namespace.