CakePHP 3.x UnitTest "Base table or view not found" - mysql

I get an Error-Message in a UnitTest in CakePHP 3.2 and the official documentation doesn't help me here anymore. I think the error has something todo with the SQL-Joins I try to use.
The Error-Message is the following:
`1) App\Test\TestCase\Controller\GetContentControllerTest::testIndex
PDOException: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'contentmapper_test.CmDeviceclasses' doesn't exist`
In my Testclass GetContentControllerTest I load my fixtures that I need and that creates my Database-Tables on start:
`public $fixtures = [
'app.cm_content_options',
'app.cm_content_addresses',
'app.cm_deviceclasses',
'app.cm_properties'
];`
In the setUp()-Method I load the Main-Table:
`public function setUp()
{
parent::setUp();
$this->CmContentOptions = TableRegistry::get('CmContentOptions');
}`
My Test-Method testIndex() looks like this:
public function testIndex()
{
//find the belonging ContentOption to address data
//submitted by the client
$this->testFindAllByUriAndDeviceclassAndBoxId();
assert($this->arrObjContentOptions->count() == 1);
}
The testFindAllByUriAandDeviceclassAndBoxID() looks like shown in the following Image (the Editor is not able to prettyprint it correctly):
testFindAllByUriAandDeviceclassAndBoxID()
It's hard to describe the whole Context; I hope it is possible to understand.
The Error happens exactly on the statement shown in the image:
$result = $query->toArray()
I think I just forgot something to add in the setUp() Method or something like that.
I hope anyone can help.

You joins are set up incorrectly, you're mixing up aliases and table names.
The alias is the key of the join array, and the table key should hold the actual database table name, not the table class name.
Given that you are following CakePHPs naming conventions for your database table names, your join setup should look more like this
[
'CmDeviceclasses' => [ /* < this is the SQL alias */
'table' => 'cm_deviceclasses', /* < this is the database table name */
'type' => 'LEFT',
'conditions' => [
'CmDeviceclasses.classname' => $this->deviceclass
]
],
'CmContentAddresses' => [
'table' => 'cm_content_addresses',
'type' => 'INNER',
'conditions' => [
'CmContentAddresses.uri' => $this->uri,
'CmContentAddresses.boxid' => $this->boxid,
]
],
],
[
'CmDeviceclasses.classname' => 'string',
'CmContentAddresses.uri' => 'string',
'CmContentAddresses.boxid' => 'string'
]
There is no technical need to follow the CamelCase conventions for the aliases, but for sure it doesn't hurt to generally stick to the conventions.
ps, if you setup the associations properly, then there should be no need to use manual joins, you could just use Query::contain() and Query::innerJoinWith() or Query::matching().
See
Cookbook > Database Access & ORM > Associations - Linking Tables Together
Cookbook > Database Access & ORM > Retrieving Data & Results Sets > Retrieving Associated Data
Cookbook > Database Access & ORM > Retrieving Data & Results Sets > Filtering by Associated Data

Related

How to query .tab pages from local wikidata instance using API

I am using the Extension:JsonConfig on my docker instance of wikidata that has some tables loaded onto it. The configuration for the extension in my LocalSettings.php is as follows,
$wgJsonConfigEnableLuaSupport = true;
$wgJsonConfigModels['Tabular.JsonConfig'] = 'JsonConfig\JCTabularContent';
$wgJsonConfigs['Tabular.JsonConfig'] = [
'namespace' => 486,
'nsName' => 'Data',
// page name must end in ".tab", and contain at least one symbol
'pattern' => '/.\.tab$/',
'license' => 'CC0-1.0',
'isLocal' => true,
'store' => true,
];
When i query the local instance using the following url,
http://<DOMAIN_HERE>/w/api.php?action=query&list=search&srsearch=tab contentmodel:Tabular.JsonConfig &srnamespace=486&srlimit=10&format=json
i receive the following response
{"batchcomplete":"","limits":{"search":10},"query":{"searchinfo":{"totalhits":0},"search":[]}}
which means that no matches have been found even though tables that match the query statement do exist.
This same query works with commons database when the following is done
https://commons.wikimedia.org/w/api.php?action=query&list=search&srsearch=tab%20contentmodel:Tabular.JsonConfig%20&srnamespace=486&srlimit=10&format=json
Can anyone point me out as to what i am doing wrong here?

Laravel: Store error messages in database

Any one know how to send error messages to database in laravel which generate from app/exceptions/handler.php ?
I need to send what error massages generated in report() method to database.
If you are interested doing this manually, you can do something as following.
Step 1 -
Create a model to store errors that has a DB structure as following.
class Error extends Model
{
protected $fillable = ['user_id' , 'code' , 'file' , 'line' , 'message' , 'trace' ];
}
Step 2
Locate the App/Exceptions/Handler.php file, include Auth, and the Error model you created. and replace the report function with the following code.
public function report(Exception $exception) {
// Checks if a user has logged in to the system, so the error will be recorded with the user id
$userId = 0;
if (Auth::user()) {
$userId = Auth::user()->id;
}
$data = array(
'user_id' => $userId,
'code' => $exception->getCode(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'message' => $exception->getMessage(),
'trace' => $exception->getTraceAsString(),
);
Error::create($data);
parent::report($exception);
}
(I am demonstrating this using laravel 5.6)
Because Laravel uses Monolog for handling logging it seems that writing Monolog Handler would be the cleanest way.
I was able to find something that exists already, please have a look at monolog-mysql package. I did not use it, so I don't know whether it works and if it works well, but it's definitely good starting point.

CakePHP 3: Best Practice for Temporary SQL Tables

Dear CakePHP 3 developers,
I'd like to use SQL's Temporary Tables in a CakePHP 3.4.13 project for a single run through a script. Going through Cake's documentation, there seems no direct way to tell CakePHP my desire. How would I best go about it, then?
I've prepared a Table in src/Model/Table/TempItemsTable.php:
namespace App\Model\Table;
use Cake\ORM\Table;
class TempItemsTable extends Table
{
public $fields = [
'id' => ['type' => 'integer'],
'con' => ['type' => 'string', 'length' => 255, 'null' => false],
'_constraints' => [
'primary' => ['type' => 'primary', 'columns' => ['id']]
]
];
public function initialize(array $config)
{
// $this->setTable(null);
}
}
The idea to use $fields to tell CakePHP the desired table schema comes from a possibly unrelated documentation for Test Fixtures.
But how do I tell CakePHP not to look for an actual table in the database?
The uncommented line $this->setTable(null); was my poor attempt at that, which is supposedly similiar to the right way in earlier versions of CakePHP, but according to version 3.x documentation, setTable() doesn't accept null, while table() does, but it's deprecated as of 3.4 and also didn't change anything.
Finally, of course, I get this exception as soon as I try to access this "table" in a controller via $temp = TableRegistry::get('TempItems');:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'mydatabase.temp_items' doesn't exist
Help, I'm stuck. :(
There's no need to tell it to not look for the table, actually that's the opposite of what you want to do, given that you eventually want to access it.
The table class should basically be configured as usual, and you should create the temporary database table before the application causes it to be accessed. You can either write the raw table creation SQL manually, or generate it from a \Cake\Database\Schema\TableSchema instance, which supports temporary tables.
You can either explicitly create the schema object:
$schema = new \Cake\Database\Schema\TableSchema('temp_items');
$schema
->addColumn('id', ['type' => 'integer'])
->addColumn('con', ['type' => 'string', 'length' => 255, 'null' => false])
->addConstraint('primary', ['type' => 'primary', 'columns' => ['id']])
->setTemporary(true);
$TableObject->setSchema($schema);
or let the table object generate it, using your fields definition array:
$TableObject->setSchema($TableObject->fields);
$schema = $TableObject->getSchema()->setTemporary(true);
You can then generate the table creation SQL from the schema object and run it against the database:
$connection = $TableObject->getConnection();
$queries = $schema->createSql($connection);
$connection->transactional(
function (\Cake\Database\Connection $connection) use ($queries) {
foreach ($queries as $query) {
$stmt = $connection->execute($query);
$stmt->closeCursor();
}
}
);
$queries would be an array of SQL commands required to create the table, something along the lines of:
[
'CREATE TEMPORARY TABLE `temp_items` (
`id` INTEGER AUTO_INCREMENT,
`con` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`)
)'
]
Note that if you do not assign the schema to the table object, you could run into caching problems, as the cached schema wouldn't match anymore when you change the table definition and do not clear the cache.
See also
Cookbook > Database Access & ORM > Schema System
Cookbook > Database Access & ORM > Database Basics

Select default schema for MS SQL

I need to configure Yii2 to work with Microsoft SQL server.
The db configuration file (db.php) is something like this
return [
'class' => 'yii\db\Connection',
'dsn' => 'sqlsrv:Server=192.168.77.111;Database=xyz',
'username' => 'xy',
'password' => 'xyz',
This works only if i add before the table name in the tableName() function inside all models the correct schema name.
For example:
public static function tableName()
{
return '{{%xyzschema.users}}';
}
How can i set the db configuration so xyzschema is always added when connecting to the table?
I tried with tablePrefix and schemaMap with defaultSchema but it doesn't work
The error returned is
Invalid object name 'users'.
or
Invalid object name 'xyzschema.users'.
If i add tablePrefix to db.php
Update: The defaultSchema property inside connection's schemaMap/Schema config array gets ingored
For this case i solved changing the schema to the standard "dbo" for each table.

Cakephp 3 + CounterCache with prefixed plugin

Let's assume we have two models:
Foo/Blog.posts and Foo/Blog.categories.
I want to update categories.post_count fields each time a new post is created.
I attached the CounterCache behavior in Foo\Blog\Model\Table\PostsTable like this (in my initialize func):
$this->addBehavior('CounterCache', [
'Categories' => ['post_count']
]);
But when I try to add a new post, I have an error like this:
Base table or view not found: 1146 Table 'my-db.categories' doesn't exist
Any idea?
Tx for your help
I found what it doesn't work.
My relationships between Foo/Blog.posts and Foo/Blog.categories was incorrect. I forgot the plugin prefix.
The correct relationships declaration:
$this->belongsTo('Categories', [
'className' => 'Foo/Blog.Categories'
]);