MasoniteFramework / core

Main pip package location for Masonite
http://masoniteproject.com
MIT License
85 stars 52 forks source link

Implement some form of HMVC into Masonite #107

Closed josephmancuso closed 6 years ago

josephmancuso commented 6 years ago

So after a job interview, they quickly went over what HMVC actually is and I thought it was actually awesome. We should implement some form of it in Masonite.

This will target Masonite 2.0 I think. Possibly 1.6.4 or 5 but probably 2

Goal

So the goal of HMVC seems basically to be to call a controller from another controller (which will in turn return a view). This allows things to be "widgetized"

What it solves

So correct me if I'm wrong but I believe it solves the template issues:

index.html

{% block content %}
    {% include 'sidebar.html' %}
    {{ user.name }}
{% endblock %}

Now the sidebar.html, for simplicity sake, the template might look something like:

{{ app.name }}

This means that whenever you call a controller that returns index.html, it also includes the sidebar.html which in turn requires that app variable:

So normally the controller will look like:

def show(self):
    return view('index', {'user': request().user'})

but now because the sidebar is there we need to do something like:

def show(self, Application):
    return view('index', {'user': request().user', 'app': Application})

and I need to do this for every single template that requires a sidebar.

Solution 1 - View Composers or View Sharing

So one solution is to actually create a view composer or a view share.

def boot(self, Application):
    View.share({'app': Application'})
    # or
    View.compose(['index', 'about'], {'app': Application'})

which will actually share that variable. but what if we need something way more complex than a simple variable. What if we need a huge amount of logic? Then a view compose or view share won't work. What we need is something like an entire controller worth of logic.

Solution 2 - Calling Controllers in Controllers

Maybe we should implement something like calling controllers from controllers?

def show(self):
    sidebar = self.controller('SidebarController@sidebar')
    return view('index', {'user': request().user', 'sidebar': sidebar})
{% block content %}
    {{ sidebar }}
{% endblock %}

@mapeveri @aisola What do you think? Any third or fourth options here?

Solution 3 - loading logic right into the view

Another solution I just thought of will be to actually "load the view". I think this is the solution that CodeIgniter takes.

What we can do here is something like:

def show(self):
    self.load_view('SidebarController@sidebar', view='index')
    # or
    self.load.view('SidebarController@sidebar', view='index')
    return view('index', {'user': request().user')

which will actually just create a view composer in the backend. We'll need to instruct it which view to actually compose for though.

or we can add all this logic to the view class and run:

def show(self):
    return view('index', {'user': request().user').widgets({'sidebar': 'SidebarController@sidebar'})

If possible, this should be a single Service Provider implementation. Even if it means adding logic to the core class to get it done.

IF we need to we can extend the View class like the documentation below:

https://docs.masoniteproject.com/~/edit/primary/advanced/extending-classes

I haven't really found a use for that but it's worth looking into. Kind of added that when I was bored

mapeveri commented 6 years ago

HMVC is thinking to modularize an app, I like it, but it is not the best for me, if one wants to modularize an app, why not create the modules with craft and ready?. For example:

craft controller module/controller
craft model module/model

What do you think?

josephmancuso commented 6 years ago

So that command would actually just create a separate directory with models and controllers right?

mapeveri commented 6 years ago

Exactly!

josephmancuso commented 6 years ago

I'll look into this. I think this is what most controllers are going to end up being but I think there is another step involved, right? For example how does that solve the template issue?

mapeveri commented 6 years ago

When a controller is created, the templates are created. Or do you mean another topic?

josephmancuso commented 6 years ago

Ok so heres the whole problem that the interviewer explained to me:

We have a checkout page. Now in the sidebar, the cart is automatically updated everytime an option changes (such as changing the quantity, color, price etc), The entire cart should be updated. Now in the sidebar, there should be this sidebar widget that re renders every time the cart is updated.

This sidebar widget requires a lot of logic involved such as rules, shipping requirements, etc.

We should be able to load all of this somewhere. If we include a view with Jinja then all logic needs to be done in each controller.

All this basically does is make controllers smaller.

Now if you don't understand I don't blame you. If this was explained to me last week then I probably wouldn't have understood it

josephmancuso commented 6 years ago

maybe this picture makes sense: https://s3.amazonaws.com/nettuts/681_hvmc/images/HMVC-structure.png

josephmancuso commented 6 years ago

basically a controller calls another controller which returns a view

josephmancuso commented 6 years ago

and we can inject that entire view the controller returns into the current view we are working with. I'm wondering if this is super useful and let's things be more reusable

josephmancuso commented 6 years ago

Taylor Otwell actually didn't like this design when building Laravel because he said it causes bad design decisions but almost every company uses CodeIgniter over Laravel because of this HMVC architecture

josephmancuso commented 6 years ago

The HMVC is actually an extension for CodeIgniter so it doesn't come out of the box. I say if possible this should be a package

mapeveri commented 6 years ago

I understand what you say. In rails they do not use HMVC either, and Django solves it with the modules. With what I say, you could solve what you say. And have a utils.py file for common module logic.

josephmancuso commented 6 years ago

hmm after watching some tutorials on how CodeIgniter does HMVC, I hate it lol. I like the separations of concerns approach that Laravel uses. With the self.load stuff, Code igniter actually outputs it right then and there. This basically mixes views and controller methods too much.

If we are going to go with this approach then I would like load views into views to keep the separation of concerns and loading controllers from controllers. What CodeIgniter does is basically loads a view into the controllers which is shitty I think.

josephmancuso commented 6 years ago

This might be a shitty approach and I can probably close the issue with @aisola input but apparently Taylor Otwell has a book that explains why HMVC is bad architecture. I'm going to give it a read to see the opposite side of the argument.

mapeveri commented 6 years ago

Codeigniter is horrible lol :)

For me it is not bad HMVC, but it can be solved with modules like I say or other better approaches.

Ok, then tell us what the book says ;)

josephmancuso commented 6 years ago

nvm its $30. I was hoping it was like 5 bucks lol. I'll just close this. I think you are right. There are better ways to solve this than HMVC 👍 . and yeah code igniter looks awful