I think I understand the concept of HMVC after reading this question and answer https://softwareengineering.stackexchange.com/questions/220480/hmvc-and-database-connections; an extract from an answer is below:
Let's assume you want to have a view that enables a user to make a
comment to a blog post. You would have fields for name, e-mail, title
and comment, but you also want to have a field country displayed as a
dropdown. In the action that displays this view you would make a
database query that loads the countries and then populate that
dropdown. Which is ok, but it forces you to duplicate the query and
the view required to display the countries if you need it in another
part of your application. A better approach would be to create
separate controller for countries with an action that returns a view
with the dropdown and then render that action whenever you need to
show a list of countries.
What I cannot wrap my head around is that if I can internally request a controller/model/view which just displays a widget (e.g. a country select box), doesn't that mean that by accessing that url from a browser will also just show that view?
How is this managed in HMVC, are routes defined as internal/external only, so matching an internal route with an external request would show a 404 page?
Is this generally how it is done and is the HMVC description/definition above satisfiable with the general use case of it in most web applications?
Showing the output of a sub-request in the browser shouldn't be a problem, so I wouldn't bother, especially that those URLs are not known by the user and it's safe to output the widgets separately.
Despite the above, you could, as #deceze mentionned, not attach those controllers to any routes. If you have a "default" route (matching all requests), then you would have to disable it.
Related
I'm a beginner in Symfony and am using v5.0.11 as part of a work project (inb4: as its a work for the company I'm employed by, I have little control over updating the version).
My issue is the following: I have a controller (that extends the "CommonController") file that contains different routes leading to different URLs, supposed to be triggered by a multi-field form's button. The first route in this controller (except for the one leading to the main page) is "#Route: /global/search/" related to a "globalSearch funtion". The following routes (eg #Route: /global/product_code/{product_code}) are defined further down the document, indented at the same level and are located outside of that first "globalSearch" function.
Depending on the form's fields fill beforehand; it should send the user to a specific URL related to said field (eg: if I fill the "product code" category, it should send me to an address like "/global/product_code/{product_code}".
However, when I fill any field and press the button, it still sends me to the general search URL ("global/search") instead of the one I routed above '"global/product_code" for example.
Do you have any idea why that is ? I've gone down Symfony & Doctrine docs but couldn't find any answer for it; and from what I read I can't prioritize routes as I'm in 5.0.11.
Thanks in advance for any help.
NB: as my work concerns a sector and company bound by secret to my country's governement & multiple firms; I can't share the code online to 3rd parties; tho I will try to bring as many infos about the code as needed.
Without some code samples it would be hard to identify the problem and whether it's a problem at all.
But here are some ideas, how to narrow the problem down.
First:
However, when I fill any field and press the button, it still sends me to the general search URL ("global/search") instead of the one I routed above '"global/product_code" for example.
If you're using symfony forms to create and/or render forms, it's probably <form action=""> attribute. I assume it either blank (which will submit it to the same URL. In your case it's /global/search) or it is set to a specific route. (e.g /global/search )
In any case, you should consider #Cerads suggestion to check all available routes to find out more and find out which controller action is responsible for /global/product_code/{product_code}. If there are some routes matching this pattern, they have to have a "route name" so you could search in the whole project for that route name.
bin/console debug:router or bin/console debug:router | grep global
Second:
Depending on the form's fields fill beforehand; it should send the user to a specific URL related to
To somehow change submit-url by users-input requires JavaScript. Whether you send a single field value via AJAX or just "replace" form's action attribute, you have to check related JavaScript code.
I am very new to MVC.
I just finished reading a book and am trying to implement what I have learned, but I am stuck. In the book and some other explanations I have read online, it's always one controller for one view, like navigation view being controlled by its controller, login form controlled by its own controller.
But I have a header with couple of navigation links, and a search form. Do I separate navigation from searching or assume searching is part of navigation and just control them all in one controller?
First of all, you seem to have the impression that "template" and "view" is the same thing. It's wrong. A properly done view will juggle multiple templates and choose which combination to use based on the current state of the model layer.
As for your navigation & search thing ... well ... it's confusing. Each link in navigation would point to either a different controller entirely or a different methods of controller. And search query would definitely be submitted to a separate controller/view pair.
The navigation+search is just a template, that is used in multiple views as part of the complete response.
I have a situation where I need to create a shortcut for a specific filter in a Joomla component.
The problem is that I cannot unset it, as I do not know if Joomla sets the form fields to its own session handler, request handler or some kind of custom handler. There also does not appear to be any documentation on this specific case.
The full situation is that I have a link that will auto filter in the same view as another link (in the components sidebar). One view will be just a specific filter and the other is standard. So I need it when you click into the filtered view it will reset the current filters to make sure everything displays as it should, and vice-versa so clicking back will again reset the filters.
I have tried a number of approaches for this, and although I can consistently force it to filter but it will not reset the form when I re-enter the last page with any technique I have tried so far and of course I want to avoid bypassing Joomla's default functions.
if(JRequest::getVar('filter_group_id',false)==10){
JRequest::setVar('last_filter',true);
EthicstoolHelper::addSubmenu('supervisors');
}else{
if(JRequest::getVar('last_filter',false)===true){
JRequest::setVar('last_filter',false);
JRequest::setVar('filter_group_id',false)
}
EthicstoolHelper::addSubmenu('users');
}
This is the most recent think I have tried, as you can see I try to reset the value to false in a hope that Joomla will read it as not being set, as JRequest has no built in unset method.
I don't have enough rep to comment yet, so I'm guessing a bit as to what the problem could be. Assuming that you are using a model to set the state of the filters, you can look at overriding the populateState method.
Another options is to fiddle with the context property in the model. For example, you could change the context if you have your special filters enabled if you are using things like $app->getUserStateFromRequest(). If you can post a bit more information about the design of your component (controllers and models), I can help more.
I would like to ask about optimal approach to creation of reusable content blocks in CakePHP 1.3.
Under reusable content blocks I mean partial views used to build up the page. E.g. in an eshop application the minicart summary can be considered as reusable content block - it is displayed on each page header.
In CakePHP 1.3 there are two posibilities (and both have serious disadvantages):
Creation of element /app/plugins/myeshop/elements/minicart.ctp and use $this->element('minicart) to load this reusable content e.g. in header. The disadvantage is that this beaks business of Cart entity into many places. Minicart is only some representation of Cart entity whose views are treated by controller /app/plugins/myeshop/controllers/carts_controller.php. So why to put it out of controller and keep it in element? Elements are good to keep some general reusable contents e.g. header, footer, interactive_map, ... something which is not related to application business objects/entities.
Creation of method CartsController::minicart() with corresponding view and use $this->requestAction('/myeshop/carts/minicart') to load this reusable content e.g. in header. The advantage is that now all business and views of Cart entity is treated by CartsController. There are no side-logic and side-views hidden in elements.
The disadvantage of this approach is apparent - use of requestAction() costs a lot of time.
At this point I must say that I totally agree that requestAction() must be used very carefully. To use it to call some procedural/busines logic of controller is bad application design. Such kind of logic should not be placed in controller but in model. Still, IMHO, it is legitimate to call controller action to get a partial/reusable content (view) and keep the entity business on one place.
Does the CakePHP have some optimal solution for this?
I highly suggest going the route of elements/requestActions.
Here's a great article by CakePHP Master Mark Story: "How using requestAction increased performance on my site"
We've built many large, highly-traffic sites using CakePHP and use requestActions all over, and our sites load extremely fast.
If possible I would create it as an element. I assume your controller will calculate the contents of the mini cart and the view will display it?
If so its fine to use an element. You certainly dont want additional HTTP requests as you state.
However, the element should only display the content, it should perform any business logic. You need to incldue this in a Controller or Component and set the necessary elements for the view.
If you only need it on certain pages, you can create a new layout.ctp file that includes the mini cart and then use this layout on those pages.
If this is just about displaying the content of your cart on every page I recommend this solution: Write the cart into session, if the user is not logged in and logs in sync it with the database. If a user comes back and logs in restore the session from the saved cart.
In your AppController::beforeFilter() read and set the session data to the view or if it is just read, read it using the session helper in your minicart element. You won't have additional requestAction() calls by this or any additional db queries.
I've implemented my cart like this, you can take a look at it here. https://github.com/burzum/cart a working example app is also available https://github.com/burzum/CartSampleApp
I'm working on building up an interface that I want to function as a "tabbed browsing" sort of function. Each of these tabs has already been written as an action and the tabbed interface works fine as links to the individual tabs. I decided to try writing the "index" page for this controller - putting the content of all the tabs into hidden divs and swapping between them with jQuery, but once I started to use the action view helper - I ran into a lot of people saying that its bad practice. (see this article)
Some of these actions build up forms - grab some data from the model, etc to display. I want each of the actions to continue to function on their own (some parse forms as well).
Browsing to /item should give you the tabbed menu, plus all of the div's contents in a hidden tag - where /item/tab2 is a specific action (form submit for instance).
Another complication/caveat - Some of the actions will throw Access Exceptions if the user doesn't have access to that "tab". I'd prefer not to build access checking into the system twice (thus showing a tab with empty content).
I'm just trying to figure out what the best practice is to handle this sort of thing, and I thought that the action helper might be it. If I try to use View Helpers - I start wondering if that is the right place to assemble a Zend_Form.
Does anyone have any suggestions on the "proper" way to work around not using the Zend_View_Helper_Action ?
The Correct way to work around the action view helper, as I stated in the article you cited, is to create partials which access the model directly to fetch the data they need. This can be through a view helper (you make this yourself ;)) if this would involve a lot of logic in your view.
The action view helper is plagued with more than just performance issues, but also creates horrendous debugging nightmares, and if you need it, then your application is probably not following MVC, and therefore, you are using the controller for reuse, instead of the model, which is the patterns intention.
You can render partials from within your layout or current actions view with the render or partial methods of the view object.
If you have multiple actions to deal with multiple possible posts from your tabs, then you should set all of these actions to render the same view script, which will then render all of the tabs with data direct from the model.
If you're not generating the tab/tab panes from existing markup, and you're loading the content on demand, then you simply must check whether the user has permission to access the tab before displaying the tab itself, and again when attempting to load the tab's content.
Checking whether the user has these access permissions should be an acceptable mode of operation and should not be expensive to perform.
If these actions produce content that works in some standalone page, in addition to the tabs, then the Action view helper is the corrent way to proceed. Simply perform the same ACL (or other) check performed in the action when generating the tab.
I'm not entirely sure what your exact problem is, however you can disable the layout:
$this->_helper->layout->disableLayout();
Then the requested Action will just display it's view script, which you can load into the tab.
Any authorisation code you have will function as normal and you can display the requested view script for the Action, or not depending on if they have access.
You can catch any access exceptions by using a try/catch block:
try { // action throwing exceptions } catch (Exception $e) { // catch silently }