What's going wrong with my migrations on CakePHP 4? - cakephp

I've applied a couple of minor changes to the database structure for my app, adding new columns to a table called Plots. This is one of the migrations -
declare(strict_types=1);
use Migrations\AbstractMigration;
class AddGarageToPlots extends AbstractMigration
{
public function change()
{
$table = $this->table('plots');
$table->addColumn('garage', 'string', [
'default' => null,
'limit' => 255,
'null' => true,
]);
$table->update();
}
}
When I apply the migration it seems to run fine: there are no errors and I can see the new column in the database if I connect directly to it but when I try to access data in the new field in a view using, for example, <?= $plot->garage ?> it consistently returns null even though I have populated this field via the direct connection.
Is there something else I need to do that I'm missing here or is there some way I can check that the migration has worked properly like a schema file somewhere?

Found the answer to my own question by reading slightly further in the documentation - migrations and deployment.
I needed to run bin/cake schema_cache clear

Related

setTable not working as expected with a legacy database in CakePHP 3.x

I have a legacy (not written to Cake naming conventions) database on a CakePHP 3.5.13 application.
One of the database tables is named article_95.
When I attempted to bake the application it's showing the entity name as Article95. It's then producing loads of error messages saying:
Table 'article95' doesn't exist
So I've read CakePHP error: cake bake is using the wrong table name and How to use table name different then in database in cake php 3 and decided to do it manually using setTable().
So I have created src/Model/Table/Article95Table.php with the following code in it:
namespace App\Model\Table;
use Cake\ORM\Table;
class Article95Table extends Table
{
public function initialize(array $config)
{
$this->setTable('article_95');
}
}
But it won't seem to recgonise this. In a controller I've created a testing method and done the following:
Cache::clear(false);
$Article95 = TableRegistry::get('Article95');
debug($Article95->find()->list());
But it's coming up with:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'article95' doesn't exist
It's as if it's not reading the setTable() method.
I've used the Cache::clear(false) to ensure it's not being cached and have inspected the tmp/cache directory for any suspect files - nothing relevant in there.
Any ideas?
Equally if I change my debug() statement to just debug($Article95) I get the following, with the wrong table name:
object(Cake\ORM\Table) {
'registryAlias' => 'Article95',
'table' => 'article95',
'alias' => 'Article95',
'entityClass' => '\Cake\ORM\Entity',
'associations' => [],
'behaviors' => [],
'defaultConnection' => 'default',
'connectionName' => 'default'
}
Incidentally, if I put a non-existent class/entity name in TableRegistry::get() - for example TableRegistry::get('dsfdsfdsfsd'); it won't produce an error message but will show the object above with the non-existent table name. Surely this is also wrong?
I've managed to get this working so wanted to share my solution.
After some trial and error it seems that appending an 's' to the class name (presumably to make Cake consider it plural?) works.
So I renamed the Table class to Article95sTable.php and then used the following code inside:
class Article95sTable extends Table
{
public function initialize(array $config)
{
$this->setTable('article_95');
}
}
Now when I call the following it picks up the table correctly:
$foo = TableRegistry::get('Article95s');
debug($foo);
To confirm this is working if I rename the table inside my setTable() method the output will change accordingly.

TYPO3 saving Backend content in another database

I want to store content from my Backend in another database.
So let's say i have this in my Backend:
How can i save the value (e.g. the float value in the picture) in another database?
The reason why i need this, is, because i have another database, which is being used for some dynamic content loaded onto my Website with PHP.
Hopefully, someone has an idea and can help me :)
I would use either a hook which updates the foreign database with the value which is triggered if something is changed in the TYPO3 backend or I would use a scheduler task / command controller which is triggered by CLI and runs all x minutes and changes the values in the database.
There are several ways to achieve that. I just assume that you want to create relations between the tt_content table of TYPO3 and some external table in a different database or even different storage engine (web-service, file-system, ...).
In that case you could extend the TCA of the tt_content table by an additional property, let's call it external_reference. The backend form then should provide an additional selector field that allows to chose entities of the external data-source.
The following example assumes that your extension key is called my_extension, this has to be adjusted of course to the actual naming.
You can do so by putting the following configuration to your extension in the folder typo3conf/ext/my_extension/Configuration/TCA/Overrides/tt_content.php:
<?php
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns(
'tt_content',
[
'external_reference' => [
'exclude' => 1,
'label' => 'External Source',
'config' => [
'type' => 'select',
'items' => [
['-- none --', 0]
],
'itemsProcFunc' => ExternalReferenceSelection::class . '->render',
'default' => 0,
]
],
]
);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
'tt_content',
'external_reference'
);
Then you have to implement the selector and the retrieval from the external source, like e.g.
<?php
class ExternalReferenceSelection
{
public function render(array $parameters)
{
$references = ExternalReferenceRepository::instance()->findAll();
foreach ($references as $reference) {
$parameters['items'][] = [
$reference->getTitle(),
$reference->getIdentifier()
];
}
}
}
To be able to persist the selected reference, you have to extend the SQL schema of tt_content as well in typo3conf/ext/my_extension/ext_tables.sql
#
# Table structure for table 'tt_content'
#
CREATE TABLE tt_content (
external_reference int(11) unsigned DEFAULT '0' NOT NULL
);
The database schema is updated by invoking the database analyzer in the TYPO3 Install Tool, or by (re-)installing the extension in the Extension Manager.

CakePHP read() is not returning a model name

I am having trouble with my cakePHP and wondering if anyone else has experienced this. I am trying to setup a User object. I create the Model:
class User extends AppModel
{
}
I create the controller:
class UsersController extends AppController
{
function view($id = null) {
$this->User->id = $id;
$this->set('users', $this->User->read());
}
}
and I go to the view page. However, I am not getting what the cake documentation says I should be getting. I am getting:
Array
(
[0] => Array
(
[id] => 3
[FirstName] => 1
[LastName] => 1
)
)
when what I am expecting to see is
Array
(
[User] => Array
(
[id] => 3
[FirstName] => 1
[LastName] => 1
)
)
Also when I do a $this->User->find('all'); I get back an array like so:
Array
(
[0] => Array ([0] => Array (/*stuff here*/))
[1] => Array ([0] => Array (/*stuff here*/))
[2] => Array ([0] => Array (/*stuff here*/))
)
I have tried changing the name to Myuser (including the database table, controller, model, etc) and still have the same results, so I don't think it's related to a reserved keyword.
Has anyone run into this or, more importantly, does anyone have a clue how I might fix it? Thanks.
EDIT:
I am using cake version 2.0.6. I am using a MySQL 5.0.92 database. I just have tried setting the name variable and it did not change my results.
After an ENTIRE DAY of troubleshooting, I finally was able to solve it.
The cause is definitely an outdated pdo_mysql.so library. This is located in /usr/local/lib/php/extensions/(latest directory)/pdo_mysql.so
The table name being returned in getColumnMeta was only added in a certain version due to this function request:
https://bugs.php.net/41416/
Now, the problem is, in some web hosts, PHP needs to be compiled with Easy Apache. Mine had to go through that as well just in order to enable PDO (it was initially disabled). But the problem is, for some reason, Easy Apache is downloading some obsolete source code everytime it runs. Running yum or installing any RPMs don't help either.
So here is what I did:
- I downloaded the latest PHP sources from the PHP site, extracted the tarball
- I ran Easy Apache, did a recompilation, and very quickly went to the console to watch it redownload the outdated PHP sources
- When the PHP sources have reappeared, I very quickly replaced the entire ext/pdo_mysql directory with the latest sources
- Easy Apache will compile httpd first, so you have some time to do the above step
- After the build is done, reboot.
- To check if your version of pdo_mysql.so supports the table name, execute this command:
strings -f pdo_mysql.so | grep ': table'
- There should be an entry there. The old version doesn't.
- By the way, I noticed that there are more copied of the pdo_mysql.so in /usr/lib/php/modules and /usr/lib/php/extensions, but it seems that the one in /usr/local is the one that is active. Nevertheless, I update all copies manually
NOTE: if you just try to update the pdo_mysql.so file, it will not work. You will get a segmentation fault, and the pages will render nothing. You need to recompile PHP using the above steps.
I hope this will help other people who will come across this bug.
Be sure your table is named users and include the association explicitly
class User extends AppModel {
public $name = 'User';
public $useTable = 'users';
...
You need to set the $uses variable to associate the User model with the controller if you are using any additional models. Adding it explicitly even if there's just one will not hurt either...
for example
class UsersController extends AppController {
//Controller Name
public $name = 'Users';
//DB Config for desired connection
public $useDbConfig = 'test';
// Array of associated models
public $uses = array('Store','User');
//Array of Helpers used by Controller Views
public $helpers = array('Html', 'Form');
...
Also, check to be sure there are no edits in AppModel or AppController which may be accidentally contributing to the interactions here... You may also consider dumping the value of the $uses to see what's there.
Finally found out that the reason for it has to do with a function called PDOStatement::getColumnMeta. This gets called on the queries that cakePHP runs is used by the framework to get the column name, column type, and table name. However, for whatever reason, on the webhost I currently have, this function does not return the table name so cakePHP defaults to creating the array with a 0 index rather than a table name index.
$column = $results->getColumnMeta($index);
if (!empty($column['table']) && strpos($column['name'], $this->virtualFieldSeparator) === false) {
$this->map[$index++] = array($column['table'], $column['name'], $type);
} else {
$this->map[$index++] = array(0, $column['name'], $type);
}
still not sure how to fix it yet, but this is definitely why it is happening.
Yes, you are right. beastmaster
The reason why is that u using old version of PDO driver which has been been deprecated. the PDOStatement::getColumnMeta does not show [table]=name in old version
So solution here download new version of PHP which has build-in PDO. DO NOT INSTALL PDO VIA PECL coz u getting old version of PDO extension. and using
<?php phpinfo ?>
to check if it is installed properly. so u can use native PDO driver coming with PHP rather than use extension PDO driver.
By the way, Thank you for point out the problem.
I have just faced the problem. The cause was not an outdated pdo_mysql.so library.
If you use cakephp 2.3.x and make sure to use PHP 5.2.8 or greater, you should check whether the pdo_mysql extension is enabled or disabled.
You can echo phpinfo() to check it.
Note: the pdo_mysql extension is only enabled if you see "PDO Driver for MySQL enabled", otherwise it is disabled.

CakePHP - toMany relationship not working with UUIDs

I have the following model class:
class Property extends AppModel
{
var $name = 'Property';
var $hasMany = array(
'Inventory' => array(
'className' => 'Inventory',
'foreignKey' => 'property_id'
)
);
}
My database schema is set so that the id fields are all set to CHAR(36) so that CakePHP generates UUIDs for each entity. When I attempt to perform a find on my Property entity, it doesn't seem to be adding the necessary join to retrieve any related Inventories. Does anyone have any experience with this issue?
Thanks!
UUIDs will have nothing to do with it, I have a very similar model setup and use UUIDs everywhere.
You technically don't need those className and foreignKey declarations in there, as you seem to be following the CakePHP convention :)
I'd remove those lines, check your database for actual inventories with product IDs. If not, post the find()s you're doing.
The answer turns out to be somewhat stupid.
I'd migrated this from a CakePHP 2.0 install to a CakePHP 1.3 install (couldn't update PHP on the server I was using), and all of my model classes still had uppercase first characters. Changing the file from Property.php to property.php fixed it.

CakePHP model useTable with SQL Views

I'm in the process converting our CakePHP-built website from Pervasive to SQL Server 2005. After a lot of hassle the setup I've gotten to work is using the ADODB driver with 'connect' as odbc_mssql. This connects to our database and builds the SQL queries just fine.
However, here's the rub: one of our Models was associated with an SQL view in Pervasive. I ported over the view, but it appears using the set up that I have that CakePHP can't find the View in SQL Server.
Couldn't find much after some Google searches - has anyone else run into a problem like this? Is there a solution/workaround, or is there some redesign in my future?
First of all, which version of CakePHP are you using? I'll assume it's about CakePHP 1.2+.
The problem
I'm not familiar with SQL Server 2005 (nor any other versions), but after some investigation, I think the problem is in DboMssql::listSources() method, which selects available table names from INFORMATION_SCHEMA.TABLES and so it doesn't "see" any available views.
The solution
Change DboMssql::listSources() to select available table names from sys.tables or, if I'm wrong about sys.tables, to additionally select names from INFORMATION_SCHEMA.VIEWS.
So, not to mess with CakePHP core files, you'll have to create custom datasource, which extends DboMssql and overrides ::listSources() method. To do so, you'll have to:
Create <path/to/app>/models/datasources/dbo/dbo_custom_mssql.php:
<?php
App::import('Datasource', 'DboMssql');
class DboCustomMssql
extends DboMssql
{
public
function listSources()
{
$cache = DboSource::listSources();
if ($cache != null) {
return $cache;
}
$result = $this->fetchAll('SELECT TABLE_NAME FROM SYS.TABLES', false);
if (!$result || empty($result)) {
return array();
} else {
$tables = array();
foreach ($result as $table) {
$tables[] = $table[0]['TABLE_NAME'];
}
DboSource::listSources($tables);
return $tables;
}
}
}
Change config/database.php config: 'driver' => 'custom_mssql'
Test
NB: The worst thing is that DboMssql::listSources() interface is kinda broken (w/o optional $data argument (like Datasource::listSources() declares)) and doesn't provide any point of extension, so, in order to have source list caching, we're forced to call DboSource::listSources() instead of broken parent::listSources().
I have SQL Server views being happily displayed. The main difference that I have to you is that I am using the mssql driver rather than the odbc_mssql driver. Perhaps you should try switching to that and figure out whatever problems you have there first.

Resources