Yii Table Prefix Cannot read table with that prefix - php

I started develop in localhost, using yii 1.1.11 using the auto generate app, create users table, using gii to generate crud. When I migrate to webhosting, I have to use prefix for the table thus become "yii_users" and edit the config with this:
'db'=>array(
'connectionString' => 'xxxxx',
'username' => 'xxxxx',
'password' => 'xxxxx',
'tablePrefix' => 'yii_',
),
But I can no longer login and get error 'The table "users" for active record class "Users" cannot be found in the database. ' So I assume the tablePrefix doesn't work. How to fix this?

This requires you to change all your activerecords also, check the guide:
Info: To use the table prefix feature, the tableName() method for an AR class may be overridden ...
......
That is, instead of returning the fully qualified table name, we return the table name without the prefix and enclose it in double curly brackets
So you will need to do this:
public function tableName() {
return '{{user}}';
}
Also from tablePrefix doc:
By setting this property, any token like '{{tableName}}' ... will be replaced by 'prefixTableName', where 'prefix' refers to this property value.
(emphasis mine)

Related

How to specify the database schema to use for a Lavavel Pivot Table

Is it possible to specify the Schema for a Laravel Pivot table when attaching?
We have multiple Schemas, specific schemas for each application and the public being tables that are shared between them.
Our Laravel app has a schema that it is defaulted too in the .env file. Reaching outside the default schema is relatively painless, just needing to explicitly set the table name.
protected $table = "public.table_name_here";
The issue is when we have a pivot table in the public schema, there doesn't seem to be a way to tell Laravel to look at the public schema for it.
Ex.
//users model
public function roles() {
return $this->belongsToMany('App\Roles', 'user_role', 'userId', 'roleId')->withTimestamps();
}
$user->roles()->attach($roleId);
will always look in the laravel schema for the user_role
When I add the user_role to the laravel schema, everything works great.
I've tried to specific to use the user_role table in public by doing the following
//users model
public function roles() {
return $this->belongsToMany('App\Roles', 'public.user_role', 'userId', 'roleId')->withTimestamps();
}
Unfortunately I haven't been able to find any resources on specifying the schema for a pivot table, so any advice on if this is possible and, if so, how would be great.
Thanks in advance.
In config/database.php there is the key connections.pgsql.schema
When laravel connects to PostgreSQL uses this key to send this command to the server:
"set search_path to {$schema}"
You can set this config key to a comma separated list of schemas that will be searched in order to find a table when you don't specify a schema for the table name.
In your case you can set this key in config/database.php to something like this:
return [
//
'connections' => [
//
'pgsql' => [
//
'schema' => 'laravel,public',
With that in place your SQL queries should be able to find the public.user_role table even without specifing the schema, i.e:
public function roles() {
return $this->belongsToMany('App\Roles', 'user_role', 'userId', 'roleId')->withTimestamps();
}
Be aware that if you have a table laravel.user_role it will be found first because in the search path, as configured above, the laravel schema comes first, in this case just invert the order, like this:
'schema' => 'public,laravel',

Laravel ORM: Query without table prefix

I'm working on a project where I have to integrate with some tables form wordpress and other systems. To setup the database for my Laravel project I chose to use table a prefix and for my project tables it's working fine.
My problem is when I have to work with tables from other systems using Laravel. For example, the query below adds my project's table prefix to it:
$item = DB::table('cnp_item')
->where('code', $row[1])
->first();
Instead of querying the cnp_item table it's querying laravel_cnp_item table, which does not exist.
I know it makes sense since I configured a table prefix. My question is if there is anything I could do in some queries to make it ignore my table prefix.
Thanks for any help
You could define a different a different connection in config/database.php that omits the prefix setting:
'connections' => [
'mysql' => [
...
'prefix' => 'laravel',
...
], 'alternate' => [
...
'prefix' => '',
...
]
],
Then, if you want to query a table that doesn't have that connection, switch to it on the fly using DB::connection():
$item = DB::connection('alternate')->table('cnp_item')->where('code', $row[1])->first();
Or, if you use a Model, you should be able to define the connection and table, so you'd simply have to do:
class CNPItem extends Model {
protected $connection = 'alternate';
protected $table = 'cnp_items';
...
}
Then you'd simply query like so:
$item = CNPItem::where('code', $row[1])->first();

CakePHP 3 dynamic database connection

In the controller I want to change my default database connection, such that I can access a different database. It used to work, I created a function in the AppController, calling it in each controller when needed, containing the following:
ConnectionManager::config('database', [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
'username' => $username,
'password' => $password,
'database' => $database,
'encoding' => 'utf8',
'timezone' => 'UTC',
'cacheMetadata' => true,
]);
ConnectionManager::alias('database', 'default');
I created a new database connection, calling it 'database', and aliased default to this connection, such that instead of the default connection, this connection will be used. However, when I print
$this->{$modelName}->connection()->config();
It still gives the default connection. And an error saying the table doesn't exist, confirms I am not in the new connection's database.
Aliases are only picked up at table instantiation time
Alising connections on the fly generally works fine, but models / table classes only pick up connections up on their own once when they are being instantiated.
So if it doesn't work for a specific table, this is most probably because it has already been instantiated and picked up the default connection (the table registry only instantiates a table class once per alias).
So, either make sure that the tables are being instanted afterwards, which may require clearing (TableRegistry::clear()) / removing from (TableRegistry::remove()) the registry if the alias needs to be created late in the request cycle (which however could cause other problems, as you'd loose possibly applied dynamic configuration), or set the connection on the involved table(s) manually:
\Cake\Datasource\ConnectionManager::alias('database', 'default');
$connection = \Cake\Datasource\ConnectionManager::get('default');
$this->{$modelName}->setConnection($connection); // connection() before CakePHP 3.4
Apply connections dynamically in a more automated fashion
If you need this on multiple, or maybe all tables, or if you just want to shift away the responsibility from the controller (it most probably shouldn't be overly involved in configuring the model layer), then maybe dispatch an event when creating the alias, and use a base table class or a behavior that listens to the event, or maybe even use a "service" that knows about the tables and updates the tables connections accordingly.
\Cake\Datasource\ConnectionManager::alias('database', 'default');
$connection = \Cake\Datasource\ConnectionManager::get('default');
$event = new \Cake\Event\Event('Connection.aliased', $connection, ['source' => 'default']);
\Cake\Event\EventManager::instance()->dispatch($event);
For example in a table you could then do something like this, applying the new connection in case the table is configured to use the connection that has been aliased, ie if defaultConnectionName() === 'default', then pick up the new connection:
\Cake\Event\EventManager::instance()->on(
'Connection.aliased',
function (\Cake\Event\Event $event) {
// data() before CakePHP 3.4
if ($event->getData('source') === static::defaultConnectionName()) {
$this->setConnection($event->getSubject()); // subject() before CakePHP 3.4
}
}
);
See also
Cookbook > Events
Cookbook > Database Access & ORM > Behaviors
I built a sample project with dynamic connections based on the session variable.
I hope somebody find it useful:
https://github.com/jszoja/cakephp3-multidb
I documented it there.

Laravel 5.3 Creating Models Returns "Field doesn't have a default value"

I'm using Laravel and Eloquent for two years and today I've decided to install a fresh Laravel 5.3 and try something with it.
I used an old database schema of mine and created my models, defined fillable columns. This is what my Page model looks like:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Page extends Model
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'language',
'title',
'slug',
'url',
'description',
'tags',
'wireframe',
'order',
'is_active'
];
public function menus()
{
return $this->belongsToMany(Menu::class);
}
}
url attribute is a TEXT-type column on MySQL so if I don't pass any value to it when creating a model, it should be a empty string. Instead, I keep getting SQLSTATE[HY000]: General error: 1364 Field 'url' doesn't have a default value error.
Here is my attempt to create a Post model:
Page::create([
'title' => $root_menu['title'],
'slug' => $root_menu['slug'],
'language' => $this->language,
'wireframe' => key(config('cms.wireframe')),
'order' => 0
]);
Is this a Laravel 5.3 related issue or am I missing something? Thanks in advance for your helps.
The reason for the error has been explained by #Nicklas.
The reason this is happening now, however, is that Laravel 5.3 uses strict mode for MySQL by default.
If you would like to revert to previous behavior, update your config/database.php file and set 'strict' => false for your connection.
You are trying to insert an object, with no 'URL' attribute, into a table that has a 'URL' column without a default value. So the database can't know what to do with that column.
You can do one of three things.
Fill in the URL value in the create
Change your schema to allow null insertion on URL
Change the URL schema to include a default value. (empty string)
Post your migration or schema, if you need further help.

Laravel changing Database

I'm rather new to Laravel 4. What I have is a bunch of sports statistics information and for organization purposes I have a database for every sport (NFL, MLB, etc...). What I want to do is change the DB easily in queries and mimic the functionality of $myslqi->select_db() but aside from setting up a bunch of database connections in the config file, I can't find a way to do what I'm looking for. It's all the same connection and same user, I just want to be able to switch the DB without having to insert a variable into SQL in order to point to the right database.
You will need to define the connections in the config/database like so:
'nba' => array(
'driver' => 'mysql',
...
),
'nfl' => array(
'driver' => 'mysql',
...
),
And then use these in models schema or queries
class NbaPlayers extends Eloquent {
protected $connection = 'nba';
//other stuff on your model
}
$nflplayers = DB::connection('nfl')->whatever
If you define the connection in the model, you will use model::all() or whatever without having to define the connection everytime

Categories