propelorm / propel Goto Github PK
View Code? Open in Web Editor NEWCurrent stable (and outdated and unmaintained) version of Propel - Please use v2 https://github.com/propelorm/Propel2 --
Home Page: http://www.propelorm.org
License: MIT License
Current stable (and outdated and unmaintained) version of Propel - Please use v2 https://github.com/propelorm/Propel2 --
Home Page: http://www.propelorm.org
License: MIT License
It is nearly impossible to use migrations with PostgreSQL, and I believe the problem is related to the issue mentioned in #6
PostgreSQL doesn't have a "default" schema per se, it uses the database's "search_path" setting. Usually PG is set up so it would seem that the "public"-schema is the "default" for all intents and purposes, but this is not really the case. The search path is by default set to "$user",public
, so if I log on as "horros" and there's a schema named "horros" in my database, that will be the default schema (unless modified with SET search_path TO ....
)
If you don't set the schema
-attribute for the database or some tables, Propel (well, PostgreSQL) just uses whatever happens to be the first schema on the search path. All well and good so far. Now, if you have, say, a table called "books
" in the first existing schema of the search path (eg. "public
") and a table called "author
" in the schema "authors
" and need to reference the books table from the author table, you might attempt something like
<foreign-key foreignTable="books" onDelete="CASCADE" onUpdate="CASCADE">
<reference local="ref_book" foreign="id"/>
</foreign-key>
Naturally that won't work, as it'd look for the books
-table in the authors
-schema. So then you might think "hey, the table is in the public-schema, let's use that then."
<foreign-key foreignTable="books" onDelete="CASCADE" onUpdate="CASCADE" schema="public">
<reference local="ref_book" foreign="id"/>
</foreign-key>
This won't work either unless you have schema="public"
defined on either the <table>
-tag or the <database>
-tag, because Propel doesn't know what on earth the "public
"-schema is. So let's say we do add it to the <database>
-tag so all tables without an explicit schema defined is considered to belong to the "public
"-schema.
Now code generation works brilliantly, and all is well, until you attempt to use the migration target.
When we try to run the diff target, Propel looks at the books-table, sees that the database has a schema called "public
", and therefore the name of the table will be "public.books
". PgsqlSchemaParser.php
on the other hand discards the schema name for tables and foreign keys if the schema is "public
", because otherwise nothing would work if one didn't explicitly set the schema in the XML-file. This causes a name mismatch, as the table name Propel expects does not match what PgsqlSchemaParser returns ("books" with "public" stripped off), and so it generates code to drop and recreate ALL tables in the public schema, and will keep on doing so every single time you run the diff-target.
(Even more funky stuff would ensue if one blindly assumes that public is the default schema and someone deploys the app on, say, a shared host where the search path is set to "john,public
". Keep in mind, nothing says that the public schema even needs to exist at all in the database.)
I have been banging my head against the desk for the past few days trying to figure out a backwards compatible solution that wouldn't break anything, but I'm starting to suspect that this issue is fundamentally unsolvable unless PostgreSQL users are forced to always specify a schema (and PgsqlSchemaParser stops discarding the public schema from the table and foreign key names).
There appears to be a bit of an issue with the Versionable behaviour and ENUM type fields.
As ENUMs are handled via Propel rather than the database, they have particular getters and setters in place to correctly map their integer values to the right results. However, when a table uses the versionable behaviour, the versioning functions in the base class completely ignore these, eg:
public function addVersion($con = null)
{
...
$version->setEnumField($this->enum_field);
The base version class then rejects this as it's passing through an integer rather than the expected values, giving an error such as:
Value "1" is not accepted in this enumerated column
I presume the fix should be to use the included getter, eg:
$version->setEnumField($this->getEnumField());
When calling toArray, toXML, toCSV ... on an Object derived from BaseObject also on a PropelCollection an exception is generated.
Fatal error: Uncaught exception 'PropelException' with message 'Unknown parser class "PropelArrayParser"' in /home/neoguard/public_html/_data1/core/thirdparty/propel/runtime/lib/parser/PropelParser.php:95
Stack trace:
#0 /home/neoguard/public_html/_data1/core/thirdparty/propel/runtime/lib/om/BaseObject.php(354): PropelParser::getParser('Array')
#1 /home/neoguard/public_html/_data1/core/thirdparty/propel/runtime/lib/om/BaseObject.php(380): BaseObject->exportTo('Array')
#2 /home/neoguard/public_html/_data1/models/build/classes/neoguardian/om/BaseDevice.php(2057): BaseObject->__call('toArray', Array)
#3 /home/neoguard/public_html/_data1/core/thirdparty/propel/runtime/lib/collection/PropelObjectCollection.php(134): BaseDevice->__call('toArray', Array)
#4 /home/neoguard/public_html/_data1/core/thirdparty/propel/runtime/lib/collection/PropelObjectCollection.php(134): Device->toArray('phpName', true, Array, true)
#5 /home/neoguard/public_html/_data1/core/thirdparty/propel/runtime/lib/collection/PropelCollection.php(466): PropelO in /home/neoguard/public_html/_data1/core/thirdparty/propel/runtime/lib/parser/PropelParser.php on line 95
From what I understand the exportTo function of the BaseObject tries to call toArray but no such function exists, so the __call function redirects it to exportTo('Array') which tried to load PropelArrayParser.php which does not exist.
Is this a bug or am I doing something wrong?
Thanks
Hi,
I try ti use propel with Symfony2. I find this in the documentation :
<?xml version="1.0" encoding="UTF-8"?>
<!--
Document : schema_project.xml
Created on : 21 septembre 2011, 08:41
Author : gcamus
Description:
Purpose of the document follows.
-->
<database name="default"
namespace="Oxy\Bundle\ProjectBundle\Models"
defaultIdMethod="native"
tablePrefix="oxy_"
>
<table name="project">
<vendor type="mysql">
<parameter name="Engine" value="InnoDB"/>
<parameter name="Charset" value="utf8"/>
</vendor>
<column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />
<column name="title" type="varchar" primaryString="1" size="100" />
<column name="desc" type="longvarchar" />
<!--<column name="start_date" type="date" />-->
<column name="due_date" type="date" />
<column name="is_public" type="boolean" />
<column name="address" type="varchar" size="255" />
<column name="address_complement" type="varchar" size="255" />
<column name="city" type="varchar" size="255" />
<column name="cp" type="varchar" size="5" />
<column name="country" type="varchar" size="100" />
</table>
</database>
When i try run the command
app/console propel:build
propel generate the sql without charset :
SET FOREIGN_KEY_CHECKS = 0;
-- ---------------------------------------------------------------------
-- oxy_project
-- ---------------------------------------------------------------------
DROP TABLE IF EXISTS `oxy_project`;
CREATE TABLE `oxy_project`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`title` VARCHAR(100),
`desc` TEXT,
`start_date` DATE,
`due_date` DATE,
`is_public` TINYINT(1),
`address` VARCHAR(255),
`address_complement` VARCHAR(255),
`city` VARCHAR(255),
`cp` VARCHAR(5),
`country` VARCHAR(100),
PRIMARY KEY (`id`)
) ENGINE=InnoDB CHARACTER SET='';
# This restores the fkey checks, after having unset them earlier
SET FOREIGN_KEY_CHECKS = 1;
The PropelSQLExec
task does not take care about charset and it creates problem with insertions, while loading fixtures for example.
@maxailloud creates a patch for this class : http://www.propelorm.org/ticket/1418
It works fine but it's so much MySQL oriented as he uses the MYSQL_ATTR_INIT_COMMAND
parameter as @fzaninotto noticed.
@themouette proposal is:
thing is we are facing a choice here with followng solutions:
- check this is mysql and set charset if so (dirty patch, but works)
- use factory design pattern, lot of work, but able to handle more than just charset (pdo is already a factory, but what we need here is to prepare default params depending on vendor)
- let the user configure it for his own need, but it means duplicate
configuration key when using symfony, and moreover ask user to configure PDO.
Mine is:
$adapter = DBAdapter::factory($adapter_name);
$adapter->initConnection($this->conn, array('charset' => array('value' => $charset)));
// or
$adapter->setCharset($this->conn, $charset);The $pdoOptions variable will be removed.
This issue is about how to handle Adapter
in tasks.
William.
Hello.
Here is the code that thrown a PropelException:
$userQuery = new \core\orm\UserQuery();
$userQuery->condition('email', 'User.Email = ?', $emailOrNick);
Please look at exception stack:
Here is table definition in schema.xml:
<table name="users" phpName="User">
<column name="id" type="BIGINT" required="true" primaryKey="true" autoIncrement="true"/>
<column name="notary_id" type="BIGINT" required="true"/>
<column name="notary_admin" type="BOOLEAN" required="true" defaultValue="0"/>
<column name="email" type="VARCHAR" size="180" required="false" description="Email is unique but not required for notary helpers. However it is strictly required for notary owners." />
<column name="nick" type="VARCHAR" size="180" required="true" description="If only email specified, nickname will be set to email. This rule works for both notary owners and helpers."/>
<column name="pass" type="LONGVARCHAR" required="true" />
<column name="date_created" type="TIMESTAMP" required="true" defaultExpr="CURRENT_TIMESTAMP"/>
<column name="date_authorized" type="TIMESTAMP" required="true" defaultExpr="CURRENT_TIMESTAMP"/>
<column name="date_visited" type="TIMESTAMP" required="true" defaultExpr="CURRENT_TIMESTAMP"/>
<column name="auth_token" type="VARCHAR" size="40" required="false" description="Authorization token - sha1 of some random key."/>
<column name="active" type="BOOLEAN" defaultValue="1" description="Notary superuser can disable access for notary helper."/>
<index name="ind_notary_ids">
<index-column name="notary_id"/>
<index-column name="notary_admin"/>
</index>
<unique name="uniq_user_emails">
<unique-column name="email"/>
</unique>
<unique name="uniq_user_nicks">
<unique-column name="nick"/>
</unique>
<foreign-key name="frn_notary_of_user" foreignTable="notaries" onDelete="cascade" onUpdate="cascade">
<reference local="notary_id" foreign="id" />
</foreign-key>
<index name="ind_user_created">
<index-column name="date_created"/>
</index>
<index name="ind_user_authorized">
<index-column name="date_authorized"/>
</index>
<index name="ind_user_visited">
<index-column name="date_visited"/>
</index>
<index name="ind_user_passwords">
<index-column name="pass"/>
</index>
<unique name="uniq_user_auth_tokens">
<unique-column name="auth_token"/>
</unique>
</table>
I have also tried following but nothing worked:
$userQuery->condition('email', 'user.email = ?', $emailOrNick);
$userQuery->condition('email', 'user.Email = ?', $emailOrNick);
$userQuery->condition('email', 'User.email = ?', $emailOrNick);
$userQuery->condition('email', 'User.Email = ?', $emailOrNick);
$userQuery->condition('email', '\core\orm\User.Email = ?', $emailOrNick);
In case an ENUM column is hydrated by position, provided value has to be the key or value is forced to null.
The translation in case a key is given has to be kept, but validation and translation from value to ENUM key should be handled by the setColumnNameValue
.
<?php
$book = new Book2();
$book->setByPosition(2, 'novel'); // will set style to null
$book->setStyle('novel'); // but should be equivalent to this
currently words ending with "o" are pluralized in "oes". I think it's not default plural for too much English words.
Examples: photo, video, typo...
Indeed, I tried
egrep 'o$' /usr/share/dict/american-english
and I hardly found words for which plural ends with "oes".
Imported from: http://www.propelorm.org/ticket/1486
So at the end hierarchy will look so (for table "users"):
-PropelCollectionBase (regenerated with each build)
--- PropelCollection (editable by user)
------ UserCollectionBase (regenerated with each build)
--------- UserCollection (editable by user)
a. With (1) we give a way to extend all collections in one place with common logic, this is useful for geeks. For example, we can implement method to define an array map for some columns to speedup access to rows by these columns, like retrieving distinct values without making additional query, or filtering loaded objects by some criteria.
b. With (2) we give a way to add model-collection tools specific to business logic. For example, for objects loaded by any query "in the code above", initialize state to something, or remove some related information, or build some maps and put them into the cache - to speedup "code below", etc etc.
Hope it makes sense.
Regards,
Anton Andriyevskyy
This Pattern
/^([a-z0-9_-])+$/i
will fail because prepareRegexp
looks for the closing slash at the last pos.
propel-gen om doesn't accept the"-" in the following enum column definition:
<column name="status" phpName="Status" type="CHAR" sqlType="enum('p','s','-')" required="true">
due to the pattern in propel/generator/resources/xsd/database.xsd:
<xs:simpleType name="sql_type">
<xs:restriction base="xs:string">
<xs:pattern value="[\w\s\[\]\(\),\.']+"/>
</xs:restriction>
</xs:simpleType>
Is there a reason for not including the "-" sign in the pattern?
Error:
[propel-om] Loading XML schema files...
[PHP Error] DOMDocument::schemaValidate(): Element 'column', attribute 'sqlType': [facet 'pattern'] The value 'enum('p','s','-')' is not accepted by the pattern '[\w\s,.']+'. [line 441 of [...]/propel/generator/lib/task/AbstractPropelDataModelTask.php]
Execution of target "om-template" failed for the following reason: [...]/propel/generator/build-propel.xml:538:20: XML schema file ([...]/schema.xml) does not validate. See warnings above for reasons validation failed (make sure error_reporting is set to show E_WARNING if you don't see any).
[phingcall] [...]/propel/generator/build-propel.xml:538:20: XML schema file ([...]/schema.xml) does not validate. See warnings above for reasons validation failed (make sure error_reporting is set to show E_WARNING if you don't see any).
Execution of target "om" failed for the following reason: [...]/propel/generator/build-propel.xml:525:22: Execution of the target buildfile failed. Aborting.
[phing] [...]/propel/generator/build-propel.xml:525:22: Execution of the target buildfile failed. Aborting.
Propel 1.6.0 generates different class names than 1.5.x if I use "tablePrefix" in the database tag. All class names will also have the prefix => this breaks BC.
Example:
Prefix: tr_
Table name: user
Resulting table name in 1.5.x: tr_user
Resulting class name in 1.5.x: User
Resulting table name in 1.6.0: tr_user
Resulting class name in 1.6.0: TrUser
Hey Guys,
I found, what appears to be, a small bug with the generator (as of commit 8a5bab1 in propel). When I create a table that has a foreign key to itself (as in a tree structure), it adds an extra index with no name.
INDEX `I_referenced_gst_user_FK_2_1` (``),
When I change the schema.xml to point to a different table, the bug disappears and everything is fine. But naming a foreign key to the same table, results in this added (and apparently unnecessary) index. Removing the index SQL fixes the error as well.
Below is the portion of schema.xml in question. Changing the foreignTable attribute in the foreign-key for "gst_user" is the field that I'm talking about.
<table name="gst_user">
<column name="public_primary_key" type="char" size="8" />
<column name="profile_picture_image_id" type="integer" required="false" />
<column name="coach_user_id" type="integer" />
<foreign-key foreignTable="image" onDelete="setnull">
<reference local="profile_picture_image_id" foreign="id" />
</foreign-key>
<foreign-key foreignTable="gst_user" onDelete="setnull" onUpdate="setnull">
<reference local="coach_user_id" foreign="id" />
</foreign-key>
<index>
<index-column name="public_primary_key" />
</index>
<unique>
<unique-column name="sf_guard_user_id" />
</unique>
<behavior name="concrete_inheritance">
<parameter name="extends" value="user" />
</behavior>
</table>
Hydrating fails when single table inheritance is being used. The bug is in PropelFormatter::getWorkerObject which ignores the $class we're trying to hyrdate.
I added the following code to BookstoreDataPopulator::populate:
$bemp3 = new BookstoreCashier();
$bemp3->setName("Tim");
$bemp3->setJobTitle("Cashier");
$bemp3->save($con);
New test:
public function testFormatSingleTableInheritanceManyResults()
{
$con = Propel::getConnection(BookPeer::DATABASE_NAME);
BookstoreDataPopulator::populate($con);
$stmt = $con->query('SELECT * FROM bookstore_employee');
$formatter = new PropelOnDemandFormatter();
$formatter->init(new ModelCriteria('bookstore', 'BookstoreEmployee'));
$employees = $formatter->format($stmt);
foreach ($employees as $employee) {
$row = array();
$row[1] = $employee->getClassKey();
$omClass = BookstoreEmployeePeer::getOMClass($row, 0, false);
$actualClass = get_class($employee);
$this->assertEquals($omClass, $actualClass, 'PropelOnDemandFormatter::format() should handle single table inheritance');
}
}
Running phpunit testsuite/runtime/formatter/PropelOnDemandFormatterTest.php
1) PropelOnDemandFormatterTest::testFormatSingleTableInheritanceManyResults
PropelOnDemandFormatter::format() should handle single table inheritance
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-BookstoreCashier
+BookstoreEmployee
/var/www/workspaces/slangley/propel/test/testsuite/runtime/formatter/PropelOnDemandFormatterTest.php:169
FAILURES!
Tests: 8, Assertions: 120, Failures: 1.
Hi,
The current documentation is written in Wiki syntax or something like that as it was embedded in a Trac wiki but today, it's a pain to maintain it as it's not the best syntax... I suggest to rewrite it in Markdown which is a nice syntax and well integrated in Github.
Once done, we will move the documentation in its own repository and we will use the gh-pages feature provided by Github to host the up to date documentation.
Cheers,
William
Hi,
currently Propel has 2 types of inheritances: single table and concrete.
But the most common inheritance and the one I would like to use is the inheritance that uses join in its children tables.
E.g:
User { id, name } //parent
Company { user_id, slogan } //child
Person { user_id, sex } //child
That's the normalized version of the schema. It similar to the concrete table, but it won't copy all the parent's field to its children nor the parent fields to its children. Instead it will "join" those tables to access the data.
I had already talked about it in the IRC with others (Jarda mostly) and it seems that it's not just me that want that. Francois didn't really understand what I was asking when we talked, I think I didn't know how to explain it because it is recommended approach in most of the cases when dealing with inheritance.
For reference: http://www.doctrine-project.org/docs/orm/2.0/en/reference/inheritance-mapping.html#class-table-inheritance
I have several fields of type TINYINT[2+] in a MySQL database. When I reverse engineer my model, Propel 1.6 creates my class with BOOLEAN type. This is obviously wrong. I have values ranging from -127 to 127 and now propel interprets this all is 0s or 1s which is not what is intended.
Propel should only treat TINYINT(1) as a BOOLEAN. All other TINYINTs in mysql should be treated as TINYINTS.
Currently some popular IDEs (like PHPSTORM from IntelliJ) still have problem with understanding relative namespace notation from PHPDOC. Example:
<?php
namespace core\orm\om;
abstract class BaseRunnerQuery extends ModelCriteria
{
/**
* ...
* @return RunnerQuery
*/
public static function create($modelAlias = null, $criteria = null)
{ ... }
}
Now in another file:
use \core\orm\RunnerQuery;
RunnerQuery::create()->|
... in place of cursor, eg |, it does not hint members of query object - because it simply does not recognize relative namespace notation from PHPDOC. The simple solution would be to have an option for build configuration to allow notation of full namespace for each class in PHPDOC. I have not found such option in documentation by this url: http://www.propelorm.org/wiki/Documentation/1.6/BuildConfiguration
Hi,
Following the first part of this short discussion, we have a problem with the behavior versionable.
If you have a table which is versionable:
propel:
user:
id: ~
name: { type: VARCHAR, size: '255', required: true }
post:
_propel_behaviors:
versionable: { log_created_at: true, log_created_by: true, log_comment: true }
id: ~
ref: { type: VARCHAR, size: '255', required: true }
user_id: { type: INTEGER, required: true, foreignTable: user, foreignReference: id, onDelete: cascade }
And tried to make a deepCopy of this table (post):
<?php
$post= PostQuery::create()->findOneById(1);
$newPost = $post->copy(true);
$newPost->save();
Then you will have a SQL Error:
Unable to execute INSERT statement [INSERT INTO `post_version` (`ID`,`REF`,`VERSION`,`VERSION_CREATED_AT`) VALUES (:p1,:p2,:p3,:p4)] [wrapped: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-1' for key 'PRIMARY']
In fact, when you check the mysql queries, you see that the deepCopy also copy the post_version table.
And after the postSave
of Post
, it will try to addVersion
for the new post (with version number 1). Here it fail.
The problem is in copyInto
:
<?php
public function copyInto($copyObj, $deepCopy = false, $makeNew = true)
{
// ....
if ($deepCopy) {
// ....
foreach ($this->getPostVersions() as $relObj) {
if ($relObj !== $this) { // ensure that we don't try to copy a reference to ourselves
$copyObj->addPostVersion($relObj->copy($deepCopy));
}
}
I think when we copy an object we don't need to retrieve all the past version and that's the same for the refers.
Hi guys,
I'm facing an annoying issue with the way Propel manages paths. Propel uses the dot character as a namespace or directory separator.
Everything works for people who don't have dots in their path. That's not the case for me. The session username of my laptop is "hugo.hamon" so the full path to a model class is something like this :
/Users/hugo.hamon/Sites/Sandbox/src/Sensio/Bundle/BlogBundle/Model/Post
But propel replaces all / characters to dot to use the newly created path in its XML mapping file. After conversion, the newly created path is:
Users.hugo.hamon.Sites.Sandbox.src.Sensio.Bundle.BlogBundle.Model.Post
Finally, Propel rechanges dot to directory separator to create file on the filesystem. So the final path is as following:
/Users/hugo/hamon/Sites/Sandbox/src/Sensio/Bundle/BlogBundle/Model/Post
The segment "hugo.hamon" became "hugo/hamon".
I can't build anything because of this path transformation...
The PropelSQLTask
should be refactored and to follow the Migration
task architecture.
Generated SQL files should be written one per connection, not one per schema because it produces constraint bugs.
Doesn't seem like this should be the case (but please let me know if this is expected behavior): When using the "soft_delete" behavior a deleted object will fire the preDelete hook, but not the postDelete hook. The problem lies in the fact that the "if" block for soft delete issues a "return" prematurely. Additionally, any cascading is killed due to this return.
I'll try to get a patch working, but wanted to make sure this was not expected behavior first
Current code (generated BaseMyClass):
public function delete(PropelPDO $con = null)
{
...
$ret = $this->preDelete($con);
// soft_delete behavior
if (!empty($ret) && MyClassQuery::isSoftDeleteEnabled()) {
$this->keepUpdateDateUnchanged();
$this->setDeletedAt(time());
$this->save($con);
$con->commit();
MyClassPeer::removeInstanceFromPool($this);
return; // <-- this return forces a skip of both the postDelete hook and cascading
}
if ($ret) {
MyClassQuery::create()
->filterByPrimaryKey($this->getPrimaryKey())
->delete($con);
$this->postDelete($con);
// versionable behavior
// emulate delete cascade
MyClassVersionQuery::create()
->filterByMyClass($this)
->delete($con);
$con->commit();
$this->setDeleted(true);
} else {
$con->commit();
}
...
}
There is no info what are column names generated after adding those parameters:
<behavior name="versionable">
<parameter name="log_created_at" value="true" />
<parameter name="log_created_by" value="true" />
<parameter name="log_comment" value="true" />
</behavior>
And that their types and names can be changed.
Imported from: http://www.propelorm.org/ticket/1488
delegation is not working when tablePrefix is set.
with tablePrefix set to "tbl_" delegation behavior needs to be like
<database name="myDatabase" tablePrefix="tbl_">
...
<behavior name="delegate">
<parameter name="to" value="tbl_player" />
</behavior>
...
</table>
to work.
Propel-gen diff generates a migration file which would ALTER many of our tables to the state in that they already are. The workaround would be to check and delete all unnecessary ALTER commands as long as there are no relevant changes in these tables because the getDownSQL() task will destroy some information.
length_in
smallint(5) unsigned DEFAULT NULL COMMENT 'in m to the right', ...customer_station_tracks
CHANGE length_out
length_out
smallint(5) unsigned COMMENT 'in m to the left';customer_station_tracks
CHANGE length_out
length_out
smallint(5) unsigned;length_in
smallint(5) unsigned COMMENT 'in m to the right',...We have a similar issue with some MEDIUMINT type tables (know that Propel has less types than MySql):
departure_lateness_diff
mediumint(9) DEFAULT NULL, ...disposition_changes
CHANGE departure_lateness_diff
departure_lateness_diff
MEDIUMINT(9); ...disposition_changes
CHANGE departure_lateness_diff
departure_lateness_diff
SMALLINT(9); ...departure_lateness_diff
MEDIUMINT(9), ...Checked out and tested with several (also the actual) versions of the propel generator.
Looking into the code, found a query in the MysqlSchemaParser "SHOW COLUMNS FROM " . $table->getName()"
" to parse the DDL. With this query some information like the COMMENT will be discarded.
I have ran into a problem when using the new ENUM column type in conjunction with findOneOrCreate(). In cases where it needs to create the object, when it comes to setting the values based on what was specfied in the query, it will break for any ENUM columns.
Having had a quick scan though the code it looks like it's related to the getValue() function in the Criteria class returning the actual value (TINYINT) it would set in the database and then using that value in the setter function for that column without performing any sort of reverse transformation on it.
I get this problem with symfony, but I think it's related to Propel itself.
When generating a migration, tables are created with ENGINE=MyISAM even if setting is propel.mysql.tableType = InnoDB
When there's a table with column named "Table_Name" the generated PeerClass contains PHP-errors.
The constant TABLE_NAME is being defined twice then...
Possible solution might be to check XML and reject such column names ?
Hi,
It seems commit 5a40249 broke the i18n behavior when inserting translation for the default locale.
I noticed propel set the default locale as the default value for the locale column in the database schema, and tries to escape the specified value of course. I also noticed, when inserting a record with the default locale, the locale column is not present in the sql query, because it will be filled by the default value at the database level directly I guess.
When mysql_escape_string() was used, everything was fine but since mysql_real_escape_string() is used, this behavior is broken :
mysql_real_escape_string needs a connection to work, whereas mysql_escape_string() doesn't. When propel tries to escape the value, the connection to the database seems not to be initialized yet. mysql_real_escape_string tries to connect to mysql with the default parameters (meaning no username, no password, localhost) and fails, returning false.
[PHP Error] mysql_real_escape_string(): Access denied for user ''@'localhost' (using password: NO) [line 586 of /var/www/dev/project/vendor/propel/generator/lib/platform/MysqlPlatform.php]
[PHP Error] mysql_real_escape_string(): A link to the server could not be established [line 586 of /var/www/dev/project/vendor/propel/generator/lib/platform/MysqlPlatform.php]
At this point, the default value of the locale column is not correctly set because it results to an empty string.
And then, when you try to insert a record with the default locale, the locale is not present in the sql query (as explained before) and so an empty string is set (the default value of the database column) instead of the desired locale. From there, everything is messy. When you retrieve the record, propel can't find the locale, so it gives you a new translation, and if you try to save it, you will end up with a duplicate primary key for your i18n record.
I noticed this bug with the i18n behavior but I think it may affect other things, like all default values set in the schema.
I don't know the best way to deal with this issue. Not sure that initializing a connection only for quoting some strings is the best but I don't know how else to proceed.
Hi,
When using a condition like this one :
'Entry.Isdeleted = ? AND Entry.Isactive = ?', array(1, 2)
then via $myQuery->toString() displayable information look like :
SQL : Entry.ISDELETED = :p1 AND Entry.ISACTIVE = :p2
Params: Entry.ISDELETED => 1, Entry.ISDELETED => 2
That works very well, but params information use same field names (.ISDELETED) where as there are two different name (.ISDELETED and *.ISACTIVE). That look to do this only when condition params are in an array.
It seems that the AggregateColumn Behavior isn't compatible with the class prefix setting. I've marked the two incorrect line below.
Actual:
/**
* Finds the related store_category objects and keep them for later <~ this line
*
* @param PropelPDO $con A connection object
*/
protected function findRelatedstore_categorys($con)
{
$criteria = clone $this;
if ($this->useAliasInSQL) {
$alias = $this->getModelAlias();
$criteria->removeAlias($alias);
} else {
$alias = '';
}
$this->store_categorys = store_categoryQuery::create() <~ and this line
->joinstore_category_product($alias)
->mergeWith($criteria)
->find($con);
}
Expected:
/**
* Finds the related DB_store_category objects and keep them for later <~ this line
*
* @param PropelPDO $con A connection object
*/
protected function findRelatedstore_categorys($con)
{
$criteria = clone $this;
if ($this->useAliasInSQL) {
$alias = $this->getModelAlias();
$criteria->removeAlias($alias);
} else {
$alias = '';
}
$this->store_categorys = DB_store_categoryQuery::create() <~ and this line
->joinstore_category_product($alias)
->mergeWith($criteria)
->find($con);
}
I am defining something like:
child:
_attributes: { baseClass: MyBaseChild }
name: { type: VARCHAR, size: '255' required: false, description: 'The object' }
_propel_behaviors:
concrete_inheritance:
extends: parent
I'd like and expect BaseChild to extend MyBaseChild, not Parent.
Currently, there is no possibility to specify an alternate connection to PropelModelPager. ModelCriteria's paginate() has a $con parameter, but it is not used anywhere. Here is a patch that resolves the issue.
It would be nice to be able to define custom datatypes, that share configuration. It would be nice if data conversion can be delegated to a 'filter' object. A simpler variant would be a way to simply hook input/output filters into the Propel entities, but that would be a diffent feature request, I suppose.
Use cases:
There is an hidden logical error introduced in commit : cd547f2
The $dsn
variable line 642 (cd547f2#L0L642) is set before the prepareParams()
pass, that causes a wrong DSN
so you'll never get the correct charset
in it.
To fix it, it just needs to invert few lines. Could solve a bunch of issues on sfPropelORMPlugin.
I'm sorry to didn't catch it before. I'll fix it tomorrow.
William
Again, the "dot-notation" causes bugs as some parts are not consistent.
E.g.:
.om
.propel.generator.
.It should not cause problems except in some weird contexts. Anyway, it should be fixed.
I suggest to add a special case for the /
support everywhere. In this case, we will be able to get the absolute path of each class in the package value.
William
Hi,
Here is a possible enhancement for the schema.xml validation. I noticed that you can give two columns in the same table the same phpName -> this won't work later when you try to use the method, because the method would get generated twice.
Here is my example (phpName="LanguageId"
is there twice)
<table name="Expert_Language" phpName="ExpertLanguage">
<column name="id_number" phpName="IdNumber" type="VARCHAR" size="8" primaryKey="true" required="true"/> <column name="language_id" phpName="LanguageId" type="INTEGER" size="4" scale="0" primaryKey="true" required="true"/>
<column name="language_fluency" phpName="LanguageId" type="VARCHAR" size="10" required="true"/>
<foreign-key foreignTable="Expert" >
<reference local="id_number" foreign="id_number"/>
</foreign-key>
<foreign-key foreignTable="Language" >
<reference local="language_id" foreign="language_id"/>
</foreign-key> <index name="PK_Expert_Language">
<index-column name="id_number"/> <index-column name="language_id"/>
</index>
</table>
Here is the current error:
Fatal error: Cannot redeclare BaseExpertLanguageQuery::filterByLanguageId() in K:\ExpertFinder_Development_Zend\library\Propel\models\ExpertFinder_Development\om\BaseExpertLanguageQuery.php on line 208
My Proposal is to throw an error during the generation similar to when you get an error if a foreign key is missing.
Let me know what you think.
Thanks, Nikesh
Imported from: http://www.propelorm.org/ticket/1487
To describe my model in short:
https://gist.github.com/baaa491b8fb2a7404455
The main concept is the 1:1 relation between Invoice and Membership. This is my code, that is not working as expected:
// $m is an instance of Membership
// create invoice
$invoice = new Invoice();
$invoice->setCreated(new DateTime());
$invoice->setUser($m->getUser());
$invoice->setPaymentOptionId($paymentOption);
$invoice->addProduct($p);
$m->setInvoice($invoice);
$m->save();
So, I would expect that the Invoice is saved, the primary, auto increment key is generated and saved in the membership table as well. This does not work at the moment. So I went into the generated code. That is the doSave() method in BaseMembership.
I put a little debug code in there:
if ($this->aInvoice !== null) {
if ($this->aInvoice->isModified() || $this->aInvoice->isNew()) {
$affectedRows += $this->aInvoice->save($con);
}
$this->setInvoice($this->aInvoice);
}
echo 'BaseMembership::doSave, InvoiceId: ' . $this->invoice_id;
// If this object has been modified, then save it to the database.
if ($this->isModified()) {
if ($this->isNew()) {
$criteria = $this->buildCriteria();
$pk = BasePeer::doInsert($criteria, $con);
$affectedRows += 1;
$this->setNew(false);
} else {
$affectedRows += MembershipPeer::doUpdate($this, $con);
}
$this->resetModified(); // [HL] After being saved an object is no longer 'modified'
}
The echo Statement is printed 2 times. The first one without the InvoiceId, the second one with the InvoiceId. From what I read in the code, the invoiceid is tried to save in the first run of doSave() when there is no invoiceid available. The second one has an invoiceid, but its not saved.
And I wonder why the doSave() or better its body is run two times, when the guard variable $this->alreadyInSave shouldn't let this happen.
I guess this applies to all 1:1 resp. 1:n mappings.
Tried several workarounds:
$invoice->save();
$m->setInvoice($invoice);
$m->save();
$invoice->save();
$m->setInvoiceId($invoice->getInvoiceId());
$m->save();
$invoice->save();
$m->setInvoiceId(null);
$m->setInvoiceId($invoice->getInvoiceId());
$m->save();
whichever version, I don't get the invoice id updated in the membership row.
Propel Version: 1.6.1
Hi,
looks like SQL DDL generation is partially broken or at least inconsistent.
I made some further tests (see below).
With defaultValue="x" or default="x"
Schema:
<column name="is_temp" type="BOOLEAN" required="true" defaultValue="1" />
<column name="connections_type" type="VARCHAR" size="16" required="true" defaultValue="disabled" />
<column name="profile_count" type="INTEGER" required="true" defaultValue="0" />
DDL:
`is_temp` TINYINT(1) DEFAULT 1 NOT NULL,
`connections_type` VARCHAR(16) DEFAULT '' NOT NULL,
`profile_count` INTEGER DEFAULT 0 NOT NULL,
Base Object:
public function applyDefaultValues()
{
$this->is_temp = true;
$this->connections_type = 'disabled';
$this->profile_count = 0;
}
BOOLEAN and INTEGER default values are set in DDL,
but VARCHAR is always an empty string.
With defaultExpr="x"
Schema:
<column name="is_temp" type="BOOLEAN" required="true" defaultExpr="1" />
<column name="connections_type" type="VARCHAR" size="16" required="true" defaultExpr="disabled" />
<column name="profile_count" type="INTEGER" required="true" defaultExpr="0" />
DDL:
`is_temp` TINYINT(1) DEFAULT 1 NOT NULL,
`connections_type` VARCHAR(16) DEFAULT disabled NOT NULL,
`profile_count` INTEGER DEFAULT 0 NOT NULL,
Base Object:
public function applyDefaultValues()
{
}
Works as expected.
Tested on mysql platform with propel 1.6.2 from git.
Upgraded from propel 1.5.x.
Please note that applying VARCHAR default values to SQL DDL by schemas default="" attribute worked for years, so this is definitive not BC.
Propel diff generates many false positives for indices in mssql.
I pinned down the proplem to PropelTableComparator->compareIndices for some reason $toTableIndices is always empty regardless of indices in the table or not.
_if/_elseif/_else logic is completely wrong in Propel 1.5 Let's look at example:
<?php
SomeQuery::create()
->_if(false) // returns Proxy
->_elseif(true) // returns Query
->_elseif(*) // returns Proxy
->_elseif(true) // returns Query
// calls here are executed, although they shouldn't
->_endif()
->_elseif(*) // should throw an exception, I think
;
SomeQuery::create()
->_if(true) // returns Query
->_if(true) // should throw an exception, but it doesn't
->_elseif(*) // returns Proxy
->_elseif(true) // returns Query
// calls here are executed, although they shouldn't
->_endif()
;
Here is a patch that moves all logic from PropelConditionalProxy to Criteria itself, leaving the former just as a no-op proxy, and adds flags to Criteria that let us make _if etc behavior right.
// referring to propel_generator/lib/reverse/mysql/MysqlSchemaParser.php:90
$stmt = $this->dbh->query("SHOW TABLES");
This only returns the table names, maybe you like to think about the "SHOW FULL TABLES" statement instead:
90 $stmt = $this->dbh->query("SHOW FULL TABLES");
91
92 // First load the tables (important that this happen before filling out details of tables)
93 $tables = array();
94 if ($task) $task->log("Reverse Engineering Tables", Project::MSG_VERBOSE);
95 while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
96 $name = $row[0];
97 $type = $row[1];
98 if ($name == $this->getMigrationTable() or $type != "BASE TABLE") {
99 continue;
100 }
You could divide with the second column 'Table_type' between 'BASE TABLE' and 'VIEW'. It would be easy to simply continue few lines of code later, until VIEWS will cause no more primary key errors.
Table "view_foo" does not have a primary key defined.
Propel requires all tables to have a primary key.
The new 1.6 migrations cannot support multiple schemas. If you have 2 schemas:
schema1:
<database package="beta" name="scratch" schema="beta" defaultIdMethod="native">
<table name="projects" phpName="Projects">
...
schema2:
<database package="analysisdbv2" name="scratch" schema="analysisdbv2" defaultIdMethod="native">
<table name="analyzer_log" phpName="AnalyzerLog">
...
The diff task generates:
DROP TABLE IF EXISTS `analyzer_log`;
(snip)
CREATE TABLE `beta`.`projects`
(snip)
CREATE TABLE `analysisdbv2`.`analyzer_log`
Imported from: http://www.propelorm.org/ticket/1483
Problem also mentioned here https://github.com/fzaninotto/sfPropel15Plugin/issues/13
Looks like
here's a patch to correct embedi18n and the generator
You can also preview the modification on
https://github.com/mazenovi/propel1.6/commit/2b750e0f26065292fcfe0c7a72448dfed0b36b76
and
https://github.com/mazenovi/sfPropel15Plugin/commit/ddbdf9933becfc7296d574b162e9a2535d17b05b
Imported from: http://www.propelorm.org/ticket/1473
One more proposal on connections. When I create some collection using FooQuery::create()->...->find($con), I would like the objects in this collection to use $con in their getBar() (or getBars()) methods.
One way to do it I see is to store the connection in BaseObject (just a slight modification of PropelObjectFormatter is needed), and use it in internal find(), findOne(), findPk() etc method calls (need to modify generators, this might be a little harder). I think I could do it and post a patch, if developers decide that such a modification can be useful for the project.
Propel 1.5.6: generated SQL is ok
SELECT DISTINCT mateam.ID,.. mabfw.ID_MA, ... FROM mateam CROSS JOIN
mabfw_rollen LEFT JOIN mabfw ON (mateam.ID_MA=mabfw.ID_MA)
Propel 1.6.0 - [wrapped: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'mabfw.ID_MA' in 'on clause']
SELECT DISTINCT mateam.ID, ... mabfw.ID_MA, ... FROM mateam INNER
JOIN mabfw_rollen ON (mabfw.ID_MA=mabfw_rollen.ID_MA) LEFT JOIN mabfw
ON (mateam.ID_MA=mabfw.ID_MA)
Criteria used:
$auswahl->addJoin(MabfwPeer::ID_MA, MabfwRollenPeer::ID_MA);
$auswahl->setDistinct();
$Team->getMateamsJoinMabfw($auswahl)
Following the relevant part of the Schema:
mabfw:
_attributes: { phpName: Mabfw }
id_ma: { phpName: IdMa, type: VARCHAR, size: '20', primaryKey: true, required: true }
name: { phpName: Name, type: VARCHAR, size: '30', required: false }
vorname: { phpName: Vorname, type: VARCHAR, size: '30', required: false }
passwort: { phpName: Passwort, type: VARCHAR, size: '60', required: false }
mabfw_rollen:
_attributes: { phpName: MabfwRollen }
id_ma: { phpName: IdMa, type: VARCHAR, size: '20', required: true, foreignTable: mabfw, foreignReference: id_ma, onDelete: RESTRICT, onUpdate: RESTRICT }
id_rolle: { phpName: IdRolle, type: INTEGER, size: '10', required: true, defaultValue: '0', foreignTable: marollen, foreignReference: id_rolle}
id: { phpName: Id, type: INTEGER, size: '11', primaryKey: true, autoIncrement: true, required: true }
_indexes: { id_ma: [id_ma] }
_uniques: { id_ma_2: [id_ma, id_rolle] }
mateam:
_attributes: { phpName: Mateam }
id: { phpName: Id, type: INTEGER, size: '11', primaryKey: true, autoIncrement: true, required: true }
id_team: { phpName: IdTeam, type: INTEGER, size: '11', required: true, foreignTable: team, foreignReference: id, onDelete: CASCADE, onUpdate: CASCADE }
id_ma: { phpName: IdMa, type: CHAR, size: '20', required: true, foreignTable: mabfw, foreignReference: id_ma, onDelete: RESTRICT, onUpdate: RESTRICT }
verantwortlich: { phpName: Verantwortlich, type: TINYINT, size: '4', required: true, defaultValue: '0' }
_indexes: { id_ma: [id_ma] }
_uniques: { id_team: [id_team, id_ma] }
Also a rewrite with Propel Queries instead of the old Criterias was not successful:
Query used:
$q = MabfwRollenQuery::create()
->useMabfwQuery()
->useMateamQuery()
->orderByVerantwortlich('DESC')
->endUse()
->orderByName('ASC')
->endUse()
->setDistinct()
->find();
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'mateam.ID_MA'
in 'on clause'
SELECT DISTINCT mateam.ID, ..., mabfw.ID_MA FROM `mabfw_rollen` LEFT
JOIN `mabfw` ON (mateam.ID_MA=mabfw.ID_MA)INNER JOIN `mateam` ON
(mabfw.ID_MA=mateam.ID_MA) ORDER BY mateam.VERANTWORTLICH DESC,
mabfw.NAME ASC
Seems to be related with http://trac.propelorm.org/changeset/1959 and http://trac.propelorm.org/changeset/2049
If we have a table in the schema and add a <unique>
element, eg
<unique>
<unique-column name="foo" />
</unique>
the migration target generates
CREATE UNIQUE INDEX "test_U_1" on "test" ("foo");
which is fine, except if we remove the unique-element, the generated migration code from PgsqlPlatform::getDropIndexDDL()
is
ALTER TABLE "test" DROP CONSTRAINT "test_U_1";
this won't work, because the unique index created is a, well, unique index, not a table or column constraint.
There are two (maybe three) possible fixes for this. Either the generator needs to create the add SQL along the lines of
ALTER TABLE "test" ADD CONSTRAINT "test_U_1" UNIQUE ("foo");
or generate drop SQL along the lines of
DROP INDEX "test_U_1";
The third option I suppose is poke around in the metadata-tables in PostgreSQL and figure out if it's a table/column constraint and call some getDropUniqueConstraintDDL()
or something similar, but that may quckly become way too hard to do.
Maybe the schema (and Propel) should differentiate between unique indexes and table/column constraints somehow? Maybe the <vendor>
-element could be used for this?
I'm not quite sure what the real-world difference between a table constraint and a unique index on a column really is, other than you can't drop the constraint with DROP INDEX
because the constraint depends on the index, and you can't drop the index with ALTER TABLE .. DROP CONSTRAINT
, becuase it isn't a table constraint.
Hello,
if propel tries to drop a index on a mssql database it doesn't work because the generated syntax is incorrect.
Mssql needs a table name before the index name.
Here is my version of getDropIndexDDL in MssqPlatform:
/**
* Builds the DDL SQL to drop an Index.
*
* @param Index $index
* @return string
*/
public function getDropIndexDDL(Index $index)
{
$pattern = "
DROP INDEX %s.%s;
";
return sprintf($pattern,$this->quoteIdentifier($index->getTable()->getName()),
$this->quoteIdentifier($index->getName())
);
}
In PropelDateTime::newInstance
, the passed value is checked via is_numeric
. If true
, it is supposed, that $value
is a timestamp:
...
if (is_numeric($value)) { // if it's a unix timestamp
...
Unfortunately timestrings of the format "Ymd" are seen as timestamps, as well, which leads to wrong dates in database.
I would really appreciate a fix.
Imported from: http://www.propelorm.org/ticket/1480
Hi folks,
i got a fatal error while running a diff over my mysql database:
PHP Fatal error: Call to a member function getColumn() on a non-object in /usr/local/zend/share/pear/data/propel_generator/lib/reverse/mysql/MysqlSchemaParser.php on line 301
I analysed this part and found out, that one of my "old" tables in this database have an InnoDB constraint to a non existing even older table.
e.g.
CREATE TABLE `old_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`fg_id` int(11) NOT NULL,
`some_integer` int(11) NOT NULL,
`some_decimal` decimal(3,2) NOT NULL DEFAULT '1.00',
PRIMARY KEY (`id`),
KEY `key1` (`integer`),
KEY `key2` (`fg_id`),
CONSTRAINT `con1` FOREIGN KEY (`fg_id`) REFERENCES `deleted_old_table` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `con2` FOREIGN KEY (`some_integer`) REFERENCES `some_other_table` (`ID`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3163 DEFAULT CHARSET=utf8;
Anyhow, this table still exists from an older version of my application and doesn't ever exists in the schema.xml.
Finally i fixed my schema manually, but only because the propel-gen diff couldn't handle it probably. I hope you are interested in this kind of use case!
Greetings,
rvolk
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.