Backbone Marionette - Router & Controller - marionette

Let say if my apps have 2 models and 2 collections
Author (Model) | AuthorList (Collection)
Book (Model) | BookList (Collection)
Should I create a router and controller for Author
and create another router and controller for Book ?
or should I just create only 1 router and controller for both Author and Book?
//Router for Author
appRoutes {
"authors/:id":"showAuthor"
"authors": "showAuthorList"
...
}
//Router for Book
appRoutes {
"books/:id":"showBook"
"books": "showBookList"
...
}
Thanks

As usual, the answer is: "it depends". Both will work, and the solution you choose will come down to preference.
However, for larger scale applications, it makes a lot of sense to have separate routing controllers (and to sub-divide the app into smaller bits). You can see an example of the multiple routers in the code accompanying my Marionette book.

Related

Laravel 3 tables on belongsToMany relation

Based on the official Laravel documentation I found that :
$books = App\Book::with('author.contacts')->get();
In this case, imagine we have a structure like this :
books
books_authors
authors
contacts
books_authors_contacts
That's just an hypotetic case but I would like some more information : what about if I would like to retrieve all authors contacts for this specific book, imagining that for a specific book multiples authors could have multiple contacts (such contacts are linked through both authors and books as the entity books_authors_contacts says)
Is it possible to retrieve it through Laravel with eager loading with a belongsToMany relation?
By using the example below, it would just retrieve all of the contacts of an author no matter the book is.
Thanks you in advance!
There is tricks to gain this functionality in a very complex fashion, see this post. In a more practical sense, when these cases arrive in a professional environment, you often end up doing a method that aggregates this data. This can be done in multiple ways, this is an approach i feel is fairly easy and readable.
public class Book
{
public function contacts()
{
$contacts = new Collection();
$this->authors->each(function(Author $author) use($contacts) {
$contacts->concat($author->contacts);
})
return $contacts;
}
}
Offcourse for the eager loading, you have to remember to include the whole structure. For more Laravel approach contacts can be made as a Eloquent Mutator.
$book = App\Book::with('authors.contacts')->find(1);
$contacts = $book->authors();

Has-Many-Through Relations

I have done a lot of research in Google about this. There are not a good examples with using this type of relation between models.
Can somebody share own sample using Has-Many-Through Relations in Laravel?
Let's take a sample of a social network where you have User, their Friends and their friends' Photos. 3 models. yep a friend is just a normal user but for this example, a Friend would be a separate Model.
1- A user has friends
public function friends() {
return $this->hasMany(Friend::class);
}
2 - A friend has photos
public function photos() {
return $this->hasMany(Photo::class);
}
3 - You are the admin. you have many users, including John. John has a lot a friends. So sometimes, you want to see John's friends photos, maybe those where they tag him. So in user you define the relationship
public function friendsPhotos() {
return $this->hasManyThrough(Friend::class, Photo::class); //could add a scope here for picture with tags only.
}
Not problably the best example. But it shows how you can see all John's friends pictures by just doing
$john = User::where('email', 'john#email.com')->first();
$john->friendsPhotos();
If the example doesnt suit you well, now think of a bank looking for their best salesperson in a specific Branch. A Branch hasMany Salesperson, and each Salesperson hasMany Customers they deal with.
In Branch model, you define
public function customers() {
return $this->hasManyThrough(Salesperson::class, Customer::class);
}
I hope this helps a little bit.
Database tables for the banking system
1- Branch
id
name
...
2 - Salesperson
id
branch_id
firstname
...
3 - Customer
id
salesperson_id
firstname
...

Relationship mapping with NeoEloquent

I'm tinkering with Neo4j 2.3.0 and Laravel 5.1 using NeoEloquent. I've set up a couple of dummy nodes and some relationships between them:
image of Neo4j model - apologies, I cannot insert images directly yet :)
So articles can use a template. The inverse of this relationship is that a template is used by an article.
I've set up the classes like so:
Class Template extends Model
{
public function articles()
{
return $this->hasMany('App\Article', 'USED_BY');
}
}
And:
Class Article extends Model
{
public function template()
{
return $this->belongsTo('App\Template', 'USES');
}
}
So far, so good, I think.
I have a page where I am wanting to eventually list all of the articles in the system, along with some useful metadata, like the template each ones uses. For this, I have set something up in the controller:
$articles = array();
foreach (Article::with('template')->get() as $article) {
array_push($articles, $article);
}
return $articles;
Not the most elegant, but it should return the data for both the article and it's associated template. However:
[{"content":"Some test content","title":"Test Article","id":28,"template":null},{"content":"Some flibble content","title":"Flibble","id":31,"template":null}]
So the question is - why is this returning null?
More interestingly, if I set up the relationship to the same thing in BOTH directions, it returns the values. i.e. if I change the USED_BY to USES, then the data is returned, but this doesn't make sense from an architectural point of view - a template does not 'use' an article.
So what am I missing?
More interestingly, if I set up the relationship to the same thing in BOTH directions, it returns the values.
That's correct, because this is how it operates. It is worth knowing that the relationship methods you have defined represent the relationship itself, which means for both models Template and Article to target the USED_BY relationship from any side it has to be the same in articles() and template.
The solution would be to use something like USES (or any notion you like) on both sides. This reference should help you make good decisions regarding your relationships.
On the other hand, if you still wish to have different relations on the sides then kindly note that in your model (image) both relationships are in outgoing direction. i.e. Fibble-[:USES]->Template and Template-[:USED_BY]->Fibble which means template() should be an outgoing relationship such as hasOne instead of belongsTo which is incoming.

Yes or no: Should models in MVC contain application logic?

Yesterday I had some discussion with one of our developers regarding MVC, more precisely about the role of the model component in MVC.
In my opinion, a model should just contain properties and almost no functionality so there are as few methods in model classes as possible.
My collegue though believes that models could and should have more than that and offer a lot more functionality.
Here is an example we argued about.
Example 1
Let's say we wanted to create a blog. A blog has articles and tags. Each article can have multiple tags and each tag can belong to multiple articles. So we have a m:n relation here.
In pseudocode it'd probably look something like this:
class Article{
public int id;
public String title;
public String content;
public Tag[] tags;
// Constructor
public void Article(id, title, content, tags){
this.id = id;
this.title = title;
this.content = content;
this.tags = tags;
}
}
class Tag{
public int id;
public String name;
// Constructor
public Tag(id, name){
this.id = id;
this.name = name;
}
}
Now, assume that we're working loose coupled here which means that it could happen that we have an instance of Article which has no Tags yet so we'll use an Ajax call (to our backend which has a database containing all the information) to get the tags that belong to our article.
Here comes the tricky part. I believe that getting the backend data via Ajax+JSON should be the controller's job using a dedicated class which deals with the ajax request using a parser:
class MyController{
private void whatever(articleID){
Article article = (Article) ContentParser.get(articleID, ContentType.ARTICLE);
doSomethingWith(article);
}
}
public abstract class ContentParser{
public static Object get(int id, ContentType type){
String json = AjaxUtil.getContent(id, type.toString()); // Asks the backend to get the article via JSON
Article article = json2Article(json);
// Just in case
Tag[] tags = article.tags;
if (tags == null || tags.length <= 0){
json = AjaxUtil.getContent(article.id, ContentType.TAGS); // Gets all tags for this article from backend via ajax
tags = json2Tags(json);
article.tags = tags;
}
return article;
}
// Does funky magic and parses the JSON string. Then creates a new instance of Article
public static Article json2Article(String json){
/*
...
*/
return new Article(id, title, content, tags);
}
// Does funky magic and parses the JSON string. Then creates a new instance of Tag
public static Tag[] json2Tags(String json){
/*
...
*/
return tags;
}
}
Example 2
My collegue believes that this breaks with the idea of MVC, he suggests that the model should take care about this:
class Blog{
public int id;
public String title;
public Article[] articles;
// Constructor
public Blog(id, title, articles){
this.id = id;
this.title = title;
this.articles = articles;
}
public void getArticles(){
if (articles == null || articles.length <= 0){
String json = AjaxUtil.getContent(id, ContentType.ARTICLE); // Gets all articles for this blog from backend via ajax
articles = json2Articles(json);
}
return articles;
}
private Article[] json2Articles(String json){
/*
...
*/
return articles;
}
}
class Article{
public int id;
public String title;
public String content;
public Tag[] tags;
// Constructor
public Article(id, title, content, tags){
this.title = title;
this.content = content;
this.tags = tags;
}
public Tag[] getTags(){
if (tags == null || tags.length <= 0){
String json = AjaxUtil.getContent(id, ContentType.TAGS); // Gets all tags for this article from backend via ajax
tags = json2Tags;
}
return tags;
}
// Does funky magic and parses the JSON string. Then creates a new instance of Tag
private Tag[] json2Tags(String json){
/*
...
*/
return tags;
}
}
And outside of the model you'd do: blog.getArticles(); or article.getTags(); to get the tags without bothering with the ajax call.
However, as handy as this might be I believe that this approach breaks with MVC because at the end of the day all models will be full of methods that do various funky stuff and the controller and helper classes do almost nothing.
In my understanding of MVC, models should only contain properties and a minimum of "helper methods" inside. For example a model "Article" could offer a method getNumOfTags() but it shouldn't do any Ajax calls on its own.
So, which approach is correct?
Generally I try to keep controllers simple in terms of logic too. If business logic is required, it will go up to 'service layer' classes to handle it. This also saves repeating any code/logic too, which ultimately makes the whole project more maintainable if business logic was to change. I just keep models purely as entity objects.
I think the answer above sums it up nicely though, it is easy to over engineer a project based on design patterns: Go with whatever works for you and is most maintainable/efficient.
You should stop treating "model" in MVC like some class. Model is not a class or object. Model is a layer (in modern MVC, there has been some evolutions since the inception of concept). What people tend to call "models" are actually domain object (I blame Rails for this mass-stupidity).
The application logic (interaction between domain logic structures and storage abstraction) should be a part of model layer. To be more precise: it should be inside the Services.
The interaction between presentation layer (controllers, views, layouts, templates) and model layer should happen only through those services.
Application has no place in controllers. Controllers are structures of presentation layer, and they are responsible for handling user input. Please do not expoqbse deomain objects to it.
Correct? Either. They both compile, don't they?
Handy tricks are nice, why not use them were you can? That being said, as you've pointed out, you may get bloated models if you put all sorts of logic in them. Likewise, though, you can get bloated controllers when they do massive amounts in each action. There are ways to abstract elements out of either, if that's necessary too.
At the end of the day all design patterns are is guidelines. You shouldn't blindly follow any rule, just because someone else said it. Do what works for you, what you think gives clean, extensible code and hits whatever metrics you think make good code.
All that being said, for true idealistic MVC I would say that models should not have any external actions, they're data representations, nothing more. But feel free to disagree :-)
Your suggestion about the modules (without any business logic inside) sounds more like you talk about Value Objects. The suggestion of your college sounds more like Domain Objects.
In my opinion the concept which will be used depends on the framework which is used (that's the practical view, the more philosophical one is bellow). If framework is used it usually sets rules about how you should implement each component.
For example we can look at different MVC frameworks. In Flex's Cairngorm framework we have both. VO (Value objects) are primary used for bindings to the view, while the DO (Domain objects) hold the business logic. If we look at ASP.NET's MVC implementation there we have a model which contains at least the data (VO) but also some validation (if required). Let us look at a UI MV* framework - for example Backbone.js. Backbone's documentation says:
Models are the heart of any JavaScript application, containing the
interactive data as well as a large part of the logic surrounding it:
conversions, validations, computed properties, and access control.
If we look into the traditional MVC provided by Smalltalk we see that: "Model: manages the behavior and data of the application domain" so we have some behavior in it, not just plain data.
Let's think practically, if don't have any logic in the Model probably we should put all the application and business logic into the Controller.
Now let's focus on a concrete example. Imagine we have a model which is a Graph. We want to find the shortest path between two nodes in it. A good question is where to put the algorithm which finds the shortest path? It's a kind of business logic, right? If we look at the main benefits of MVC (code reuse, DRY etc.) we can see that if we want to reuse our model in the best possible way we should implement the shortest path inside it. The shortest path algorithm usually depends on the graph inner representation (or at least for best performance of the algorithm) but this representation is encapsulated into the model, unfortunately we cant reuse the full shortest path for matrix representation and list of neighbors so it's not a good idea to put it into the controller.
So as conclusion I can said that it depends on your needs (mostly). The traditional MVC purpose is to be used in the UI (inside GoF
The Model/View/Controller (MVC) triad of classes [first described by Krasner and Pope in >1988] is used to build user interfaces in Smalltalk-80.
)
now we use it in different areas - only UI, for web applications, etc. It cant be used in it's pure form because of that.
But anyway, in my opinion the best separation of concerns can be achieved by isolation of the business logic into the Model and the application logic into the Controller.
In short I believe the Model should just be data that will be sent to your View. It helps drive the MVC paradigm into other aspects of your application.
If you are tring not to break the MVC pattern your data should all be returned as a Business Model to your controller and unpacked into your ViewModel. Request the information server side and then send everything. If you need to make JSon requests then that should either be a Rest Service or calls to a Controller. Having these getTags and getArticles makes it very messy ... if your view is now deciding on which to call ... I cant understand why you dont have that information isnt available upfront. Using static methods is the same approach just a different angle.
I have found it best to have my controller actions call an injected service which does the magic and use the Models within the MVC web application to return the information. This makes things neater and further emphasisis the seperation of concern. Your Controller Actions then become very lean and its clear what they are doing.
I believe starting by treating the Model as completly dumb might go a long way in sorting some of these architectural problems I am seeing from this code.
Yes. It should. You are talking about Domain Driven Design.
https://en.wikipedia.org/wiki/Domain-driven_design
If you feel, you are not doing that then you are doing Anaemic Domain Model Design. that is an Anti Pattern.
I read through an article from Martin Flower on how bad the Anaemic Domain Design is. https://martinfowler.com/bliki/AnemicDomainModel.html

ASP.NET MVC 3 areas and DDD aggregate roots

I'm building a site and am considering using areas to cover a similar scenario to the one I'm about to describe.
I currently have a site with 4 sections, lets call these Create, Manage, Section 3 and Section 4
Create and Manage are actions on the domain object that I'm working with. The domain object has a number of collections of sub objects that relate to it. These need to be created and managed as well.
I am using Products as an example so as not to give anything away but it doesn't quite fit the same domain - so please don't say "Why don't you have a Products section"
My current implementation has a ManageController which has Actions like Categories, Category, ProductsForCategory
I'm thinking I need areas, however, some URLs will need to be scoped so I want
/Manage/Category/8/Products
/Manage/Category/8/Product/1
Is this possible using Areas? Do I need to set up new routing rules?
Would my CategoryController have 2 parameters on the action e.g.
public ActionResult Product(int categoryId, int productId)
{
//get category
var cat = GetCategory(categoryId);
//get product
var product = cat.Products.SingleOrDefault(x=>x.Id == productId);
if(product == null)
return RedirectToAction("Index","Manage");
return View(product);
}
Then I would have a routing rule that passed in the category id?
Is my thinking on this correct?
This is possible with Areas.. although it's my understanding that areas are mainly recommended for structuring your code into a meaningful folder structure to deal with large-ish MVC apps, whereas it looks like you want to use it for achieving nested routes?
To map your nested route to /Manage/Category/8/Product/1 you could create your "Manage" area, and then add a route like so:
context.MapRoute(null,
"Manage/{controller}/{categoryId}/{action}/{id}",
new
{
action = "Product",
id = "1",
categoryId = "2"
});
You then create an action method to accept those params:
public ActionResult Product(string categoryId, string id)
However, your question talks about aggregate DDD roots, so I suspect I've only answered part of the question?

Resources