How do you write model logic with NDB & NDBT (in Nette 2.3)
- juzna.cz
- Member | 248
TL;DR: what's the best practice for handling model logic in NDB & NDBT, which would allow me:
- easily query and fetch rows from database with great and super simple NDBT syntax
- work with the same model representation in complex business logic
Longer version:
Hi, I've been traditionally working with Doctrine 2, where you define your model
classes explicitly and then it's very easy to manipulate your
rows / entities in your complex business model logic, and eventually save the
changes, e.g.:
<?php
class MySuperService {
// Approve objection to a change request, and update the change request accordingly.
public function approveObjection(ChangeRequest $request, Objection $objection) {
if ($objection->isOpen()) {
$objection->status = '...';
}
if (...) {
$this->updateRequestDeadline($request); // possibly modifies $request->deadline and other fields
}
$this->updateWeight($request); // more logic which updates $request
$this->em->flush(); // save changes to db
}
?>
On a smaller projects, I decided to use Nette Database (NDB) & Nette
Database Table (NDBT), because it's simpler and you don't need to write so much
code. It was in version 2.1, and my business logic looked very similar. Concrete
model classes were replaced by generic ActiveRow
:
<?php
class MySuperService {
// Approve objection to a change request, and update the change request accordingly.
public function approveObjection(ActiveRow $request, ActiveRow $objection) {
if ($objection->status === 'open') {
$objection->status = '...'; // works in Nette 2.1
}
if (...) {
$this->updateRequestDeadline($request); // possibly modifies $request->deadline and other fields
}
$this->updateWeight($request); // more logic which updates $request
// save changes to db
$request->update(); // works in Nette 2.1
$objection->update();
}
?>
NDB and especially NDBT made it really easy to fetch data from database and pass it to templates. And it also allowed me to have complex logic in the business model.
However, when I tried upgrading to Nette 2.3, I noticed that this functionality has been removed.
That means I'd have to convert ActiveRow
to an array or to my
custom model class, process the business logic, and then save it back to the
database. This seems very weird and schizophrenic to me – some code working
with ActiveRow
and some with different representation.
How do you handle model classes with NDB & NDBT? Do you
sometimes use ActiveRow
and sometimes another representation? Do
you always convert to your representation? What's the best approach?
- hrach
- Member | 1838
@juzna.cz Well, what a nice question. Nette Database does not allow and support such modeling as it is possible with ORMs. Returned rows are just simple crates. Direct writing access in NDB < 2.3 was causing problems, therefore it was changed. To use advanced modeling over NDB, it is needed to use some advanced|other tools. I didn't agree with David's point of view – such as no possibility to set own row class, that's reason I developed own orm.
- juzna.cz
- Member | 248
That's not really advanced modeling, just working with the simple crates.
You can do the same with plain old PHP:
<?php
$request = mysql_fetch_object(mysql_query("SELECT * FROM ... WHERE ID=1"));
$request->deadline += 10;
$this->updateWeight($request); // changes $request->weight
$fields = [];
foreach ($request as $k=>$v) $fields[] = "`$k`='$v'"; // this would need better escaping in reality
mysql_query("UPDATE ... SET " . join(',', $fields) . " WHERE ID=$request->ID");
?>
You can use the same with PDO, Dibi or basically any other database layer.
- Jan Tvrdík
- Nette guru | 2595
BTW: This change is the reason why I decided not to use NDB on one project. The only workaround I know is to add some abstraction which kills the NDB simplicity.
- juzna.cz
- Member | 248
My workaround was forking GitHub repo of Nette Database and reverting the change :P That was the only way to upgrade my app to Nette 2.3.
What problems was it causing? Any chance the removal can be re-considered?
- hrach
- Member | 1838
@juzna.cz I totally get your feelings. The main point is that the architecture of ndb(t) is pretty messed up and it's not easy to make it right. Some reasons may be found here:
- juzna.cz
- Member | 248
Thanks for the explanation and links.
The TL;DR answer for my question above would be: Best practice is to use a higher-level library on top of NDB(T), e.g. nextras/orm.
Am I right?
- hrach
- Member | 1838
Yes, for your usecase, it would be better to use some library like YetOrm. Nextras/ORM is not based on NDB.