I have a class like this:
<?php namespace AppORM; use CakeORMQuery as ORMQuery; use CakeDatabaseValueBinder; use CakeDatasourceConnectionManager; class Query extends ORMQuery { /*Some stuff which has no relevance in this question*/ protected $mainRepository; protected function isReplicate() { return ($this->mainRepository && $this->mainRepository->behaviors()->has('Replicate') && ($this->getConnection()->configName() !== 'c')); } public function __construct($connection, $table) { parent::__construct($connection, $table); $this->mainRepository = $table; } public function execute() { if ($this->isReplicate()) { $connection = $this->getConnection(); $replica = clone $this; $replica->setConnection(ConnectionManager::get('c')); $replica->execute(); } $result = parent::execute(); return $result; } }
This works well, that is, there is a central c
server and there are other servers that are separated by districts. There are some tables that are to be refreshed on c
when something was executed
for them on a district server. Table models that are to be replicated look like this:
<?php namespace AppModelTable; use AppORMTable; class SomeNameTable extends Table { public function initialize(array $config) { /*Some initialization that's irrelevant from the problem's perspective*/ } }
Everything works, but there is a catch. The use AppORMTable;
statement specifies that my own Table
implementation should be used and that Table
implementation ensures that once query
is being called, my Query
class will be used, described in the first code chunk from this question. This is my Table
class
:
<?php namespace AppORM; use CakeORMTable as ORMTable; class Table extends ORMTable { public function query() { return new Query($this->getConnection(), $this); } }
As mentioned earlier, everything works as expected, but this approach effectively means that I will need to change the namespace of the base class for all the models where this replication behavior is needed. This is surely easy to do now, but in the future I worry that some new tables are to be replicated and developers working on that will not read documentation and best practices section, inheriting the model directly from Cake’s class with the same name. Is there a way to tell Cake that I would like all models fulfilling some logical validation, (for example for models that have a behavior) will use the overriden execute
method? In general, the answer to such questions would be a “no”, but I wonder whether Cake has a feature for overriding code behavior based on some rules.
Ex.
function isReplicate($model) { return ($model->behaviors()->has('Replicate')); }
The function above could determine whether the new execute
is preferred or the old, Cake one.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Not really, no, at least as far as I understand your question.
There’s events that you could utilize, Model.initialize
for example, it would allow you to check whether the initialized model has a specific behavior loaded, but you would not be able to change how the inherited query()
method behaves.
You could use it for validation purposes though, so that developers that don’t follow your documentation get slapped in the face when they don’t extend your base table class, eg check whether it’s being extended and throw an exception if that’s not the case, something along the lines of this:
// in `Application::bootstrap()`
CakeEventEventManager::instance()->on(
'Model.initialize',
function (CakeEventEventInterface $event) {
$table = $event->getSubject();
assert($table instanceof CakeORMTable);
if (
$table->behaviors()->has('Replicate') &&
!is_subclass_of($table, AppModelTableAppTable::class)
) {
throw new LogicException(
'Tables using the Replicate behavior must extend AppModelTableAppTable'
);
}
}
);
See also
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0