Model is the central Orm manager, it provides repositories and manages their loading. Model requires a repository loader. Model itself ensures the persistence, removal and refresh behavior synchronization across repositories.
Call persist()
or remove()
method to process the
passed entity. Persist internally handles the needed insert or update database
call. At the end of your work, you should confirm your changes by flushing them.
Flushing is internally implemented as a transaction commit; transactions are
automatically opened with the first persist or remove call. Not only newly
created entities, but also already persisted entities must be persisted once
more to promote its changes to the storage. This behavior differs from
Doctrine, which automatically saves all changes in attached entities.
$user = $model->users->getById(1);
$user->isEmailSubscribed = false;
$model->persist($user);
$model->flush();
// or
$model->persistAndFlush($user);
To remove call remove()
method.
$user = $model->users->getById(1);
$model->remove($user);
$model->flush();
// or
$model->removeAndFlush($user);
You may totally disable cascade behavior by passing the second optional
false
argument. However, this may lead to inconsistencies what is
stored in database and what is not, then it's your responsibility to call
persist properly.
$author = new Author();
$book = new Book();
$book->author = $author;
// with auto-cascade
$model->persit($book);
$model->flush();
// or without auto-cascade
$model->persist($author, false);
$model->persist($book, false);
$model->flush();
In some use-cases it is needed to refresh the entity data from the storage,
where they may have been changed. However, just repeated fetching entity from
repository does not return updated entity though it may run new database select
query. This is due to Identity map and Orm data constistency. To solve the
refresh need Orm provides Model::refreshAll()
method which will
refresh all entities from the storage.
$book = $model->books->getById(1);
sleep(60); // sleep for one minute
$model->refreshAll();
// $book is updated with the latest data from database
Also, some entities may be changed but not persisted. Calling
refreshAll()
in such case will throw an
Nextras\Orm\Exception\InvalidStateException
exception. You may
allow data override by passing true
argument to the method.
$book = $model->books->getById(1);
$book->title = 'Test';
$model->persistAndFlush($book);
$book->title = 'Changed title';
$model->refreshAll(true);
assert($book->title === 'Test');
// the title may be actually different, because another process may have changed it
// the "Changed title" value is discarded and replaced by the actual database value
Batch processing is often memory demanding. To free some memory, you may use
IModel::clear()
method. Calling clear will clear all caches and
references to all fetched entities, it also nulls their values & data. Be
aware that you should never access these entity after calling the clear method.
Also, be careful not to store any references to this entities.
$lastId = 0;
do {
$fetched = $model->books->findBy(['id>' => $lastId])->orderBy('id')->limitBy(1000)->fetchAll();
foreach ($fetched as $book) {
// do the work
$lastId = $book->id;
}
// release the entities from the memory
$model->clear();
} while (!empty($fetched));
// optionally, the final memory release
unset($fetched, $book);
$model->clear();