I've been working with Doctrine_Record classes that autoload just fine for a while; but after some reading, I've decided I would like to implement both Doctrine_Records as well as Custom Table Classes.
So I added this to my bootstrap
$manager->setAttribute(
Doctrine::ATTR_AUTOLOAD_TABLE_CLASSES,
true
);
Which has made the Custom table classes work just fine... but it breaks autoloading Records!
How to make both autoload?
I.E. new User.php gets my User Doctrine_Record class and Doctrine_Core::getTable('User') gets my Custom UserTable class.
Here's how it looked (working) before I tried implementing Custom Tables:
public function _initDoctrine() {
require_once 'Doctrine.php';
/*
* Autoload Doctrine Library and connect
* use appconfig.ini doctrine.dsn
*/
$this ->getApplication()
->getAutoloader()
->pushAutoloader(array(
'Doctrine',
'autoload'),
'Doctrine');
$manager = Doctrine_Manager::getInstance();
$manager->setAttribute(
Doctrine::ATTR_AUTO_ACCESSOR_OVERRIDE,
true
);
$manager->setAttribute(
Doctrine::ATTR_MODEL_LOADING,
Doctrine::MODEL_LOADING_CONSERVATIVE
);
// try these custom tables out!
// $manager->setAttribute( Doctrine::ATTR_AUTOLOAD_TABLE_CLASSES, true );
$config = $this->getOption('doctrine');
$conn = Doctrine_Manager::connection($config['dsn'], 'doctrine');
return $conn;
// can call flush on the connection to save any unsaved records
}
Thanks
edit:
Let me clarify.
Not just custom classes.. I already use custom classes which extend Doctrine_Record.
class Model_User extends Doctrine_Record {}
$foo = new Model_User;
Much of my application currently works around this and will not be changing in that respect.
However, I would like to ALSO use Custom Tables
class UserTable extends Doctrine_Table {}
$bar = Doctrine_Core::getTable('User');
But, as soon as I enable this (custom table classes) feature to call classes of Doctrine_Table utilising the Table suffix. Any Doctrine_Record classes I've previously extended and called directly, stops working! I want to make use of both!
I don't really understand your problem about your custom classes but in any case here is my bootstrap for Doctrine 1.2.4 in ZF, using mysql and UTF-8. It doesn't need a require() and load all my models flawlessly.
protected function _initDoctrine()
{
$this->getApplication()->getAutoloader()
->pushAutoloader(array('Doctrine', 'autoload'));
spl_autoload_register(array('Doctrine', 'modelsAutoload'));
$manager = Doctrine_Manager::getInstance();
$manager->setAttribute(Doctrine::ATTR_AUTO_ACCESSOR_OVERRIDE, true);
$manager->setAttribute (
Doctrine::ATTR_MODEL_LOADING,
Doctrine::MODEL_LOADING_CONSERVATIVE
);
$manager->setAttribute(Doctrine::ATTR_AUTOLOAD_TABLE_CLASSES, true);
$dsn = $this->getOption('dsn');
$conn = Doctrine_Manager::connection($dsn, 'doctrine');
$conn->setAttribute(Doctrine::ATTR_USE_NATIVE_ENUM, true);
$conn->setCollate('utf8_unicode_ci');
$conn->setCharset('utf8');
$conn->setAttribute(Doctrine_Core::ATTR_AUTO_FREE_QUERY_OBJECTS, true );
Doctrine::loadModels(APPLICATION_PATH . '/models');
return $manager;
}
Doctrine models are stored in "application/models"
Then in my application/configs/application.ini :
autoloadernamespaces[] = "Doctrine"
dsn = "mysql://your_login:your_pass#server_ip/database"
I found the problem!
You must make sure every x.php Doctrine_Record class has an associated xTable.php Doctrine_Table class or the record loading will break!
Related
I have write my code to instantiate Eloquent Capsule/Manager using slim DI like this
$container['db'] = function ($c) {
$settings = $c->get('database');
$db = new \Illuminate\Database\Capsule\Manager;
$db->addConnection($settings);
$db->setAsGlobal();
$db->bootEloquent();
return $db;
}
And I have my route like this
$app->get('/adduser', function() {
$user = new Users;
$user->name = "Users 1";
$user->email = "user1#test.com";
$user->password = "My Passwd";
$user->save();
echo "Hello, $user->name !";
});
When I run the route in browser it will produce error in web server error log
PHP Fatal error: Call to a member function connection() on a non-object in /home/***/vendor/illuminate/database/Eloquent/Model.php on line 3335
In my opinion this is happened because the Eloquent Capsule/Manager is not triggered to be instantiate by DI.
I found a solution to solve this by declare the Model with custom constructor like this
use Illuminate\Database\Eloquent\Model as Eloquent;
use Illuminate\Database\Capsule\Manager as Capsule;
class Users extends Eloquent {
protected $table = 'users';
protected $hidden = array('password');
public function __construct(Capsule $capsule, array $attributes = array())
{
parent::__construct($attributes);
}
}
But I don't think this is a clean solutions, because I have to rewrite all my Models using custom constructor.
I need help to find solutions for my problem.
I try to use code below:
$app->get('/adduser', function() use ($some_variable) {
// create user script
});
but so far I don't know how to trigger $container['db'] using this method. I really appreciate a help here.
It's probably not a good idea to inject your capsule manager into each model.. As you say yourself, that's going to be a pain to manage.
Have you tried this code outside of the closure? ie. in the bootstrap part of your app..
$db = new \Illuminate\Database\Capsule\Manager;
$db->addConnection($settings);
$db->setAsGlobal();
$db->bootEloquent();
The setAsGlobal function makes the Capsule Manager instance static, so the models can access it globally.
Just to note, convention is to name your model classes in singular form. ie. User rather than Users.
I'm writing a custom renderer and following this tutorial that explains how to instantiate PhpRenderer object.
class CustomRenderer implements RendererInterface
{
.....
public function render( $nameOrModel, $values = null )
{
.....
$renderer = new \Zend\View\Renderer\PhpRenderer();
$renderer->setResolver( $this->resolver ); // $this->resolver Zend\View\Resolver\AggregateResolver
return $renderer->render( $model ); // $model Zend\View\Model\ViewModel
.....
Renderer is constantly throwing errors like
'Zend\View\HelperPluginManager::get was unable to fetch or create an
instance for translate
or
'No base path provided' in Zend\View\Helper\BasePath
etc. Basically everything that has to do with helpers in template does not work. Also, tried this code in controller, or with clean model but no luck. Resolver and model are correct.
How to properly instantiate new PhpRenderer object.
Currently I decided to look at Phalcon php as an alternate php framework to Codeigniter. I followed the tutorials on the website and it is pretty sweet the way it works. I'm still trying to wrap my head around few things though.
From my understanding, Models are bind with Database and mapped to the table in the database. I have a project, where I need to use 2 or more databases. The project has a backend (one database) and multiple frontends (another database). The easiest way is to run custom MySQL queries to fetch data from multiple databases. I'm not sure how to do that from the Model in the Phalcon. I looked over stackoverflow, tried few suggestions, but still no luck.
I would guess there should be some easy way to do so from the Model like $result=$this->query("SELECT * FROM backend.users")->fetch(); but it doesn't work.
Here what I have:
Controller:
class SignupController extends \Phalcon\Mvc\Controller{
function indexAction()
{
}
function registerAction()
{
$user = new Users();
$result=$user->saveNewUser();
print_r($result); // Nothing
//$result=$this->db->query("SELECT * FROM phalcon.system_users")->fetchAll();
//print_r($result); // Works
$this->view->disable();
}
}
Model:
class Users extends Phalcon\Mvc\Model
{
public function saveNewUser()
{
return $this->db; // how to run the query???
}
}
Bootstrap:
try {
//Register an autoloader
$loader = new \Phalcon\Loader();
$loader->registerDirs(array(
'../app/controllers/',
'../app/models/'
))->register();
//Create a DI
$di = new Phalcon\DI\FactoryDefault();
//Setup the database service
$di->set('db', function(){
return new \Phalcon\Db\Adapter\Pdo\Mysql(array(
"host" => "localhost",
"username" => "root",
"password" => "123456",
"dbname" => ""
));
});
//Setup the view component
$di->set('view', function(){
$view = new \Phalcon\Mvc\View();
$view->setViewsDir('../app/views/');
return $view;
});
//Setup a base URI so that all generated URIs include the "tutorial" folder
$di->set('url', function(){
$url = new \Phalcon\Mvc\Url();
$url->setBaseUri('/phalcon/');
return $url;
});
//Handle the request
$application = new \Phalcon\Mvc\Application($di);
echo $application->handle()->getContent();
} catch(\Phalcon\Exception $e) {
echo "PhalconException: ", $e->getMessage();
}
I liked the way Codeigniter had it, not sure if Phalcon have a simple way of doing that. May be I need to load the extension or library to do that in the Model.
Thanks in advance!
Thanks jodator,
But it is a little bit different that I needed. I wanted to execute sql queries from the Model.
After spending more time testing and experimenting I think I figured it out. Just in case if someone has the same need to be able execute mysql queries from the model, here the way I figured it out. I'm not sure if impacts the performance, but it works.
Create a new Model class and call it for example BaseModel.php with the next inside:
class BaseModel extends Phalcon\Mvc\Model
{
public $db;
public function initialize()
{
$this->db=$this->getDi()->getShared('db');
}
}
The BaseModel will extend the Phalcon Model and I created a public property called $db. Then on the initialize() I used $this->getDi()->getShared('db') to grab shared dependency injector and assigned it to our $this->db. Now all Models that extend this BaseModel will have access to that property. Then in my Users Model I have next:
class Users extends BaseModel // Users extends out BaseModel and will have access to $db
{
public function test()
{
//print_r(\Phalcon\Di::getDefault()->getShared('db')); // This is the ugly way to grab the connection.
$result=$this->db->query("SELECT * FROM phalcon.system_users"); // Working now
echo $result->numRows();
print_r($result->fetchAll());
}
}
Now it works beautifully. I also figured out one more thing that might be interesting to someone who wants to use mysql queries (PDO) in Phalcon. I always use FETCH_ASSOC when fetching data, and to make life easier you can set up FETCH_ASSOC by default at the connection this way you don't need to setAttribute every time fetching data. Here is how I have done it. At the bootstrap, when setting DI class for the database connection, you can include the options....
//Setup the database service
$di->set('db', function(){
return new \Phalcon\Db\Adapter\Pdo\Mysql(array(
"host" => "localhost",
"username" => "root",
"password" => "123456",
"dbname" => "",
'options' => [PDO::ATTR_CASE => PDO::CASE_LOWER, PDO::ATTR_PERSISTENT => TRUE,PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC],
));
});
As you see the last option sets PDO::ATTR_DEFAULT_FETCH_MODE.
If anyone has better way to do that, please post it here.
I hope it will help newbies to Phalcon like me :)
You need to setup two database services in you config, like:
//Setup the database service
$di->set('db', function(){ /* like in what you have */ });
// then the other one
$di->set('dbBackend', function(){ /* like in what you have */ });
Then in your models change the db service
public function initialize()
{
parent::initialize();
$this->setConnectionService('dbBackend');
// or $this->setWriteConnectionService('dbB') and $this->setReadConnectionService('dbA')
}
Then just $model->create()
But if you want to run a query on different databases you can look at Pdo\Mysql Adapter.
Also models can have set table name $this->setSource() and schema $this->setSchema().
I want to extend/overwrite the method logAttempt in class Confide (Confide on GitHub) in order to execute some extra code whenever someone logs in successfully. This would be cleaner than copying the same code to all controllers where logAttempt is called.
I read through the Laravel documentation and several answers here on stackoverflow, but I just can't get it working.
I created a new folder app/extensions with a file named Confide.php:
<?php
namespace Extensions;
class Confide extends \Zizaco\Confide\Confide {
public function __construct(ConfideRepository $repo) {
die('no way!');
$this->repo = $repo;
$this->app = app();
}
public function logAttempt($credentials, $confirmed_only = false, $identity_columns = array()) {
die('yeah man!');
}
}
I added the directory to my app/start/global.php:
ClassLoader::addDirectories(array(
// ...
app_path().'/extensions',
));
I also added it to composer.json and ran composer dump-autoload:
"autoload": {
"classmap": [
...,
"app/extensions"
]
},
My own Confide class seems not to be loaded at all, because Confide works as normal – without ever die()-ing.
And if I use \Extensions\Confide::logAttempt($input, true); in my controller including the namespace, I get this ErrorException:
Non-static method Extensions\Confide::logAttempt() should not be called statically, assuming $this from incompatible context
Do I really need my own ConfideServiceProvider class as well? I tried that, too, but I'm not sure at all what to put in there to make Confide use my extended class.
Is there no simple way to extend a tiny bit of a class? There must be, I'm just missing something here.
If you are looking to execute some code when a user logs in, you should just listen for that event. In this case, I believe Confide uses the Auth class to login, so you should be able to listen for that event.
Event::listen('auth.login', function($user)
{
$user->last_login = new DateTime;
$user->save();
});
I find this much easier and cleaner than worrying about extending classes.
EDIT: Made a mistake
I think you need to call the method like this:
\Extensions\Confide->logAttempt($input, true);
because you are using:
\Extensions\Confide::logAttempt($input, true);
Which is how you call static methods.
I think I finally figured it out.
I had to extend ConfideServiceProvider as well like so:
<?php
namespace Extensions;
class ConfideServiceProvider extends \Zizaco\Confide\ConfideServiceProvider {
/**
* Bootstrap the service provider.
*
* #return void
*/
public function boot() {
$this->package('extensions/confide');
}
/**
* Register the application bindings.
*
* #return void
*/
protected function registerConfide() {
$this->app->bind('confide', function($app) {
return new Confide($app->make('confide.repository'));
});
}
}
The code above goes into app/extensions/ConfideServiceProvider.php. Note: In boot() I replaced "zizaco" with "extensions" and in registerConfide() I made no changes at all, but if this method is not present in the extended class, the original class will be used. I've got no idea why.
Then in app/config/app.php I replaced Zizaco\Confide\ConfideServiceProvider with Extensions\ConfideServiceProvider.
My own extended Confide class looks like this now:
<?php
namespace Extensions;
class Confide extends \Zizaco\Confide\Confide {
public function logAttempt($credentials, $confirmed_only = false, $identity_columns = array()) {
$result = parent::logAttempt($credentials, $confirmed_only, $identity_columns);
if ($result) {
// Login successful. Do some additional stuff.
\Log::info('User ' . \Auth::user()->username . ' logged in.');
}
return $result;
}
}
Note: If you want to use any other standard Laravel class like Log, Session etc., prefix it with one backslash as shown in the example above, or add a use operator for each class you use (e.g. use \Log;).
I am trying to register my default database adapter in my bootstrap.php file so that I can access it where ever I am. This is my code so far:
//bootstrap.php
protected function _initDb()
{
$dbAdapter = Zend_Db::factory(Zend_Registry::get('configuration')
->resources->db->adapter,
Zend_Registry::get('configuration')
->resources->db->params->toArray());
Zend_Registry::set('dbAdapter', $dbAdapter);
Zend_Db_Table_Abstract::setDefaultAdapter($dbAdapter);
}
I am then trying to call it in one of my models by saying:
//exampleModel.php
$select = $this->_getDbAdapter()
->select()
->from(array('t' => $this->_getTable()->getName()),
array('name'))....
However I am just getting the error:
Call to undefined method Application_Model_Example::_getdbAdapter() in...
So obviously it is looking for it within my current class and can't find it...
You need this in your Model_Example
public function _getSqlAdapter()
{
return Zend_Registry::get('dbAdapter');
}
Or directly call Zend_Db_Table::getDefaultAdapter() instead of $this->_getDbAdapter()
In the code provided you don't appear to be calling it the adapter from the registry. You would need to use Zend_Registry::get('dbAdapter');
What class does Application_Model_Example extend?
I have Zend_Db_Table::setDefaultAdapter($dbAdapter); in my bootstrap (notice its Zend_Db_Table, not Zend_Db_Table_Abstract).
Then in my models, I would just use
$select = $this->->select()
->from(array('t' => $this->_getTable()->getName()), array('name'))....
assuming your model extends Zend_Db_Table?