Read table from another database - sql-server

Is it possible to read tables from another database using the builting CakePHP model features? I don't mean having an entirely different configuration in DATABASE_CONFIG but using the same host, user and password. The obvious thing:
class Provincia extends AppModel {
public $useTable = 'shared_data.dbo.provincia';
}
class DebugController extends AppController {
public function index() {
/* #var $modeloProvincia Provincia */
$modeloProvincia = ClassRegistry::init('Provincia');
$provincias = $modeloProvincia->find('all');
}
}
... triggers:
Error: Table shared_data.dbo.provincia for model Provincia was not found in datasource default.

I'll share my findings so far...
Short answer: you cannot.
CakePHP magic depends heavily on information about tables and columns fetched from the INFORMATION_SCHEMA views. That information is gathered in \Sqlserver::listSources (list of tables) and \Sqlserver::describe (list of columns).
While it's possible to extend the datasource driver and reimplement these methods:
// Model/Datasource/CustomSqlserver.php
class CustomSqlserver extends Sqlserver {
}
class DATABASE_CONFIG {
public $default = array(
'datasource' => 'CustomSqlserver',
// ...
);
}
... that's just the tip of the iceberg. The data structures account for two levels:
Schema (e.g. dbo)
Table (e.g. users)
They aren't designed for an extra database level on top. As a result, you end up needing to patch so much code that it isn't worth the effort.
I've also been playing with Synonyms in SQL Server. It's a more promising path because, while you still need to write \CustomSqlserver::listSources and \CustomSqlserver::describe yourself, to most (not all) effects they behave like regular tables. The main restriction though is that there can't be duplicate table names.

You would need to add a new connection to DATABASE_CONFIG, but you could do this in the constructor so that you can inherit your default database credentials and just modify the database name:-
public function __construct() {
$this->alt = $this->default;
$this->alt['database'] = 'provincia';
}
Then in your Provincia model you can swap to the alt database connection:-
public function __construct($id = false, $table = null, $ds = null) {
parent::__construct($id, $table, $ds);
$this->useDbConfig = 'alt';
}

Related

Limit c# model class parameter call to MS SQL server for non-existing table field

Working with database-first approach creating ASPNETCORE MVC web app with user authentication, I would like to override the way the parameters from IdentityUser class are queried to the database. The reason is the current implementation of IdentityUser has two new parameters NormalizedEmail and NormalizedUserName (which in my opinion retracts from Normalization).
Is there a way I can write the code below in the Model class so that those two parameters are not included in the query to the database or is that something that needs to be done in the controller class?
public class IdentityUser : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser
{
public override string NormalizedUserName
{ get { return null; } set { value = null; } }
public override string NormalizedEmail
{ get { return null; } set { value = null; } }
}
Not far as I can tell, both parameters are part of the data model and as explained in this Issue #351
About Identity 3.0:
...Instead we compute a normalized representation of the user name and we
store it in a separate column so that lookups by normalized user name
should now be sargable.
So in other words, if you "override the way the parameters from IdentityUser class are queried to the database" in essence you'll be doing exactly the opposite the class intends to do.

laravel remember database connection per class

class DogsConfigs extends DogsModel {
protected $table = 'configs';
/**
* #return
*/
public function getAll() {
return DB::connection($this->connection)
->table($this->table)
->select('conf_key', 'conf_val', 'description')
->get();
}
}
For every functiuon which uses non default database connection - I have to call DB::connection
I know this connections is used for whole class. How could I make it default for that class so I would not need to repeat code? Same for table.
Tried to google for solutions, but what I found - does not work.
In your model you can define the connection you want to use:
protected $connection = 'connection_name';
The connection you use must be in your app/config/database.php
You can read this for more informations : http://fideloper.com/laravel-multiple-database-connections

CakePHP, creating extensible Plugin

I have several projects in CakePHP, and would like to move common code into plugins and use seperate GIT repositories for those.
For example, I created a UserManager plugin which contains MVC for users, groups and permissions.
My problem is: the different projects have different (additional) relations to the models from the plugin. E.g., one project should have "User belongsTo Location" in addition.
I'm now confused how to set this up properly. The manual tells how to override Plugin views, but not how this is done with models and controllers.
How can this be done in a clean way?
You can simply extend the plugin classes and override/add the necessary associations, just like you're probably already doing it with AppModel respectively UserManagerAppModel.
http://book.cakephp.org/2.0/en/plugins.html#plugin-models
Here's a basic example (assuming the user class in the plugin is named User):
App::uses('User', 'UserManager.Model');
class AppUser extends User
{
public $belongsTo = array('Location');
}
Or create the associations dynamically in case there are existing ones that need to be kept:
class AppUser extends User
{
public function __construct($id = false, $table = null, $ds = null)
{
parent::__construct($id, $table, $ds);
$this->bindModel(array('belongsTo' => array('Location')));
}
}

Filter data based on User field cakePHP

So I have a company based system and I am keeping all data within the one database and I separate the data by using a site_id field which is present in all tables and in the users table.
Now at the moment I am doing a condition on every single find('all'). Is there a more global way to do this. Maybe in the AppController? Even for saving data I am having to set the site_id every single save.
Something like
public function beforeFilter() {
parent::beforeFilter();
$this->set('site_id', $this->Auth->user('site_id'));
}
Any direction would only help. Thanks
TLDR:
Create a Behavior with a beforeFind() method that appends a site_id condition to all queries.
Example/Details:
Create a behavior something along the lines of the below. Note, I'm getting the siteId from a Configure variable, but feel free to get that however you want.
<?php
class SiteSpecificBehavior extends ModelBehavior {
public function setup(Model $Model, $settings = array()) {
$Model->siteId = Configure::read('Site.current.id');
}
public function beforeFind(Model $Model, $query = array()) {
$siteId = $Model->siteId;
$query['conditions'][$Model->alias . '.site_id'] = $siteId ;
return $query;
}
}
Then on any/all models where you want to make sure it's site-specific, add:
public $actsAs = array('SiteSpecific');
This can be tweaked and improved up certainly, but it should give you a good idea.

CakePHP requiring a database table

I intended to create a controller that handles a contact page. I created the controller ContactsController. The problem is that it is asking for a table with the same name:
Missing Database Table
Error: Database table
username_contacts for model Contact
was not found.
Notice: If you want to customize this
error message, create
app/views/errors/missing_table.ctp
Do I really need to create a table with no data for this?
This is my controller code:
<?php
class ContactsController extends AppController {
var $name = 'Contacts';
function index($id = null)
{
$this->set('page', ClassRegistry::init('Page')->findByShortname($id));
}
}
var $name = 'Contacts';
var $uses = array();
not to be that guy, but this is documented well.
http://book.cakephp.org
You might want to create the model anyway as you'll almost certainly find you need to do some database type stuff. It doesn't need to use a db_table:
class ModelWithoutTable extends AppModel
{
var $useTable = false;
}
Think "fat model - thin controller"

Resources