Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[10.1.1] - 2026-07-03
[10.1.1]: https://github.com/codesaur-php/DataObject/compare/v10.1.0...v10.1.1
Fixed
LocalizedModel::updateById()no longer duplicates content rows on SQLite. The existing-content check relied onPDOStatement::rowCount(), which always returns 0 forSELECTstatements on SQLite, so every update of an existing language inserted a new content row instead of updating it. The check now usesfetch(), matching howModel::getRow()already handles this driver quirk.TableTrait::getSyntax()no longer mutates theColumnobject. Declaring a primary column with an explicit->notNull()(e.g. `(new Column('id', 'bigint')) ->primary()->notNull()`) previously crashed table creation withCannot modify readonly property Column::$is_null, becausegetSyntax()callednotNull()->auto()on the column a second time. The PRIMARY -> NOT NULL + AUTO rule is now computed locally without touching the column.
Changed
- Removed the personal phone number from the author entry in
composer.json. Column::default()now declares itsColumnreturn type like the other fluent setters.- Example scripts (
example/sqlite.php,mysql.php,postgres.php) resolve the Composer autoloader via__DIR__, so they run from any working directory. - Cleaned up a duplicated
@@collation_connectionselection inTableTrait::createTable().
[10.1.0] - 2026-06-17
[10.1.0]: https://github.com/codesaur-php/DataObject/compare/v10.0.1...v10.1.0
Added
- Broader cross-driver column type conversion in
TableTrait::getSyntax(), so column types declared for one database resolve to a valid native type on the others instead of reaching the engine verbatim and raising a runtime SQL error.- PostgreSQL:
double->double precision,float->real,tinyblob/mediumblob/longblob/blob/binary/varbinary->bytea - MySQL:
jsonb->json,uuid->char(36),inet/cidr->varchar(45),bytea->longblob,double precision->double - SQLite:
bytea->BLOB,double precision->REAL(jsonb/uuid/inet/cidr/jsoncontinue to fall through toTEXT)
- PostgreSQL:
Fixed
- Invalid
(length)suffix on length-less types no longer emitted. Types that do not accept a length (bytea,real,double precision,json,longblob,text) are skipped when appending the length, preventing malformed DDL such asbytea(16)when a column likevarbinary(16)is converted.
[10.0.1] - 2026-06-09
[10.0.1]: https://github.com/codesaur-php/DataObject/compare/v10.0.0...v10.0.1
Changed
- Private property names no longer use a leading underscore (PSR-12 compliance)
Column:$_name,$_type,$_length,$_is_null,$_is_auto,$_is_unique,$_is_primary,$_default->$name,$type,$length,$is_null,$is_auto,$is_unique,$is_primary,$defaultPDOTrait:$_driver->$driver- Internal only - all properties are
private, so the public API is unchanged.
[10.0.0] - 2026-05-06
[10.0.0]: https://github.com/codesaur-php/DataObject/compare/v9.1.0...v10.0.0
Breaking Changes
setForeignKeyChecks(bool $enable)removed fromPDOTrait- The PostgreSQL branch (
SET session_replication_role) required SUPERUSER privilege, forcing applications to grant their DB user broad rights for what was usually a redundant guard aroundALTER TABLE ADD CONSTRAINT FOREIGN KEYon freshly created (empty) tables - where FK validation cannot fail anyway. - In the rare cases where toggling FK enforcement is genuinely required (bulk imports,
cyclic references, custom maintenance scripts), drivers expose this directly:
- MySQL:
SET foreign_key_checks = 0|1 - PostgreSQL:
SET session_replication_role = 'replica'|'origin'(still requires SUPERUSER) - SQLite:
PRAGMA foreign_keys = ON|OFF
- MySQL:
- Migration: callers of
$this->setForeignKeyChecks(false/true)should remove those calls when they wrap onlyALTER TABLE ADD CONSTRAINT FOREIGN KEYon empty tables, or replace with the appropriate rawexec()SQL when toggling is genuinely needed.
- The PostgreSQL branch (
[9.1.0] - 2026-03-24
[9.1.0]: https://github.com/codesaur-php/DataObject/compare/v9.0.2...v9.1.0
Breaking Changes
insert()return type changed fromarray|falsetoarrayin bothModelandLocalizedModel- Now throws
Exceptioninstead of returningfalseon failure - Callers checking
=== falseshould usetry/catchinstead
- Now throws
updateById()return type changed fromarray|falsetoarrayin bothModelandLocalizedModel- Same behavior change as
insert()
- Same behavior change as
deactivateById()now throwsExceptionwhen row is already inactive (previously returnedfalse)deactivateById()no longer modifies UNIQUE column values on deactivation- Previously negated numeric values and added
[uniqid]prefix to text values - UNIQUE columns now remain unchanged; handle conflicts at the business logic level
- Previously negated numeric values and added
Added
Constantsclass - All magic values centralized into a single final classDRIVER_MYSQL,DRIVER_PGSQL,DRIVER_SQLITE- database driver namesERR_TABLE_NAME_MISSING,ERR_COLUMNS_NOT_DEFINED,ERR_COLUMN_NOT_FOUND- error codesCOL_ID,COL_IS_ACTIVE,COL_PARENT_ID,COL_CODE- structural column namesCONTENT_TABLE_SUFFIX,CONTENT_KEY_COLUMNS,LOCALIZED_KEY- localized model conventionsPRIMARY_ALIAS_PREFIX,CONTENT_ALIAS_PREFIX- SQL alias prefixesTABLE_NAME_PATTERN,DEFAULT_CODE_LENGTH- configuration values
throwPdoError()helper inPDOTrait- Centralized PDO/PDOStatement error extraction and exception throwing- Accepts
\PDO|\PDOStatementas error source - Uses
neverreturn type (PHP 8.1+) - Replaced 11 duplicated error extraction blocks across all files
- Accepts
getById(int $id)method in bothModelandLocalizedModel- Shortcut for
getRowWhere(['id' => $id])
- Shortcut for
existsById(int $id)method in bothModelandLocalizedModel- Lightweight check using
SELECT 1 ... LIMIT 1without fetching full row
- Lightweight check using
countRows(array $condition)method in bothModelandLocalizedModel- Efficient
COUNT(*)query for pagination and statistics - LocalizedModel counts on primary table only (no content JOIN)
- Efficient
- Comprehensive test suite - 107 tests, 279 assertions
- New
PDOTraitTest- tests for driver detection, table checking - New
TableTraitTest- tests for column operations, deactivation, select statement builder - Expanded
ModelTest- countRows, existsById, getById, edge cases - Expanded
LocalizedModelTest- content columns, cascade delete, custom select, error cases
- New
Changed
- Replaced all hardcoded magic values with
Constants::*across all source files - All
execute()failures now throwExceptionwith PDO error details instead of returningfalse - Simplified error code extraction to
(int)($error_info[1] ?? 0) - Updated example files to use new methods, return types, and Constants
- Updated all documentation (EN/MN) to reflect API changes
Fixed
- Error handling code duplication resolved via
throwPdoError()helper (was flagged in code review)
[9.0.2] - 2026-03-05
[9.0.2]: https://github.com/codesaur-php/DataObject/compare/v9.0.1...v9.0.2
Changed
- Cleaned up all project files to follow old-school plain ASCII coding style
- Replaced Unicode special characters with ASCII equivalents
- Removed trailing whitespace from all files
[9.0.1] - 2026-03-04
[9.0.1]: https://github.com/codesaur-php/DataObject/compare/v9.0.0...v9.0.1
Changed
- Removed all emoji characters from documentation and project files
- Fixed Mongolian text capitalization errors ("Монгол Гарчиг" -> "Монгол гарчиг", "Монгол Тайлбар" -> "Монгол тайлбар")
- Replaced Unicode arrow
->with ASCII->across all files (docs, source, examples, tests)
[9.0.0] - 2026-01-07
[9.0.0]: https://github.com/codesaur-php/DataObject/compare/v8.1.0...v9.0.0
Breaking Changes
- Removed
getRowByCode()method fromLocalizedModel- This method has been removed as it was redundant with
getRowsByCode() - Migration: Use
getRowsByCode($code, $condition)instead - Example:
getRowByCode($id, 'en')->getRowsByCode('en', ['WHERE' => 'p.id=:id', 'PARAM' => [':id' => $id]])
- This method has been removed as it was redundant with
Added
- Project Documentation
- Created
CONTRIBUTING.mdwith contribution guidelines - Created
SECURITY.mdfor security policy
- Created
- Bilingual Documentation (English & Mongolian)
- Added complete documentation in both English and Mongolian languages
- English Documentation (
docs/en/):README.md- Full English version of READMEapi.md- Complete English API documentationreview.md- English code review documentation
- Mongolian Documentation (
docs/mn/):README.md- Монгол хэл дээрх бүрэн танилцуулгаapi.md- Монгол хэл дээрх API баримт бичигreview.md- Монгол хэл дээрх код шалгалтын баримт бичиг
- All documentation files include language switcher links for easy navigation
Documentation
- Refactored main
README.mdwith bilingual support - Fixed file paths in documentation references
- Updated all code examples to use
getRowsByCode()instead of removedgetRowByCode() - Enhanced PHPdoc comments throughout the codebase
- Improved documentation consistency across all files in both languages
[8.1.0] - 2025-12-19
[8.1.0]: https://github.com/codesaur-php/DataObject/compare/v7.0.0...v8.1.0
Added
- Full support for MySQL, PostgreSQL, and SQLite databases
Modelclass for non-localized tables with comprehensive CRUD operationsLocalizedModelclass for multi-language content management- Automatic table creation with column definitions
- Unit and Integration tests with PHPUnit
- CI/CD pipeline with GitHub Actions
Changed
- Enhanced database driver detection and compatibility
- Improved error handling across all database operations
- Better support for different SQL dialects
[7.0.0] - 2025-09-21
[7.0.0]: https://github.com/codesaur-php/DataObject/compare/v5.0.0...v7.0.0
Breaking Changes
- Removed
MultiModelclass - Replaced withLocalizedModelfor better naming and functionality - Migration: Update all
MultiModelreferences toLocalizedModel
Added
- New
LocalizedModelclass - Improved replacement forMultiModel- Better PostgreSQL support with
RETURNINGclause - Enhanced error handling for localized content operations
- Improved insert/update methods with better transaction handling
- Better PostgreSQL support with
Changed
- Refactored localized content handling architecture
- Improved content table foreign key relationships
- Enhanced
insert()method to return full row data instead of just ID - Better error messages with detailed exception information
Fixed
- Fixed PostgreSQL compatibility issues with
lastInsertId() - Improved transaction rollback on content insertion failures
[5.0.0] - 2024-06-24
[5.0.0]: https://github.com/codesaur-php/DataObject/compare/v3.0...v5.0.0
Breaking Changes
- PHP version requirement upgraded from PHP 7.2+ to PHP 8.2.1+
- Removed
StatementTrait- Functionality merged into other traits
Added
- Enhanced type safety with PHP 8.2+ features
- Improved error handling with better exception messages
Changed
- Updated
composer.jsonto require PHP ^8.2.1 - Refactored trait structure for better code organization
- Improved PDO error handling in
PDOTrait
Removed
StatementTrait- Functionality integrated intoTableTraitandPDOTrait
[3.0] - 2021-10-20
[3.0]: https://github.com/codesaur-php/DataObject/compare/v2.0...v3.0
Added
- New
PDOTrait- Extracted PDO operations into reusable trait- Centralized PDO connection management
- Improved error handling with detailed exception messages
- Added
hasTable()method for table existence checking - Added
setForeignKeyChecks()method for foreign key management
- New
StatementTrait- Statement handling functionalitycreateTable()method for table creationcreateTableVersion()method for version table creationselectFrom()method with comprehensive JOIN support (INNER, LEFT, RIGHT, CROSS)
Changed
- Improved separation of concerns with trait-based architecture
- Enhanced error messages with PDO error information
- Better exception handling throughout the codebase
[2.0] - 2021-04-06
[2.0]: https://github.com/codesaur-php/DataObject/compare/v1.0...v2.0
Breaking Changes
- Refactored
Tableclass toTableTrait- Converted from class to trait Modelclass architecture changed - Now usesTableTraitinstead of extendingTable- Property names changed from public to private with underscore prefix (
$name->$_name,$columns->$_columns)
Added
- Trait-based architecture for better code reusability
__initial()method hook for post-table creation initialization- Improved table creation with collate support
- Enhanced delete operations with better condition handling
deactivate()method for soft deletes usingis_activecolumn
Changed
- Refactored from inheritance-based to composition-based design
- Improved
delete()method with better condition array support - Enhanced
create()method with collate parameter - Better error messages with class context
Removed
Tableclass - Replaced withTableTrait
[1.0] - 2021-03-02
[1.0]: https://github.com/codesaur-php/DataObject/releases/tag/v1.0
Initial Release
This version is the initial stable release of the codesaur/dataobject package.
Added
- Core Classes:
Tableclass - Base table management with full CRUD operationsModelclass - ExtendsTablefor single-table modelsMultiModelabstract class - Multi-language content managementColumnclass - Column definition and type management
- Features:
- Table creation with column definitions
- Automatic ID column generation
- Foreign key support
- Version table creation
- Insert, Update, Delete operations
- Select operations with WHERE, ORDER BY, LIMIT
- Soft delete support via
is_activecolumn - Automatic timestamp management (
created_at,updated_at) - User tracking (
created_by,updated_by) via environment variables
- Requirements:
- PHP 7.2 or newer
- PDO extension