Let's say I have a group of database tables (customer, product, category, customer_products, product_categories, customer_categories) and classes corresponding to each of them (basic entity classes for the basic entity tables, and classes like CustomerProductLinker for the foreign key tables). The "linker" classes have methods like addXToY, removeXFromY, getXsOfY, and getYsOfX.
The problem comes from the additional business requirements that 1) adding a Customer to a Product should add that Customer to each of the Product's Categories, and 2) adding a Product to a Category should add each of that Product's Customers to the Category. With the current class system, that creates a dependency cycle between CustomerProductLinker and ProductCategoryLinker.
I do not know how to solve this. Combining all the "linkers" into one big "SuperLinker" class seems very wrong. And keeping the linker object instantiation inside only the methods that need them rather than passing the linkers in via constructor injection seems worse (though it would technically solve the cycle).
I doubt this system of linker classes is the best way to handle this kind of setup, but I'm not experienced enough to know what could be done instead. Unfortunately I can't use an ORM, because the tables are not all stored on the same server. So... What else can be done?
Related
Diving into the world of DDD is something of a whirlwind for me. While I've done a lot of research I'm struggling to change my thought process.
So, I have a package and a products entity. A package cannot function without products; vice-versa. The problem comes in when I'm needing to get the products belonging to a package (Note: the package is customisable, this means the products belonging to the package could be different the next time round). It seems that this belongs on neither entity, furthermore applying this to the package or product entity would make them tightly coupled.
I must stress that I'm using the word association because I'm trying to figure this out on a domain level rather than infrastructure.
A little thinking has led me to the following thoughts:
Make Packages an Aggregate root & the products to be a sibling of the
Package entity. However I believe that both of the Package & Products
are entities due to them been uniquely identified.
Create a domain service that would take the package ID & map to the
infrastructure layer to find the associated products. However, this
seems rather long winded for a single look up.
It would be great if someone could turn me sane again! Thanks in advance!
Ubiquitious Language
DDD is all about language - the key here is to listen to your domain experts talk about products and packages - how do they think about them? And about the processes involved in working with them?
When they create a package, do they really think to themselves "I must define products with this package", or do they think "I'll setup a package, and then link a few products to it" - if the latter, although it may on first blush feel like a package can't exist without products, notice the subtle implication in the timing - that the package can exist without products, because they expect to link products to it as a second step.
Given that, you might model the link as a completely independent aggregate with a single entity as the root, e.g. PackageProduct (or better yet, some term your domain experts use to define the assocation) and simply create new instances of this aggregate when a product is linked to a package. This entity would have a PackageId and a ProductId on it.
However, if there are business rules, e.g. a Package can only have one product of a given type, or at most 5 products, then make the PackageProduct entity an entity within the Package aggregate, which has Package as the aggregate root. The PackageProduct would have a reference to the Package and a property of the ProductId. See below for some terminology clarification.
Entities vs Aggregates
Based on your question, it seems there might be some confusion about terminology. In DDD, we have:
Entities:
Have an identity that outlasts any given property
Has a mutable state
Generally, modelling business processes is all about working out how to mutate the state of entities
Aggregate
A group of entities over which invariants must be enforced
invariants are business rules that MUST hold at all times
A single entity is always nominated as the 'aggregate root'
Other entities can only refer to the aggregate by the root
When modelling a business process in order to mutate state, the aggregate is the boundary within which the states of all entities must be consistent with the invariants.
Outside the aggregate boundary, other entities may get updated asynchronously - aiming for eventual consistency
Domain Service
A service that contains business logic that doesn't belong in a single entity
It is generally not just a wrapper around a piece of infrastructure
See https://lostechies.com/jimmybogard/2008/05/21/entities-value-objects-aggregates-and-roots/ for more info.
Read vs Write Operations
The problem comes in when I'm needing to get the products belonging to a package
This sounds a lot like it might be in order to support a UI or a report? In which case - don't stress about the entity model. The entity model is there to ensure the business rules hold while users are trying to modify the state of the system. When doing a read operation, there is no need to modify the state, so you can bypass the model. Define a query that projects your data store onto a DTO and tailor the the projection to suite the needs of the UI or report.
The problem comes in when I'm needing to get the products belonging to a package (Note: the package is customisable, this means the products belonging to the package could be different the next time round).
This sounds like a query. It often helps to separate the modelling of commands (things that can alter your domain model) and queries.
I'm facing to an issue with Doctrine relation and DDD.
I already searched a lot but I didn't find a suitable answer.
Let's take a simple example:
I have an aggregate Category and an aggregate Product.
I would like to have a ManyToOne relation between Product and Category.
Unfortunately Doctrine makes me add an attribute $category in my Product. But as Vaughn Vernon said, aggregate should reference to other aggregate by his identity, not by the aggregate itself.
Moreover even if I do this, Doctrine overwrites category_id to null if I don't set $category.
My only solution, at this moment, it's to add category_id field in mapping definition and add foreign key by myself.
Is there any other solution ?
I suspect you maybe trying to use the wrong tool for the job. Doctrine 2 is an Object Relational Manager hence it focuses on objects. If you read through the docs you won't find very much on domain driven design.
Given that Doctrine focuses on objects then:
$category = $product->getCategory();
Makes perfect sense. It also maps nicely onto how sql is designed to work.
If you really want a property Product::CategoryId then go ahead and add it. The latest Doctrine even has limited support for value objects.
But if you then want to somehow access the actual category object then you will need to add in your own query somehow. Kind of makes the orm code pretty much useless as you would be handing your own relations. Maybe drop down to pdo or the database access layer.
I have seen a few articles trying to do what you want but they barely manage the simplest cases and are impractical for any kind of production scenarios. Especially since DDD implies complex business logic.
I just would add a property categoryId to Product and that's it.
So I can't navigate from Product to Category directly, but instead I would need the CategoryRepository to fetch the respective category object, if I need it.
I lose the lazy loading convenience, but the aggregates are separated clean and nice.
I'm currently developing a simple web application with Symfony 2 that process orders with products and lines of orders. Actually I have three Doctrine entities (Product, Line and Order). I will work with the data of these models and I need filter by date, add, delete, list, and make some administrative things with all the data.
As far I know this will be Service territory and is best practice to keep the controller away from doing this.
My question really is if I need to create ONE class with the methods that I need for all operations and then call them from the Controller, or create one Service class for each Doctrine Model (OrderManager, LineManager...) or orient more to task specific (RecountTotal, FilterDate...) But with the last method I think that each Service will have only one method inside.
Which is the best practice for this?
You are totally correct in stating this is NOT a job for controller.
It's totally fine to use only one manager to contain all your data access methods.
class BaseManager { // Name it as you like
...
}
If you find yourself having very similar methods for different entities, you may want to split into different managers (OrderManager, LineManager, ProductManager) and have them extend a common BaseManager to reduce code duplication.
Additional classes for filters and counting should not be necessary unless you have some advanced requirements.
Ok, I couldn't insert the overview image, but I'm required to create a PHP app for my studies, it must allow student to register, and the administrator to edit course and student info.
We are not required to code it in an OOP style, but since its the best programming practice to code in OOP, why not learn OOP from the beginning.
I'm a beginner but I know the basics about OOP, classes, inheritance, setters and getters and all that cool lingo, but I'm struggling to decide which parts of this app should be objects, should I make course and student classes or add, edit and delete classes? Any advice on how to approach and visualize such a problem would be appreciated.
Very roughly: This is how I would do it:
Store your data in SQL or XML. You will need two SQL tables, one for Students and one for Courses. You can use one XML file containing all the data, or you can use two files (which I recommend).
Create a class called, for example, dataItem with a property like '$arr_fields' corresponding to a single data record (a single row in a SQL table, or an XML record).
The dataItem class should have the following methods (all public):
loadFromSQL() (or loadFromXML())
saveToSQL() (or saveToXML())
add(), edit() and delete()
a view() method using HTML
These methods are obviously used to read and write data between the SQL/XML data and $arr_fields of the class, and to display the data in $arr_fields. The keys of $arr_fields are the SQL column names (or XML tag or attribute names) for the specific SQL table.
Try not to call loadFromSQL() or saveToSQL() in your constructor or in any of the other methods which are used to modify only the class data. Keep these actions separate. EDIT: This is a personal preference which helps me to keep track of the state of my objects.
Create Student and Course classes that extends the dataItem class.
You can override methods, for instance the view() method, inside your extended classes if you need to.
Then you can call the methods in Students and Courses from an Admin object (like rcdmk suggested) or maybe from StudentFolder and CourseFolder classes whose view() method contains buttons for the actions that need to be performed. (Let StudentFolder and CourseFolder extend a Folder class that you create).
UPDATE:
For example: If your primary key in a SQL table is id, then dataItem's loadFromSQL($id, $tablename) should set $arr_fields so that its keys are the column names and it's values are the values from the row whose primary value is equal to $id.
In Students, you can then override loadFromSQL() as follows:
class Students extends dataItem {
// other attributes
public function loadFromSQL($id) {
parent::loadFromSQL($id, "Students");
}
}
EDIT: On reconsideration, it might be better to set $arr_fields["id"] = $id and also set $tablename with the constructor for dataItem - then you never have to override loadFromSQL() or specify parameters for it. loadFromSQL() should then load the record if it exists. saveToSQL() should save $arr_fields in SQL if $arr_fields["id"] is set and create a new record if it is not set. Anyway, you must find a consistent way of interacting with the data which works for you, these are just possibilities.
However, if you are not experienced with OOP and SQL or XML, you might be opening a can of worms for yourself and it might be better to just do your assignment using functions only and php arrays for your data. Unless you have some time to learn...
From a simple perspective:
Abstract the main objects as classes and use methods for actions of this objects:
Student (object) are deleted (action) by the Admin (object), so
Admin class will have a deleteStudent method, because Admin deletes Students.
Another aprouch is to concentrate all Student related actions in the Student class:
Student class will have a public delete method that Admin can use.
Anyone that think this in better ways of explanation can edit this wiki.
Think about which aspects of your system are actually objects, you know, something you can do something with. The methods are what you do to the objects. So, you're on the right track with course and student classes, and add, edit, and delete would be methods of those classes.
But don't get too bogged down with it. If it's not your core assignment objective, you could quickly get in over your head by trying to do everything exactly the right way. If you can formulate a clear way to get to where you need to go, then go for it, if it seems confusing, back off it a little and learn some more.
You say that you know the basis of OOP, however you ask whether you should create Course, Student classes OR Add, Delete, Edit classes. Well maybe there are other practices, but I guess the most popular one and the only I am aware of is to use nouns as classes and verbs as their methods. Hence, intuitively there is something wrong with class "Add" or "Edit". What I would have done if I were were, is to think of all "entities" that might be considered an object - like Student, Course, Lecturer, Class (Room) and depending on how advanced your model should be you can add more like Building etc. Then try to implement basic things like creating new student, registering for a course, associating teacher with a course etc. Once you have it in place and IT IS WORKING you might want to add advanced things, like inheritance. For example you might want to say, that both Teacher and Student are a Person so you might want to create such abstract class and use inheritance.
I'm learning my ways with Symfony2 while building a small eshop for a family-run wine importer. Slowly I'm gaining understanding of the Symfony2 concept but while moving on to building a shopping cart, I'm not quite sure what would be the correct (at least according to the Sf2 standards) way to implement this.
What I'm looking for is a simple Basket storing BasketItems and their amount in sessions and later use this data in the checkout. Now before I go and glue this somehow together, I'd like to hear an advice on how this should be done and separated correctly.
So far, I've created the two as entities and now I'm not sure if I should put the logic directly in the Entity classes or Repositories or where preferably?
I hope this is not a too wide question. I'm well aware of the fact that a truly robust shopping cart implementation is no small job.
On a sidenote, are there already some proven and working shopping baskets for Symfony2 around?
The general rule when creating Entities and Repositories is that an Entity class should contain the logic needed to operate on a single Entity, and Repository classes contain the logic needed to operate on groups of Entities.
A simple example:
If you wanted to convert the price of an item from dollars to euros, you would have BasketItem::convertCurrencyTo($currencyType). This is code that operates on a single Entity.
If you wanted to find all BasketItems whose price is between $10 and $20, you would use BasketItemRepository::findByPriceRange($min, $max). This is code that operates on a group of Entities.
IMO, things can get a little confusing when dealing with Entities that have a one-to-many or many-to-many relationship. I would imagine that one Basket has many BasketItems, and one User has one Basket. Therefore, I think it's reasonable to assume that in order to fetch the BasketItems a User is interested in, you could do something like this:
$user->getBasket()->getBasketItems().
Note that there is no Repository being used in this example because it's a very basic query. If you needed to do something more specific, like find the BasketItems a User is interested in that happen to be on sale, you could use something like BasketItemRepository::findWhereOnSaleForBasket($BasketId). There's nothing stopping you from adding a similar method directly to the User or Basket classes, but I feel that because your query's main 'target' is a BasketItem, it belongs in that Entity's Repository class.
You mention that implementing a shopping cart is no small task, and you're right. But the questions you're asking aren't really limited to Symfony2 (in this case it's more about Doctrine 2), so I think it might be helpful if you check out other open source shopping carts and study what they're doing. I think the only impact Symfony2 would really have is forcing you to decide how to split up your code within bundles.
Hope this helps!
There is an ecommerce bundle available called Vespolina which also provides a cart.