I'm facing some object relationship problems in an application that, among other things, handles multiple choices exercises.
Thinking of those exercises, I can that:
1- I have several exercises, that have several questions that have several alternatives.
2- A specific question can be part of several exercises.
3- A specific alternative can NOT be part of several questions.
In terms of relationship:
Exercise < n-n > Question
Question < 1-n > Alternative
I coded the classes the way bellow:
class Exercise {
private $id;
private $name;
private $questions = []; //array of ExerciseQuestion
//...
}
class ExerciseQuestion {
private $id;
private $exercise = new Exercise();
private $question = new Question();
private $order; //handles question's order of appearance
//...
}
class Question {
private $id;
private $wording;
//...
}
class Alternative {
private $id;
private $question = new Question();
private $text;
//...
}
I don't know if I did it wright, but, instead of storing relationships ID's in classes attributes, I'm storing an instance of the related class. It seemed to be right approach when I started.
The problem I foresee is that, in the relation Exercise-ExerciseQuestion-Question, I will be thrown in a hell of circular references. I will have an Exercise that has several ExerciseQuestion that holds an instance of Exercise with a lot of ExerciseQuestion inside it. Am I right in this assumption?
Is there a better - or correct - way to express that kind of relationship? Should I change to store ID's instead of instances or can can make use of some design pattern?
If I'm reading you correctly, you don't actually have a problem. If your domain includes circular or self-referencing relationships, then your models should too.
Since your objects are entities (they have identities), you'll want to take care that only one instance exists for each id. But as long as you enforce that, they can refer to each other however you need them to.
Now, circular references can be tricky to deal with if you need to traverse the object graph in some exhaustive way. In that case, you'll need to take care to not get yourself into an endless loop. But if your domain actually has these relationships, then you need to model them, and you'll have to implement some way to detect cycles and deal with them. The details will be informed by your particular needs.
I am not sure if i understand what you're saying but if you're asking : is that a circular reference problematic? the answer is yes an no, it's depends of what's you're going to do and how you're handling your issue.
But if you are talking about your implementation the answer is definitly no it's not problematic because the class attribute does not store "an objet" but "a reference to an object" hence there is no circular construction wich lead to an infinite recursive iteration in your case
Good luck
You have a problem in your model. A relation object should store only the ids of the parts involved in the relation, an exercise_id and a question_id, and any additional attributes that apply to the relation of both entities, such as the order. You don't instantiate involved entities in the relation object.
To be precise, your ER model is like this
Exercise (id, name)
Question (id, wording)
ExerciseQuestion (exercise_id, question_id, order) // both ids
// form primary key
Alternative (id, text, question_id)
And your classes should follow that.
Related
I have been using Doctrine ORM for a while an now, I have a class-level property (static property) which I need to persist in MySQL database and I would like to now how.
Class Student {
private $name;
public static $instances = array();
public __construct($name) {
$this->name = $name;
self::$instances[] = $this->name;
}
}
According to the Documentation (Basic Mapping > Property Mapping):
The next step after marking a PHP class as an entity is mapping its properties to columns in a table.
To configure a property use the #Column docblock annotation. The type attribute specifies the Doctrine Mapping Type to use for the field. If the type is not specified, string is used as the default.
It sounds like doctrine only supports object-level properties. But as the title reads "Basic Mapping", I think there should be some type of "Advanced Mapping" that maybe covers static properties. I searched for that with no success.
Also it is not listed at Limitations and Known Issues
Question
Someone please let me know if this is possible to persist static properties in Doctrine 2, and if not, How should I accomplish this task? Any work arounds or something?
Unfortunately, my reputation does not allow commenting, so I have to write this as an answer. Sorry for that.
My first thought is that you are going about this the wrong way. Can you give some more information what the "instances" actually are? It looks like it's a list of all student names in the system? Why do you need to have this as a static class property?
Some thoughts:
1)
It sounds like doctrine only supports object-level properties.
Yeah, I think that's correct, but I don't see the use case for anything else really. To me it feels intuitively wrong to have Static data in a database as it's not meant to change (very) often. Can't you just have your values in the code or in a config file (if there are too many). If, on the other hand, your data is changing often, then it's not Static (<=> not changing).
2) If you really want to map it and have it in the db I believe association mappings is the way to go (one-to-many or many-to-many). I.e., you should move it to its own Entity that has a relation to the Student entities. In your case it looks like you should create a University entity that has a list of all students. And that way you can iterate to build a list of all names.
I'm starting a little project with DDD approach. I've created my domain model with Entities and ValueObjects in plain PHP. Entities have references to their associations - in my case, there is an Employee entity with collection of Teams he belongs to, and I keep them in Employee::teams property. Everything is going great, I've created mappings for those entities with associations in YAML, interfaces for repositories to be implemented in the Symfony2 and Doctrine2 layer, etc.
When I fetch Employees from repository (with Doctrine's EntityManager::findAll()) instead of array of Teams I receive PersistentCollection with those teams. It's built on PHP7, and Employee::getTeams() has return type of array so I'm getting the critical exception.
Is there any way to convert it into array with some external listeners (Symfony layer only, to not to mess in domain files) or any other core mechanism?
Thanks.
You get ArrayCollection
http://www.doctrine-project.org/api/common/2.5/class-Doctrine.Common.Collections.ArrayCollection.html
It has toArray() method so you can write
/**
* #return Team[]
*/
public function getTeams(): array
{
return $this->teams->toArray();
}
But I prefer
/**
* #return Team[]|ArrayCollection
*/
public function getTeams()
{
return $this->teams;
}
If you use good IDE like PhpStorm it will understand it correctly to autocomplete it like ArrayCollection and as Team if you make foreach ($employee->getTeams() as $team) {...
ArrayCollection are more powerful than plain arrays. For example you can filter and order them and Doctrine will make optimized SQL so you don't have to load all items
http://docs.doctrine-project.org/en/latest/reference/working-with-associations.html#filtering-collections
Kuba,
That doesn't seem to be a DDD question but a technical question regarding PHP implementation details.
However, please let me jump into your design and try to find a better solution for your domain. You are missing to model the relation between an employee and a team, let's call it employee in team. The way you did you are forcing an AR to reference another AR, saying this way that employee manages a team life cycle. This might not be the case but under a specific scenario another actor might change a status of a team and that could break the Employee invariant over the Team AR. Because of this when you make an AR to manage another AR life cycle then this dependency shouldn't be found through the repository and the root of the aggregate is in the position to now force invariant around the aggregated AR.
There are still some concerns to mention, but just to keep it simple, go ahead and model the concept you are missing: EmployeeInTeam or whatever you want to call it. It references the conceptual identity of the employee and the team so you can remove it safely in a future, you can query employees in a team and teams an employee is part of.
If you need frameworks or the DB to keep the consistence then you are not doing DDD. Use just objects, not the technology.
Regards,
Sebastian.
As a means to try and learn object oriented PHP scripting, I'm currently attempting to rewrite a database web application that I previously wrote in procedural PHP. The application is used to store car parts and information about car parts.
In my application there are car parts. They are identified by various reference numbers, which are assigned by different organisations (the part's manufacturer, re-manufacturers, vehicle manufacturers, etc.), and any particular car part could have zero, one or many reference numbers as assigned by these organisations (and, confusingly, each reference number may refer to more than one unique car part as defined in the database I'm working on).
As far as I understand things, I am dealing with three different classes of entities. There is that of the car part, the reference number, and that of the reference-assigner (in my internal nomenclature I call these 'referrers'). As I am just getting started with learning OOP, I have begun by creating some very basic classes for each:
class Part {
public $part_id;
public $part_type;
public $weight;
public $notes;
public $references;
private $db;
function __construct(Database $db) {
$this->db = $db;
}
}
class Reference {
public $reference_id;
public $reference;
public $referrer;
private $db;
function __construct(Database $db) {
$this->db = $db;
}
}
class Referrer {
public $referrer_id;
public $referrer_name;
private $db;
function __construct(Database $db) {
$this->db = $db;
}
}
?>
What I've been struggling with is how to populate these and subsequently glue them together. The most basic function of my web application is to view a car part, including its metrics and its assigned reference numbers.
A part_id is included in a page request. Initially, I wrote a constructor method in my Part class which would look up that part in the database, and then another method which would look up reference numbers (which were JOINed with the referrer table) assigned to that Part ID. It would iterate through the results and create a new object for each reference, and hold the complete set in an array indexed by the reference_id datum.
After further reading, I began to understand that I should use a factory class to carry this out, however, as this kind of conjunction between my Part class and my Reference class is not the responsibility of any one of those discrete classes. This made conceptual sense, and so I have since devised a class that I've called PartReferenceFactory, which I understand should be responsible for assembling any kind of collation of part reference numbers:
class PartReferenceFactory {
public static function getReferences(Database $db, $part_id) {
$db_result = $db->query(
'SELECT *
FROM `' . REFERRER_TABLE . '`
LEFT JOIN `' . REFERENCE_TABLE . '` USING (`referrer_id`)
INNER JOIN `' . REFERENCE_REL . '` USING (`reference_id`)
WHERE `part_id` = :part_id
ORDER BY `order` ASC, `referrer_name` ASC, `reference` ASC',
array(':part_id' => $part_id);
);
if(empty($db_result)) {
return FALSE;
} else {
$references = array();
foreach($db_result as $reference_id => $reference_properties) {
$references[$reference_id] = new Reference($db);
$references[$reference_id]->reference = $reference_properties['reference'];
$references[$reference_id]->referrer = new Referrer($db);
$references[$reference_id]->referrer->referrer_id = $reference_properties['referrer_id'];
$references[$reference_id]->referrer->referrer_name = $reference_properties['referrer_id'];
}
return $references;
}
}
}
?>
The getReferences method of my factory class is then called inside my Part class, which I revised thusly:
class Part {
public $part_id;
public $part_type;
public $weight;
public $notes;
public $references;
private $db;
function __construct(Database $db) {
$this->db = $db;
}
function getReferences() {
$this->references = PartReferenceFactory::getReferences($this->db, $this->part_id);
}
}
Really I'm looking for advice on whether my general approach is a good one or if, as I suspect, I've misunderstood something, am overlooking other things, and am tying myself in knots. I will try to distill this into some underlying, directly-answerable questions:
Does my understanding of the purpose of classes and of factory classes seem erroneous?
Is it a bad idea for me to store arrays of objects? I ask from a viewpoint more of design than performance, insofar as they are not intertwined.
Is this even an appropriate way to structure relationships/inter-dependencies between classes in PHP?
Is it correct to call my PartReferenceFactory inside the getReferences method of the (instantiated) Part class? And is storing the returned reference objects within the part objects appropriate?
As a part of the application's GUI, I'll need to provide lists of referrers, requiring me to create another array of ALL referrers independently of any part object. Yet some of these referrers will exist within the $references array inside the part object. It has occurred to me that in order to avoid duplicate referrer objects, I could SELECT a list of all referrers at the beginning of each page request, formulate these into a global array of referrers, and simply reference these from within my Part and Reference classes as needed. However, I have read that it is not good to rely on the global scope within classes. Is there an elegant/best-practice solution to this?
Thank you very much for the time of whomever happens to read this, and I apologise for the extremely long question. I often worry that I mis-explain matters, and so wanted to be as precise as possible. Please let me know if it would be beneficial for any parts of my post to be deleted.
Hmmm, I think Jon is right, this question has taken real commitment to get my head round and I'm still not sure I know everything you're asking, but I'll give it a go.
1) Is your understanding of classes/factory classes right?
Well yes and no. Yes you do understand it, but you're taking a very classroom type approach to the problem, rather than the sort of pragmatism that comes with experience. OOP is a way of modelling real things, but it's still fundamentally a programming tool, so don't over complicate your structure, just to keep it real. The main think OOP gives you over structured programming is inheritance, which means you can code things which are kind of like other things, so reuse code better by only coding the stuff that's actually different. If 2 things would share code, make them a shared parent and put the code in there. Envisaging how the hierarchy might work efficiently is 80% of the task of designing an OOP application, and you're bound to get it wrong first time and have to restructure.
For example. I've coded a number of classes which represent entities in a database: ie Users, Realthings, Collectibles. Each has fundamentally different set of attributes and relations, but also has a core set of things that are similar: the way they're interrogated, the way the data is presented, the fact that they have attributes, fields and relations. So I coded a parent class which everything inherits, and it contains most of the code, then the specific children just define the stuff which is different for each class, and the hard work was deciding how much could go in Indexed to avoid repeating code in the child classes. Initially I had a lot of code in the children, but as it evolved I moved more and more code into the parent class, and thinned out the children. Like I say, don't assume you'll get it right first time.
2) Is it a bad idea to store objects in arrays? Well no, but why would you want to? In your example you have an array of references in the database, where the relationship is a many to many relation (ie you have 3 tables with a joining table in the middle). Then when you get the data you create each object and store it in an array. Sure you can do that, but remember each object has an overhead. Loading everything into memory is fine, but don't do it unless you need to. Also be sure you need a many<=>many relationship. I may have mis-read your explanation, but I thought you'd only need a one<=>many relationship, which could be done by storing a reference to the 'one' in the record of each of the 'many' (thus loosing the middle table and simplifying the join).
5) I'm going to jump to the last one at this point because it feeds into #2. You need to think of your application from different perspectives (a) when you have data and are trying to present it (read) (b) when you have some data and are trying to add new data, with links to existing data (adding a relation) and (c) when you have no data, and are adding a fresh record. How might the user get to each of those perspectives and what would happen. It's often easy to get (a) and (c) to work, but making (b) intuitive is often the hard part, and if you over complicate it, then users simply won't get it. When building up the inner data structures in #2 only do what you need, for the perspective a user is in. Unless you're writing an app, you don't need to load everything, only the stuff for the task at hand.
3) Not sure what you mean by 'is this appropriate'. OOP allows you to tie yourself up in knots, or create wonderful works of art. In theory you should just try to keep it simple. There are great books which give examples of why you might want to make things more complicated, but most of the reasons aren't obvious, so you'll need experience to decide if what you're doing is needlessly over complicating things or if it actually avoids a pitfall. From personal experience if you think it's overcomplicating, it probably is.
4) Not sure if this is what you meant, but I've taken this question to be asking if you've used Factory classes correctly. My understanding of the theory is that what you should end up with, is next to no references to doing things statically, beyond the initial creation of a FactoryClass object, stored statically in the child class being used, then you have to code an abstract method in parent class, implemented in each child class, which gets you that object, so you can call on the object of that FactoryClass, using a method call. I normally only call FactoryClass stuff directly when a non-factory class is initialised (ie you need to populate the static in a new object, incase the class hasn't been init'd yet). I don't see any problem calling it directly as you have, but I'd avoid that as the Factory is IMHO an implementation detail of the class, and so shouldn't be exposed outside that.
In my experience you're always learning new things and discovering pitfalls in OOP, so even thought I've been coding professionally for nearly 20 years, I'd not claim to be an expert on this, so I'm sure there will be totally opposing views to what I've said. I think you learn most by doing what your gut says is right, then not being too stubborn to start over again, if you gut changes it's mind :-)
I'm in the process of learning OOPHP, and I'm looking for some 'best practice' advice.
With a relational db, there's obviously foreign keys in many tables. When I am creating Models for my site I am trying to determine if it is better to do JOIN queries in the model, or have one model call another?
Calling other models seems to keep the code more modular. Either way seem to create dependencies, whether it be on another table or anther model.
If I go with the 'call other models' approach I seem to run into another problem: infinite loops. Here's the example I'm running into. I have 2 tables, person and school. Each person has a favorite school, represented by a schoolId. Each school has a principal, that is a personId.
The person object the row is mapped to accepts a school object in its constructor, but the school object the school row is mapped to accepts a person object in its constructor.
From what I've found, something about lazy loading, seems to be the solution, but (I could be wrong) it seems if I do that I can't use PHP's type hinting.
(I'm guessing many will suggest an ORM tool like Doctrine to me, and it's something I will definitely look into in the future. I am avoiding it now because of its supposed steep learning curve, and because I feel I understand those tools better later on if I try it myself once)
Nice question! I had/have same thoughts. And I think it's a really good idea to start code your own before looking at frameworks :)
When I coded my model generator I decided once not to use JOINS and use 'lazy loading'. Meaning I have classes like this (just pseudo code):
class Person extends Model_Resource {
/**
*
*/
protected $name;
/**
* #var Address <-- external reference
*/
protected $address;
/**
* #return Person
*/
public static function select($filter) {
return DB::instance(filter_query('SELECT * FROM `person`', $filter));
}
/**
* #return Address
*/
public function getAddress() {
// lazy loading :
if(is_null($this->address)) {
$this->address = Address::select(new Filter('p_id', $this->id));
}
return $this->address;
}
}
That worked good for me in a medium size application over years. When I really need to speed up things or using a somewhat inregular query, then I'm free to overwrite the auto generated methods and use JOINS, UNION etc...
I'm curious what will others say.
Let's say I have two models:
class Book
{
public $book_id;
public $book_author_id;
public $title;
}
class Author
{
public $author_id;
public $author_name;
}
I'm used to writing something like this:
$DB->query("SELECT book_id, title, author_name
FROM book
LEFT JOIN author
ON book_author_id = author_id
");
Let's assume, that I'm not interested in having separate queries for this association. How do I proceed? Here are some things I've heard:
create a MySQL VIEW of the JOIN
create a model class of the VIEW
The application I'm working on involves dozens of tables and was highly optimized in procedural code (almost no SELECT * anywhere, for instance). I'm refactoring to make it more maintainable (I'm the original creator, too), but I would like to have the flexibility of using joins when I need to without compromising the structure of my files and DB calls.
A possibly related question I have is related to including other models:
class Author
{
public $author_id;
public $author_name;
/* #var Book */ //<--don't really fully understand this but I've seen something like it somewhere
public (array) $authors_books;
}
I'm still searching for answers, but if you could send a link my way, that would be appreciated.
What you are calling "models" are actually domain objects. They should be responsible for dealing with domain business logic, and have nothing to do with storage.
The storage-related logic and interaction should be handled by separate group of objects. One of most sensible solution is using data mappers. Each mapper can deal with multiple tables and complicated SQL.
As for your query, the result of such query would contain information, appropriate for passing to a collection of domain objects.
BTW, that query is quite useless. You forget that each book can have multiple authors. Take for an example this book - it has 4 different authors. To make this query useful, you should have to do GROUP_CONCAT() based on either author_id or book_id.
When implementing such JOIN statements, the database response most likely will be a collection:
$mapper = $factory->buildMapper('BookCollection');
$collection = $factory->buildCollection('Book');
$collection->setSomeCondition('foobar');
$mapper->fetch( $collection );
foreach ( $collection as $item )
{
$item->setSomething('marker');
}
$mapper->store( $collection );
P.S. Your code example seem to be leaking abstraction. It is a bad practice to let other structures to access object's variables directly.
P.P.S. It seems that your understanding of model part of MVC is quite different from how i see it.
Database joins are an artefact of relational databases, you don't need to model them. You need to model what your data is and how it behaves, e.g. you might have a getBooks() method in your Author instances, or a static getByAuthor() method in your Book class (generally, $author->getBooks() should be implemented as Book::getByAuthor($this), so your Author class shouldn't be concerned with Book's implementation details). It's not always a good idea to automatically instantiate all related data (e.g. instantiate Book instances for all books by a given Author instance, as you seem to be considering with your $author_books property), since this might easily degrade into a "load the entire database to memory for each request" scenario.
If you're trying to model your DB in classes, this is a problem that's already been solved.
I suggest you try out the Doctrine framework, which is a full ORM framework for PHP.
Hope that helps.