I am trying to get Propel to work in my Zend app, it seems that I can get the Propel library to load (from library/propel) but when called I get the exception: 'No connection information in your runtime configuration file for datasource [default]' (when I try to make a connection: 'Propel::getConnection'). My Db is not even named 'default'. I have this in my bootstrap.php from another SO question/answer:
require_once 'propel/Propel.php';
Propel::setConfiguration($this->getOptions('propel/MyPropel-conf.php'));
Propel::initialize();
// so we can get the connection from the registry easily
return Propel::getConnection();
I want the Propel configs (classmap conf as well) to be in the '/application/configs' (copies are there too right now), but I thought If I can get Propel to load from library/propel, then maybe moving my 'conf' files there, I may get them to load too. It seems that if I 'force' the config, by manually loading the params, or if I seem to get it in a temporary 'right' location (or use an absolute path), the exception I then get is this:
'Unable to open PDO connection [wrapped: SQLSTATE[28000] [1045] Access denied for user 'www-data'#'localhost'
As if Propel is not paying any attention to my configs.
My config looks like this; converted from the xml:
$conf = array (
'datasources' =>
array (
'unmActTestDB' =>
array (
'adapter' => 'mysql',
'connection' =>
array (
'dsn' => 'mysql://root:PASSWORD#localhost/unmActTestDB',
),
),
'default' => 'unmActTestDB',
),
'log' =>
array (
'ident' => 'propel-act',
'level' => '7',
),
'generator_version' => '1.5.6',
);
$conf['classmap'] = include(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'classmap-unmActTestDB-conf.php');
return $conf;
If it helps, I still have the Zend PDO DB adapter loading in the application.ini file too, would that cause a clash?. Is there a standard way to get Propel to work with Zend? Or can anyone see what I'm doing wrong?
I have been to several posts here on SO, and a couple popular posts like this one The Adventures Of Merging Propel With Zend Framework and this one at Zend's dev zone Integrating Propel with the Zend Framework, among others including the Propel Docs. They have been helpful, but I am really struggling with this. Thanks in advance! My current Zend Directory structure looks like this (w/ the two propel confs also in the library/propel folder:
What I ended up doing is this:
I got a good grip on how to generate my models from a 'reverse' using Propel. It created (as before) a 'schema.xml' file for me to build my models with.
Also my 'runtime.xml' file was incorrect for my needs, after the build I was not connecting to the right database because of my omission of a few tags, overall it is quite simple though:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<log>
<ident>unmActTestDB</ident>
<level>7</level>
</log>
<propel>
<datasources default="unmActTestDB">
<datasource id="unmActTestDB">
<adapter>mysql</adapter>
<connection>
<dsn>mysql:host=localhost;dbname=unmActTestDB</dsn>
<user>zend</user>
<password>PASSWORD</password>
<database>unmActTestDB</database>
</connection>
</datasource>
</datasources>
</propel>
</config>
The 'dsn' tag has to be in the format above with the addition of the 'user', 'password', and the 'database' tags. This fixed my issue with the database connection errors. As quoted above (and here) the exception thrown was: 'No connection information in your runtime configuration file for datasource [default]'
As far as the loading of my models goes, I ended up putting them in my 'library' folder, I already have that folder autoloading in my app, plus it seemed like a good place form them.
here is an image of my 'updated' directory structure:
Note the addition of the 'unmActTestDB' folder in my directory, this is my ORM models.
Another thing to note is that I put my generated 'conf' files into my 'application/configs' folder. These are correct now, after the correction of the runtime.xml file and a 'rebuild'.
As a side note, I had to edit my 'schema.xml' file by hand (several times :) )...The original database used plural names for the tables, so I edited all the 'phpname' declarations (attributes actually, on the declaration tag) to be singular so I wouldn't access an object called 'Users'...instead I can now access a 'User' object. I kept the table names the same (tables are plural, and I won't have any issues importing the existing data, etc.) This was suggested by an answer to another one of my questions, see here How to get related object Propel ORM.
The other big edit I made was to add primary key declarations (again, attributes) for the many SQL views in the DB, also I added a 'readonly' and a 'noSQL' attributes to the declarations, this way I will have access (through the Propel models) to my views.
And, just to be thorough, and for those who are interested here is the addition to my 'bootstrap.php' file that does my 'Propel Init' for me...
protected function _initPropel()
{
$this->_logger->info('Bootstrap ' . __METHOD__);
require '../library/propel/Propel.php';
Propel::init(APPLICATION_PATH . '/configs/unmActTestDB-conf.php');
Propel::initialize();
return Propel::getConnection();
}
Another NOTE: the '$this->_logger->info('Bootstrap ' . METHOD);' calls my 'logging' method that just tells 'firePHP' that this method has loaded. The /configs/unmActTestDB-conf.php' calls the second 'conf' file that Propel generates... and here is the 'corrected' version of that file (the unmActTestDB.conf file that is), Note the changes in the 'connection' array.
<?php
// This file generated by Propel 1.5.6 convert-conf target
// from XML runtime conf file runtime-conf.xml
$conf = array (
'datasources' =>
array (
'unmActTestDB' =>
array (
'adapter' => 'mysql',
'connection' =>
array (
'dsn' => 'mysql:host=localhost;dbname=unmActTestDB',
'user' => 'zend',
'password' => 'PASSWORD',
'database' => 'unmActTestDB',
),
),
'default' => 'unmActTestDB',
),
'log' =>
array (
'ident' => 'unmActTestDB',
'level' => '7',
),
'generator_version' => '1.5.6',
);
$conf['classmap'] = include(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'classmap-unmActTestDB-conf.php');
return $conf;
I am off and running now! This was a great way to go, otherwise I was looking and writing sooo many mapping classes for my app. Propel (currently) generates over 300 models for this application! Plus the base classes, it would take me forever...
Related
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
I am required to employ webEdition as the CMS for a web presence, which shall contain a form realised with CakePHP.
Unfortunately, both systems employ directory structures, which are incompatible with each other: CakePHP requires an "app"-folder with several subfolders, "Model", "View", "Controller", whereas webEdition provides (php) template files, from which the frontend (html) files are generated via a http-backend that must stay functional (as it is the point of using webEdition in the first place).
As such, while I can put the model and controller files into their respective CakePHP-folders, I need to write the view code into the webEdition templates. CakePHP offers configuration files to move its whole "app"-folder into arbitrary places, but this is arguably not what I require.
To summarise, the situation looks as follows:
webEdition needs the templates to go to [webroot]/webedition/we/templates/[file].php
CakePHP needs the View files to go to [arbitrary]/app/View/[controller name]/[file].[extension]
the View code must go into the template
references to the View code must reference the published files [webroot]/[file].html
Obviously these requirements are incompatible. Mayhap my understanding is wrong to begin with, but even if not, there should (hopefully) exist an alternate way to realise this.
The requirements are obviously incompatible but there are several ways to work around that:
Make the CakePHP form using AJAX or an iframe to call the CakePHP app directly
Let webEdition deal with the form completely on it's own but write to the DB table the Cake app is using
Have a RESTful API you cann call from the webEdition page and POST the data to the CakePHP app.
It seems that via this setting in the app/Config/bootstrap.php file, the webroot folder may be specified as View folder - which is arguably more of a hack, but should allow to write cakePHP view code directly into a webEdition template, from where it would be carried through to the published file.
/**
* The settings below can be used to set additional paths to models, views and controllers.
*
* App::build(array(
* 'Model' => array('/path/to/models/', '/next/path/to/models/'),
* 'Model/Behavior' => array('/path/to/behaviors/', '/next/path/to/behaviors/'),
* 'Model/Datasource' => array('/path/to/datasources/', '/next/path/to/datasources/'),
* 'Model/Datasource/Database' => array('/path/to/databases/', '/next/path/to/database/'),
* 'Model/Datasource/Session' => array('/path/to/sessions/', '/next/path/to/sessions/'),
* 'Controller' => array('/path/to/controllers/', '/next/path/to/controllers/'),
* 'Controller/Component' => array('/path/to/components/', '/next/path/to/components/'),
* 'Controller/Component/Auth' => array('/path/to/auths/', '/next/path/to/auths/'),
* 'Controller/Component/Acl' => array('/path/to/acls/', '/next/path/to/acls/'),
* 'View' => array('/path/to/views/', '/next/path/to/views/'),
* 'View/Helper' => array('/path/to/helpers/', '/next/path/to/helpers/'),
* 'Console' => array('/path/to/consoles/', '/next/path/to/consoles/'),
* 'Console/Command' => array('/path/to/commands/', '/next/path/to/commands/'),
* 'Console/Command/Task' => array('/path/to/tasks/', '/next/path/to/tasks/'),
* 'Lib' => array('/path/to/libs/', '/next/path/to/libs/'),
* 'Locale' => array('/path/to/locales/', '/next/path/to/locales/'),
* 'Vendor' => array('/path/to/vendors/', '/next/path/to/vendors/'),
* 'Plugin' => array('/path/to/plugins/', '/next/path/to/plugins/'),
* ));
*
*/
... Not yet tested though and obviously not fit for a production system.
I've set up web services using Drupal's services module. It outputs JSON for me which I am requesting through a Backbone.js front-end application.
I'm having issues with this set-up. If I request data through Backbone.js' fetch method of a model, the model's attributes are all typed as string after fetching, while there are some attributes that should be e.g. integer.
For example:
I have enabled the user resource, which is standard available in the Drupal services module
I can request a user, e.g.:
http://mydevmachine/services/user/8
...which results in the following response (slimmed down version from the real response):
{"uid":"8","name":"itsme","mail":"me#mydomain.nl"}
What I see in the response from the web service above, all values are quoted, however uid is really not a string but an integer in the database.
If I fetch the same user in my Backbone.js model, by setting the uid field of my model to 8 (integer), then call the fetch method. After fetching the uid field is typed as 'string'.
I assume the above leads to my model ending up with a uid attribute of not integer, but string. It also happens with all other web service resources I have created, using my own entities.
I need correct typing of attributes in my model due to sorting issues using Backbone's collection sorting. I.e. sorting a collection of models using a field of type 'integer' leads to different sorting results when sorting the field with the same values although stored as a string.
I'm not sure exactly where to look:
Is the JSON format output by the Drupal services module according to standards?
Is the JSON output format configurable or overridable in the Drupal services module?
Is it perhaps possible to keep the type of a model's attribute after a fetch in Backbone.js?
Should I provide a specific implementation for Backbone's collection comparator function, which handles this situation (seems hackey)?
Should I introduce other solutions, e.g. like posted here: How can I enforce attribute types in a Backbone model? (feels too heavy).
Thanks for any help.
So I finally managed to crack this issue and I found my solution here: How to get numeric types from MySQL using PDO?. I thought I'd document the solution.
Drupal 7 uses PDO. Results fetched using PDO, using Drupal's default PDO settings result in stringified values.
In Drupal's includes/database.inc file you will find this around lines 40-50:
$connection_options['pdo'] += array(
// So we don't have to mess around with cursors and unbuffered queries by default.
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE,
// Because MySQL's prepared statements skip the query cache, because it's dumb.
PDO::ATTR_EMULATE_PREPARES => TRUE,
);
The statement here that MySQL's prepared statements skip the query cache is not entirely true, as can be found here: http://dev.mysql.com/doc/refman/5.1/en/query-cache-operation.html. It states MySQL > 5.1.17 prepared statements use the query cache under certain conditions.
I used the info from the other stack overflow question/answers to override the PDO settings for the database connection in Drupal's sites/default/settings.php (please note I only did this for the database I was querying, which is different than Drupal's own database):
'database_name' =>
array (
'default' =>
array (
'database' => 'database_name',
'username' => 'user_name',
'password' => 'user_pass',
'host' => 'localhost',
'port' => '',
'driver' => 'mysql',
'prefix' => '',
'pdo' => array(
PDO::ATTR_STRINGIFY_FETCHES => FALSE,
PDO::ATTR_EMULATE_PREPARES => FALSE
),
),
),
This resulted in integers being integers. Floats/decimals are incorrectly returned by PDO still, but this is different issue. At least my problems are solved now.
I found this similar question but my problem is different.
I moved my CakePHP 2.2 application to another server. There exists no problem before migration. Most of the things works fine after migration. I can reach most of my database tables etc. But when I try to reach one of my table I get this error:
"Error 500: Table stats for model Stat was not found in datasource default."
To solve this, I checked this folder:
"/app/tmp/cache/models"
In that folder there is a file for each of my tables
myapp_cake_model_default_mydatabase_table1
myapp_cake_model_default_mydatabase_table2
myapp_cake_model_default_mydatabase_table3
etc..
But there is no file for stats table. Can it be the problem? Or how can I solve this?
(Permission for "/app/tmp/cache/models" folder is 755)
In Database.php I have this:
public $default = array(
'datasource' => 'Database/Mysql',
'persistent' => false,
'host' => 'localhost',
'login' => 'myuser',
'password' => 'mypass',
'database' => 'mydatabase',
'prefix' => '',
'encoding' => 'utf8',
);
Edit:
As I noted in thaJeztah's answer's comments, after removing all files inside app/tmp/cache/persistent problem solved. CakePHP created new model cache files and it worked. After one year I found out the real problem. The problem was setting cake model files' clear duration. I set clearing cache to +999 days, so model files aren't regenerated. While making model changes you can set lower values for model cache clear:
Cache::config('_cake_model_', array(
'engine' => "File",
'prefix' => "myapp_". 'cake_model_',
'path' => CACHE . 'models' . DS,
'serialize' => ($engine === 'File'),
'duration' => "+999 days"
));
Have you checked your database, e.g. in phpMyAdmin or MySql workbench? Does the table exist in the database?
The error message indicates that the table could not be accessed using the default connection. It's possible that the table is really missing, or that the user you're using to connect to the database does not have the right permissions for that table.
If you migrated the database from another server, did you get error messages while importing? If you did not create a dump enclosed in a transaction, it's possible that the database dump was only partially imported.
[update] this suggestion solved the problem;
Remove all files from app/tmp/cache/persistent and /app/tmp/cache/models then enable debugging. Your SQL log/debug should show the queries that CakePhp is using to detect if the tables exist in the database. Also you'll be able to check if Cake writes to the tmp files without problems
If this is helpfull for anyone in 2020.
I had this problem even with full permissions to the model. I tried doing like #theJeztah suggested which was clearing cache/persistent but the problem persisted. What ended up working was switching Configure::write('debug', 0) to Configure::write('debug', 2) in the app/core file. Presumably on debug it clears the cache better.
In my cakephp web page, I have a button that the user clicks and it performs some maintenance on the server and then presents a download to the user. The file download is testlogs.gzip but when the download option occurs in firefox, it comes up as a file type of html document.
The file downloads and extracts fine, but I want the file type to be correct.
Here is the Media view class for the download:
//$this->autoRender = false;
$this->viewClass = 'Media';
$params = array(
'id' => 'systemlogs',
'name' => 'testsystemlogs',
'download' => true,
'extension' => 'gzip',
// 'mimeType' => 'zip',
'path' => DS . 'home' . DS
);
$this->set($params);
I tried to add in the 'mimeType' => 'zip' but that did not work.
Any help would be great.
Thanks
UPDATE: I tested uploading of the same files and I used firebug to determine the content type. The only file types I care about are of type: application/octet-stream.
So I think I just need to set this type in the Media class settings, not sure how to do that though.
THanks
mimeType has to be specified as an associative array (extension -> type), in your case this would be array('gzip' => 'application/x-gzip'). CakePHP merges this array with the built-in array of known MIME types in CakeResponse class.
However, CakePHP already knows the MIME type of .gz files so changing the extension of your file, if it is an option, might be an even easier solution.