\gcgov\framework\services\mongodb
You will primarily interact with this service through extended classes that model your data structure. Data classes
will extend \gcgov\framework\services\mongodb\model
or \gcgov\framework\services\mongodb\embedded
.
environment.json
{
"...": "...",
"mongoDatabases": [
{
"default": true,
"database": "DatabaseName",
"uri": "mongodb+srv://DatabaseUsername:DatabaseUserPasswordd@Host/DatabaseName",
"audit": false,
"include_meta": true,
"include_metaLabels": false,
"include_metaFields": true,
"logging": true,
"auditDatabaseName": "",
"auditDatabaseUri": "",
"encryption": {
"useEncryption": true,
"keyVaultNamespace":"DatabaseName.__keyVault",
"kmsProviders": {
"gcp": {
"email": "serviceaccountname",
"masterKeyLocationFilePathName": "gcpMasterKeyLocation.json",
"privateKeyFilePathName": "gcpPrivateKey.txt",
"credentialsFilePathName": "gcpCredentials.json"
}
},
"cryptSharedLibPath": "C:\\inetpub\\corephp\\mongocryptlib\\mongo_crypt_v1.dll",
"encryptedCollectionsFields": [
{
"collection": "CollectionNameWithEncryptedFields",
"encryptedFieldMap": [
{
"keyAltName": "dek1",
"keyId": "generated by running $mdb->createEncryptedCollection( $collectionName )",
"path": "EncryptedFieldName1",
"bsonType": "string",
"queries": {
"queryType": "equality"
}
},
{
"keyAltName": "dek2",
"keyId": "generated by running $mdb->createEncryptedCollection( $collectionName )",
"path": "EncryptedFieldName2",
"bsonType": "int"
}
]
}
]
}
}
]
}
encryption
key is optional. Exclude it when encryption is not being used
- For encryption configuration see: https://www.mongodb.com/docs/v7.0/core/queryable-encryption/tutorials/gcp/gcp-automatic/
- Encrypted collections must be explicitly created
Configuration
masterKeyLocationFilePathName.json
{
"projectId": "gcp-project-id",
"location": "us-east4",
"keyRing": "gcp-keyring-id",
"keyName": "gcp-keyname"
}
gcpCredentials.json this file is generated when creating a service account
{
"type": "service_account",
"project_id": "",
"private_key_id": "",
"private_key": "",
"client_email": "",
"client_id": "",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "",
"universe_domain": "googleapis.com"
}
gcpPrivateKey.txt
Generate this file using the following command
cat gcpCredentials.json | jq -r .private_key | openssl pkcs8 -topk8 -nocrypt -inform PEM -outform DER | base64
Create Encrypted Collection
$mdb = new mdb( $collectionName, '', [], false );
$mdb->createEncryptedCollection( $collectionName );
Rotate Keys
$mdb = new mdb( $collectionName, '' );
$mdb->rotateKeys();
A class that extends \gcgov\framework\services\mongodb\model
is a representation of the documents in a Mongo
collection. Every model must include a public field $_id
of type \MongoDB\BSON\ObjectId
that will serve as the
'primary key' for the collection.
Example: This inspection
model defines the fields and types that documents stored in the inspection
collection in
Mongo. All examples assume this is the model.
final class inspection extends \gcgov\framework\services\mongodb\model {
const _COLLECTION = 'inspection';
const _HUMAN = 'inspection';
const _HUMAN_PLURAL = 'inspections';
#[label( 'Id' )]
public \MongoDB\BSON\ObjectId $_id;
#[label( 'Project Id' )]
public \MongoDB\BSON\ObjectId|null $projectId = null;
#[label( 'Inspection Number' )]
#[autoIncrement]
public int $inspectionNumber = 0;
#[label( 'Locations' )]
/** @var \app\models\component\address[] $address */
public array $addresses = [];
}
In Mongo, the documents in the inspection
collection will look like:
{
"_id": '66aa42df57b1bd608017dbf5',
"projectId": '66aa42e3582cbf0763728468',
"inspectionNumber": 0,
"addresses": []
}
Extending \gcgov\framework\services\mongodb\model
provides static methods for storing and retrieving documents from
Mongo.
\app\models\inspection::getAll( array $filter = [], array $sort = [], array $options = [] )
\app\models\inspection::getPagedResponse( int|string|null $limit, int|string|null $page, array $filter = [], array $options = [] )
\app\models\inspection::getOne( \MongoDB\BSON\ObjectId|string $_id )
\app\models\inspection::getOneBy( array $filter = [], array $options = [] )
\app\models\inspection::aggregation( array $pipeline = [], $options = [] )
\app\models\inspection::save( object &$object, bool $upsert = true, bool $callBeforeAfterHooks = true, ?\MongoDB\Driver\Session $mongoDbSession = null )
\app\models\inspection::saveMany( array &$objects, bool $upsert = true, bool $callBeforeAfterHooks = true, ?\MongoDB\Driver\Session $mongoDbSession = null )
\app\models\inspection::delete( \MongoDB\BSON\ObjectId|string $_id, ?\MongoDB\Driver\Session $mongoDbSession = null )
\app\models\inspection::deleteMany( array $itemsToDelete, ?\MongoDB\Driver\Session $mongoDbSession = null )
Get All
Method will return an array of you model class with all matching documents in the collection.
$options
is an associative array specifying the desired options as provided in the Mongo
library See options
Typemap is automatically added to the options based on the type definitions of the model
\app\models\inspection::getAll( array $filter = [], array $sort = [], array $options = [] )
Example: Return all records in the collection. Caution - providing no filter can be memory intensive and lengthy.
$inspections = \app\models\inspection::getAll()
Example: Return matching records in the collection, sorted by field 'inspectionNumber' in ascending order
$inspections = \app\models\inspection::getAll([ 'inspectionNumber'=>['$gt'=>10] ], [ 'inspectionNumber'=>1 ])
Get All Paged
Method will return an instance of \gcgov\framework\services\mongodb\getResult
where:
$result->getData()
is array of you model class with all matching documents in the collection
$result->getLimit()
is the maximum number of documents per page
$result->getPage()
is the current page the results represent
$result->getSkip()
is the number of documents to skip to get to the first document on this page
$result->getTotalDocmentCount()
is the grand total number of documents that match the provided filter
$options
is an associative array specifying the desired options as provided in the Mongo
library See options
Typemap is automatically added to the options based on the type definitions of the model
\app\models\inspection::getPagedResponse( int|string|null $limit, int|string|null $page, array $filter = [], array $options = [] )
Example: Return the first page of up to 10 documents that match the provided filter
\app\models\inspection::getPagedResponse( 10, 1, [ 'inspectionNumber'=>['$gt'=>10] ] )
Get One
Method will return the matching document in the collection.
\app\models\inspection::getOne( \MongoDB\BSON\ObjectId|string $_id )
Example: return one document from the collection
$inspection = \app\models\inspection::getOne( '66aa2d805b4ad858460f12b7' )
Get One By Filter
Method will return the first document in collection that matched the filter. $options
is an associative array
specifying the desired options as provided in the Mongo
library See options
Typemap is automatically added to the options based on the type definitions of the model
\app\models\inspection::getOneBy( array $filter = [], array $options = [] )
Example: return one document from the collection
$inspection = \app\models\inspection::getOneBy( ['inspectionNumber'=>9] )
Aggregation Pipeline
Method will return an array of objects produced by the aggregation pipeline.
$pipeline
is an associative array specifying
an aggregation pipeline operation
$options
is an associative array specifying the desired options as provided in the Mongo
library See options
NOTE: typemap is not defined automatically because the pipeline may generate a document that does not match the
model class. All models use persistence from the Mongo library which adds __pclass
to each document in the collection
that saves the document type. Documents defined in the pipeline output that include the __pclass
field, the returned
documents will be typecast during deserialization.
\app\models\inspection::aggregation( array $pipeline = [], $options = [] )
Example: return an array of inspection models with an added field named 'createdDate', set from a matching project
$inspections = \app\models\inspection::aggregation([
[
'$match' => [
'inspectionNumber' => ['$gt'=>10]
]
],
[
'$lookup' => [
'from' => 'project',
'localField' => 'projectId',
'foreignField' => '_id',
'as' => 'projects'
]
],
[
'$unwind' => [
'path' => '$projects',
'preserveNullAndEmptyArrays' => false
]
],
[
'$addFields' => [
'createdDate' => '$projects.applicationDate'
]
]
]);
Save One
Method will update or insert the provided object into the collection and will
return gcgov\framework\services\mongodb\updateDeleteResult
that reveals details about the database actions performed.
$object
is the model to save. It is passed by reference so any changes made to the object as a result of the save
operation will be available in the same object after the save is completed.
$upsert
defaults to true. Can be set to false to only allow updating existing records
$callBeforeAfterHooks
defaults to true. Can be set to false to disable automatic calling of _beforeSave( &$object )
and _afterSave( &$object )
on the model and
$mongoDbSession
is null by default but a \MongoDB\Driver\Session
can be provided in order to perform a transaction
of multiple model operations across one or many collections.
\app\models\inspection::save( object &$object, bool $upsert = true, bool $callBeforeAfterHooks = true, ?\MongoDB\Driver\Session $mongoDbSession = null ): updateDeleteResult
Example: default save operation for \app\models\inspection
object
$updateResult = \app\models\inspection::save( $inspection );
Example: save \app\models\inspection
object as part of a transaction
$transactionSession = \gcgov\framework\services\mongodb\tools\mdb::startSessionTransaction();
try {
\app\models\structure::save( $structure, true, true, $transactionSession );
\app\models\inspection::save( $inspection, true, true, $transactionSession );
$transactionSession->commitTransaction();
$transactionSession->endSession();
}
catch( modelException $e ) {
if( $transactionSession->isInTransaction() ) {
$transactionSession->abortTransaction();
}
}
Save Many
Method will update or insert the provided objects into the collection and will return and array
of gcgov\framework\services\mongodb\updateDeleteResult
that reveals details about the database actions performed.
$object
is the model to save. It is passed by reference so any changes made to the object as a result of the save
operation will be available in the same object after the save is completed.
$upsert
defaults to true. Can be set to false to only allow updating existing records
$callBeforeAfterHooks
defaults to true. Can be set to false to disable automatic calling of _beforeSave( &$object )
and _afterSave( &$object )
on the model and
$mongoDbSession
is null by default but a \MongoDB\Driver\Session
can be provided in order to perform a transaction
of multiple model operations across one or many collections.
\app\models\inspection::saveMany( array &$objects, bool $upsert = true, bool $callBeforeAfterHooks = true, ?\MongoDB\Driver\Session $mongoDbSession = null ): updateDeleteResult[]
Example: default save operation for many \app\models\inspection
objects
$updateResults = \app\models\inspection::saveMany( $inspections );
Example: save many \app\models\inspection
objects as part of a transaction
$transactionSession = \gcgov\framework\services\mongodb\tools\mdb::startSessionTransaction();
try {
\app\models\structure::saveMany( $structures, true, true, $transactionSession );
\app\models\inspection::saveMany( $inspections, true, true, $transactionSession );
$transactionSession->commitTransaction();
$transactionSession->endSession();
}
catch( modelException $e ) {
if( $transactionSession->isInTransaction() ) {
$transactionSession->abortTransaction();
}
}
Delete One
Method will delete the provided object in the collection and will
return gcgov\framework\services\mongodb\updateDeleteResult
that reveals details about the database actions performed.
$mongoDbSession
is null by default but a \MongoDB\Driver\Session
can be provided in order to perform a transaction
of multiple model operations across one or many collections.
\app\models\inspection::delete( \MongoDB\BSON\ObjectId|string $_id, ?\MongoDB\Driver\Session $mongoDbSession = null ): updateDeleteResult
Example: default delete operation for a \app\models\inspection
model
$updateResult = \app\models\inspection::delete( '66aa2d805b4ad858460f12b7' );
Example: delete \app\models\inspection
object as part of a transaction
$transactionSession = \gcgov\framework\services\mongodb\tools\mdb::startSessionTransaction();
try {
\app\models\structure::save( $structure, true, true, $transactionSession );
\app\models\inspection::delete( '66aa2d805b4ad858460f12b7', $transactionSession );
$transactionSession->commitTransaction();
$transactionSession->endSession();
}
catch( modelException $e ) {
if( $transactionSession->isInTransaction() ) {
$transactionSession->abortTransaction();
}
}
Delete Many
Method will update or insert the provided objects into the collection and will return and array
of gcgov\framework\services\mongodb\updateDeleteResult
that reveals details about the database actions performed.
$itemsToDelete
is an array of the model objects to delete
$mongoDbSession
is null by default but a \MongoDB\Driver\Session
can be provided in order to perform a transaction
of multiple model operations across one or many collections.
\app\models\inspection::deleteMany( array $itemsToDelete, ?\MongoDB\Driver\Session $mongoDbSession = null ): updateDeleteResult[]
Example: default delete operation for many \app\models\inspection
objects
$updateResults = \app\models\inspection::deleteMany( $inspections );
Example: delete many \app\models\inspection
objects as part of a transaction
$transactionSession = \gcgov\framework\services\mongodb\tools\mdb::startSessionTransaction();
try {
\app\models\structure::save( $structure, true, true, $transactionSession );
\app\models\inspection::deleteMany( $inspections, $transactionSession );
$transactionSession->commitTransaction();
$transactionSession->endSession();
}
catch( modelException $e ) {
if( $transactionSession->isInTransaction() ) {
$transactionSession->abortTransaction();
}
}
A class that extends \gcgov\framework\services\mongodb\embedded
is a representation of an embedded document that can
be embedded in any model class.
Embedded objects do not have any required fields but it is best practice to include
an Object Id as $_id
if the embedded object will be embedded in an array in a model field. When embedded as an array,
the model must use a PHPDoc comment to set the type. Without a PHPDoc comment to define the array type, the array will
not only be deserialized to the embedded type if __pclass
is stored in the database. __pclass
deserialization should
not be relied on.
Embedded objects cannot be saved as top level documents in a collection. If you wish to both embed an object and store it in its own collection, it must be defined as a model. There are important caveats to this approach that you must be aware of to correctly handle saving embedded models (see 'Attributes for Embedding Models' section).
namespace \app\models\component\address;
class address extends \gcgov\framework\services\mongodb\embeddable {
public \MongoDB\BSON\ObjectId $_id;
#[label( 'Address Type' )]
public string $type = 'mailing';
#[label( 'Address' )]
public string $address = '';
#[label( 'Apt/Suite' )]
public string $address2 = '';
#[label( 'City' )]
public string $city = '';
#[label( 'State' )]
public string $state = '';
#[label( 'Zip' )]
public string $zip = '';
#[label( 'Address Type List' )]
#[excludeJsonDeserialize]
#[excludeBsonUnserialize]
#[excludeBsonSerialize]
/** @var string[] $_validTypes */
public array $_validTypes = [
'mailing' => 'Mailing',
'physical' => 'Physical'
];
Model and embedded object properties may utilize attributes to customize functionality of a property or add meta data about the field.
Applied to classes. When serialized to JSON, model and embedded classes will automatically include a _meta
field. To
disable this for a specific model or embedded class, give the class the #[includeMeta(false)]
attribute
Properties tagged with #[excludeBsonSerialize]
will not be saved in the database
Properties tagged with #[excludeBsonUnserialize]
will be excluded when deserializing the document from the database.
The resulting object will have the default value for the property regardless of what value is saved in the database for
the property.
Properties tagged with #[excludeJsonSerialize]
will be excluded from the output when serializing the object to json
Properties tagged with #[excludeJsonDeserialize]
will be excluded when deserializing the object from JSON to object.
The resulting object will have the default value for the property regardless of what value was set in the JSON string.
Properties tagged with #[label(string $label)]
will be added the object's _meta
output in the labels section and the
fields section.
Example embedded class with label:
class address extends \gcgov\framework\services\mongodb\embeddable {
public \MongoDB\BSON\ObjectId $_id;
#[label( 'Address Type' )]
public string $type = 'mailing';
}
After JSON serialization:
{
"_id": "",
"type": "mailing",
"_meta": {
...
"fields": {
"type": {
"label": "Address Type",
"error": false,
"errorMessages": [],
"success": false,
"successMessages": [],
"hints": [],
"state": "",
"required": false,
"visible": true,
"valueIsVisibilityGroup": false,
"visibilityGroups": [],
"validating": false
}
}
}
}
Properties tagged with #[autoIncrement]
will automatically increment upon insert into the database. With no parameters
provided, the value will be set to the previous maximum value + 1.
final class inspection extends \gcgov\framework\services\mongodb\model {
...
#[label( 'Inspection Number' )]
#[autoIncrement]
public int $inspectionNumber = 0;
...
}
- The first document inserted into the
inspection
collection will have$inspectionNumber
set to 1 (previous max of 0 + 1). - The second document inserted into the
inspection
collection will have$inspectionNumber
set to 2 (previous max of 1 + 1). - The third document inserted into the
inspection
collection will have$inspectionNumber
set to 3 (previous max of 2 + 1).
By default, one property in a collection will have an ever-increasing automatic value. You can, however, create groups of incrementing numbers within a collection. Grouping allows one collection to have multiple automatic incrementing values that increment at different rates.
In addition, auto incremented values may be formatted by providing a method name to the countFormatMethod
parameter.
In this example, documents in the project
collection will have $projectReferenceNumber
set to a formatted increasing
value within the group provided.
final class project extends \gcgov\framework\services\mongodb\model {
...
#[label( 'Project Reference Number' )]
#[autoIncrement( groupByMethodName: 'getProjectNumberGroup', countFormatMethod: 'formatProjectIncrementer' )]
public string $projectReferenceNumber = '';
...
public function getProjectNumberGroup(): string {
if( $this->projectType==='fireMarshal' ) {
return 'FM';
}
elseif( $this->projectType==='stormwater' ) {
return 'SW';
}
//default by calendar year
return (string)$this->applicationDate->format( 'Y' );
}
public function formatProjectIncrementer( int $count ): string {
return $this->getProjectNumberGroup() . '-' . str_pad( $count, 4, '0', STR_PAD_LEFT );
}
}
- The first document inserted into the
project
collection with fieldprojectType
set tofireMarshal
will have$projectReferenceNumber
set to FM-0001 (group FM previous max of 0 + 1). - The second document inserted into the
project
collection with fieldprojectType
set tofireMarshal
will have$projectReferenceNumber
set to FM-0002 (group FM previous max of 1 + 2). - The first document inserted into the
project
collection with fieldapplicationDate
in 2024 and fieldprojectType
set topermits
will have$projectReferenceNumber
set to 2024-0001 (group 2024 previous max of 0 + 1). - The second document inserted into the
project
collection with fieldapplicationDate
in 2024 and fieldprojectType
set topermits
will have$projectReferenceNumber
set to 2024-0002 (group 2024 previous max of 1 + 1).
Properties tagged with #[redact( array $redactIfUserHasAnyRoles=[], array $redactIfUserHasAllRoles=[] )]
will be
removed from the JSON output of the system when the provided conditions are met. This is useful for allowing a role to
read from a collection but to hide certain properties from the user because of their permission roles.
Example: users with the role constants::ROLE_PUBLIC_WEB
will not see a phone property on the JSON object returned to
them.
final class project extends \gcgov\framework\services\mongodb\model {
...
#[label( 'Phone' )]
#[redact( [ constants::ROLE_PUBLIC_WEB ] )]
public \app\models\component\phone $phone
...
}
Properties tagged with #[visibility(bool $default = true, array $groups = [], bool $valueIsVisibilityGroup = false)]
will impact the output of _meta.fields.{field-name}.visible
, _meta.fields.{field-name}.valueIsVisibilityGroup
, and
_meta.fields.{field-name}.visibilityGroups
. This will only ever set the default state. Javascript must be used on the
UI to respect the visibility of fields and to respond to changes in the visibilityGroups
so that field visibility is
updated as other values on the object are modified.
Example:
final class project extends \gcgov\framework\services\mongodb\model {
...
#[label( 'Status' )]
#[visibility( default: true, valueIsVisibilityGroup: true )]
public ?\app\models\keyValueItem $status = null;
#[label( 'Application Date' )]
#[visibility( default: true )]
public \DateTimeImmutable $applicationDate;
#[label( 'Submitted Date' )]
#[visibility( default: false, groups: [ constants::EXTERNAL_STATUS_ID_SUBMITTED ] )]
public ?\DateTimeImmutable $submittedDate = null;
...
}
See Permits API/App externalWebRequests for full example in use
These attributes are only relevant on properties that embed other top level models.
When an object with a property tagged with #[deleteCascade]
is deleted, all instances of the child item are also
deleted in its own collection and anywhere else it is embedded.
Example:
final class project extends \gcgov\framework\services\mongodb\model {
...
#[deleteCascade]
public ?\app\model\inspection $inspection = null;
...
}
When \app\models\project::delete( $projectId )
is called, the inspection saved in $inspection
will be removed from
the inspection collection and removed from all other documents that it is embedded in.
It is possible to create an infinite loop by nesting models. To the extent possible, you should avoid a nesting loop of models.
An example would be if a project
embeds an inspection
but inspection
also includes project
as a property
that isn't saved to the database but is used for aggregation. This would cause an infinite loop because as the typemap
is resolved for project
, inspection
is resolved which requires project
to be resolved, which requires inspection
to be resolved, etc.
To escape this trap, tag the nested property (inspection.project
in this example) with
#[excludeFromTypemapWhenThisClassNotRoot]
to exclude it from the typemap resolution. The caveat to this is that
$inspection->project
may not be typed as project
. In these cases we are relying on __pclass
automatic
typecasting.
Properties tagged with #[foreignKey()]
must be typed arrays with a model type. The purpose is to enable insertions
of the foreign model in the foreign collection to automatically insert into the typed array as well.
Basic Example:
The first parameter of #[foreignKey(string $embeddedPropertyName, array $embeddedObjectFilter = [] )]
must match the
field name in the embedded model that will match the $_id
of the parent model.
In this example, when \app\model\transaction::save( $transaction )
is called, the transaction will be stored in the
transaction
collection and will also be inserted into documents in the project
collection in the transactions
field where project._id
matches transaction.projectId
.
final class project extends \gcgov\framework\services\mongodb\model {
...
#[label( 'Transactions' )]
#[foreignKey( 'projectId' )]
/** @var \app\models\transaction[] $transactions */
public array $transactions = [];
...
}
final class transaction extends \gcgov\framework\services\mongodb\model {
...
public \MongoDB\BSON\ObjectId $_id;
#[label( 'Project Id' )]
public ?\MongoDB\BSON\ObjectId $projectId = null;
...
}
Advanced Example:
The second parameter of #[foreignKey(string $embeddedPropertyName, array $embeddedObjectFilter = [] )]
is an optional
filter to limit what documents are embedded automatically. The $embeddedObjectFilter
should be a standard Mongo find
array filter that is used to filter the embedded model collection to further restrict which documents will be embedded
on insert. In this example, only documents where the transaction.projectId
matches project._id
and where
transaction.recurringTemplate
is false
will be embedded.
final class project extends \gcgov\framework\services\mongodb\model {
...
#[label( 'Transactions' )]
#[foreignKey( 'projectId', [ 'recurringTemplate' => false ] )]
/** @var \app\models\transaction[] $transactions */
public array $transactions = [];
...
}
final class transaction extends \gcgov\framework\services\mongodb\model {
...
public \MongoDB\BSON\ObjectId $_id;
#[label( 'Project Id' )]
public ?\MongoDB\BSON\ObjectId $projectId = null;
#[label( 'Is Recurring Template' )]
public bool $recurringTemplate = null;
...
}
See Symfony Validation for all Assert options and Validation Groups for details.
use Symfony\Component\Validator\Constraints as Assert;
use gcgov\framework\models\customConstraints as CustomAssert;
#[Assert\NotBlank]
public ?\app\models\keyValueItem $projectType = null;
#[Assert\Expression( expression: 'this.externalApplicantRequests or value', message: 'At least one applicant is required' )]
/** @var \app\models\applicant[] $applicants */
public array $applicants = [];
Classes implementing validation groups must add method public function _defineValidationGroups(): string[]
. Groups
allow fields to be conditionally validated.
Example:
final class project extends \gcgov\framework\services\mongodb\model {
...
//required if any of the validation groups listed are present in _defineValidationGroups
#[CustomAssert\OptionalValid(expression:'value!=null', groups:[ constants::EXTERNAL_PROJECT_TYPE_ID_NEW_HOME, constants::EXTERNAL_PROJECT_TYPE_ID_RES_ADDITION ])]
public ?\app\models\component\externalContractorRequest $externalBuildingContractorRequest = null;
public function _defineValidationGroups(): array {
$validationGroups = [];
if( $this->projectType instanceof keyValueItem ) {
$validationGroups = [ (string)$this->projectType->_id ];
}
return $validationGroups;
}
...
}
To run validation, call the updateValidationState
method on the model or embedded object.
${modelOrEmbeddedInstance}->updateValidationState();
Enable auditing for the database with config options.
By default, auditing will create json patches that move from the current state of the object to the state of the object
prior to the update. Enable auditForward
to generate a patch from the object prior to save to the object after save.