Skip to content

fix(xpdo): Fix Illegal offset type for compound PK with generated field (#129)#272

Merged
opengeek merged 4 commits intomodxcms:3.xfrom
Ibochkarev:fix/129-compound-pk-generated-field
Apr 7, 2026
Merged

fix(xpdo): Fix Illegal offset type for compound PK with generated field (#129)#272
opengeek merged 4 commits intomodxcms:3.xfrom
Ibochkarev:fix/129-compound-pk-generated-field

Conversation

@Ibochkarev
Copy link
Copy Markdown
Contributor

Fix PHP warning "Illegal offset type" when saving objects with compound primary key that includes a generated field (e.g. AUTO_INCREMENT).

Problem
When getPK() returns an array for compound keys, the code used it as array index: $this->_fields[$this->getPK()] — PHP does not allow arrays as array keys.

Solution

  • xPDOObject::save(): Iterate over PK fields, find the one with generated="native", and set only that field with getGeneratedKey()
  • xPDOManager (MySQL): Extend getColumnDef to add AUTO_INCREMENT for generated fields in compound PK (only for the first column in PK, per MySQL requirement)

Additional changes

  • Add NumberSeq test model and testSaveCompoundPkWithGeneratedField test
  • Fix variable initialization in testGetObjectGraphsByPK / testGetObjectGraphsJSONByPK to avoid undefined variable notices
  • Fix typo "retreiving" → "retrieving" in test messages

Fixes #129

…ld (modxcms#129)

- xPDOObject::save(): find generated field in compound PK and set value correctly
- xPDOManager (MySQL): add AUTO_INCREMENT for generated fields in compound PK
- Add NumberSeq test model and testSaveCompoundPkWithGeneratedField test
- Fix variable initialization in testGetObjectGraphsByPK tests
- Fix typo 'retreiving' -> 'retrieving' in test messages
- Add fallback in xPDOObject::save() to set _new=false when inserted with generated PK
- Add NumberSeq to testGetDescendants expected array and SQLite schema
- Create sqlite/NumberSeq.php for cross-platform test consistency
@Ibochkarev Ibochkarev marked this pull request as ready for review March 11, 2026 08:05
@opengeek opengeek force-pushed the fix/129-compound-pk-generated-field branch from 3f50fb4 to 0094028 Compare April 6, 2026 19:50
…) failures

- xPDOObject::save(): add scalar PK branch alongside compound PK iteration
  so the generated-key assignment is correct for both PK types
- xPDOObject::save(): replace silent elseif fallback (which could mark an
  object persisted with a zero PK) with a LOG_LEVEL_WARN log call
- mysql/xPDOManager::getColumnDef(): move phptype check to emission site;
  use getIndexMeta()['PRIMARY']['columns'] directly instead of iterating
  all indexes
- Remove pgsql/sqlite NumberSeq model files: compound PK with a native-
  generated field is MySQL-only; those schemas defined a different table
  and implied cross-driver coverage that does not exist
- Fix testSaveCompoundPkWithGeneratedField(): use $obj->get() accessors
  rather than named keys on getPrimaryKey(), which returns a numerically
  indexed array for compound PKs
Copy link
Copy Markdown
Member

@opengeek opengeek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, @Ibochkarev! The fix is good. Tracing the "Illegal offset type" warning back to lastInsertId() returning an empty string on compound-PK objects with a generated field, and correcting the key assignment in save(), is the right approach.

I've pushed a commit on top before merging. I'm experimenting with a "fix-merge" approach on this project. By pushing small corrections directly onto contributor branches rather than asking for another round-trip, I'm hoping we can reduce friction and increase velocity on the project.

There are essentially two changes in the addendum:

1. Silent fallback replaced with a log warning.
After the generated key is assigned, your elseif block cleared _new even when lastInsertId() returned 0 — a zero-PK insert would silently look like a successful save. The addendum replaces that block with a LOG_LEVEL_WARN log call so callers get visibility into the failure. The success path (_new = false when a real ID comes back) is untouched.

2. Removed the pgsql and sqlite NumberSeq model files.
The pgsql and sqlite variants omit generated="native" on the key field, so they don't exercise this fix on those drivers. Keeping them would imply cross-driver coverage that doesn't exist. The addendum removes those six files and scopes this fix to MySQL. PostgreSQL (sequences) and SQLite (ROWID aliasing) both need manager-level changes — those belong in a follow-on PR.

Since this puts a commit on your branch that you didn't write, I'm flagging it before the merge proceeds. If anything in the addendum looks wrong or raises a concern, let me know.

@Ibochkarev
Copy link
Copy Markdown
Contributor Author

Thanks for this, @Ibochkarev! The fix is good. Tracing the "Illegal offset type" warning back to lastInsertId() returning an empty string on compound-PK objects with a generated field, and correcting the key assignment in save(), is the right approach.

I've pushed a commit on top before merging. I'm experimenting with a "fix-merge" approach on this project. By pushing small corrections directly onto contributor branches rather than asking for another round-trip, I'm hoping we can reduce friction and increase velocity on the project.

There are essentially two changes in the addendum:

1. Silent fallback replaced with a log warning. After the generated key is assigned, your elseif block cleared _new even when lastInsertId() returned 0 — a zero-PK insert would silently look like a successful save. The addendum replaces that block with a LOG_LEVEL_WARN log call so callers get visibility into the failure. The success path (_new = false when a real ID comes back) is untouched.

2. Removed the pgsql and sqlite NumberSeq model files. The pgsql and sqlite variants omit generated="native" on the key field, so they don't exercise this fix on those drivers. Keeping them would imply cross-driver coverage that doesn't exist. The addendum removes those six files and scopes this fix to MySQL. PostgreSQL (sequences) and SQLite (ROWID aliasing) both need manager-level changes — those belong in a follow-on PR.

Since this puts a commit on your branch that you didn't write, I'm flagging it before the merge proceeds. If anything in the addendum looks wrong or raises a concern, let me know.

Hello! I don't have anything against this, as it speeds up the decision-making process regarding the PR and its integration into the release branch.

@opengeek opengeek merged commit ecf8aca into modxcms:3.x Apr 7, 2026
15 checks passed
@Ibochkarev Ibochkarev deleted the fix/129-compound-pk-generated-field branch April 8, 2026 02:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"PHP warning: Illegal offset type" when saving object with compound primary key

2 participants