Imagine I have a form (Page1.cshtml) with 1 link (LinkBrands). I also have a controller for Page1 (Page1Controller) and one for brands (BrandController). When the user clicks the link what is better to do:
LinkBrands-->Page1Controller-->BrandController (Page1Controller's action will redirect to BrandController)
OR
LinkBrands-->BrandController
Not sure what route is better. Any suggestions?
Usually you don't have a single controller per view. You would use multiple views or partial views all calling actions on the same related controller. I assume Brand is a separate entity from whatever else Page1 is trying to display, therefore it should probably use the BrandController directly but since there really isn't enough information to go on with your example as to what page1's function is I couldn't say what you are trying to relate.
If you need to capture information from the brand link as it relates to page1 then sure have it collect that in page1controller first before redirecting to brandcontroller to display a new view.
What does your Page1Controller do?? It seems as though you are defeating the purpose of the Model-View-Controller architecture and trying to form it back to the WebForms method with code-behind.
So without seeing what exactly your controllers are doing, I'd say your second option is best.
It all depends.
If you have to execute any logic in Page1Controller (saving data for instance) before displaying the second page, then you need to go by Page1Controller, and then go to BrandController:
LinkBrands-->Page1Controller-->BrandController
In case you just need to redirected to the second page (you do not need anything from Page1Controller, you do not need it to perform any action, and you can create a the model for second page in BrandController) then go with the second option:
LinkBrands-->BrandController
Hope this helps.
Related
I'm a developer and I am very confident with MVC pattern and have already developed a lot of webapp from scratch using php framework like symfony or yii.
I'm a little bit confused about joomla mvc and terminology and after googling a lot, read joomla book extensions guide, read on joomla website my doubt are still there.
What is confusing for me is the component mvc structure and how I have to set up "my way of think" about joomla mvc, for doing the things in the joomla way.
In particular I am used to reasoning in terms of controller/action (like in symfony and yii framework)
So the final list of all my webapp url will be
controller1/action1
controller1/action2
controller1/action3
controller2/action1
controller2/action2
Each controller's action will decide what view to render and what layout to use for showing the view.
In particular in these frameworks, the definition of a layout is exactly the mean of a layout. And the view is the "core part" of the page.
So I can have a view with a list of users and I can put this view inside a mobile layout or a desktop layout, or to build a view for mobile and put it only in the mobile layout and so on.
The final result about directory structure in my webapp is something similar to the following:
controllers/
controller1
controller2
controller3
models/
modelForTableA
modelForTableB
views/
controller1/
viewForAction1
viewForAction2
layouts/
mobileLayout.php
desktopLayout.php
and for me is very clear to understand.
So finally my questions are:
how would be the directory structure in joomla?
what are in joomla the definition of view, layout and task?
I need to clarify that I do not need an explaination about MVC works in general, but if I would achieve the same result as before, how I have to organize my code and my work?
Suppose that I want to build a component with the following "url"
userController/addUser
userController/editUser
userController/listUsers
userController/viewUserDetail
anotherController/addOperation
anotherController/editOperation
anotherController/myNonCrudOperation
Thank you very much
Routing in Joomla is slightly different. The SEF URLs are built from menu items, which in turn point to a View/Layout combination.
This turns things around: a controller is not bound to a specific View/Layout.
Let's make an example of the flow with the addUser functionality you mentioned as an example; I'll be referring to these files (but you'll have plenty more):
/controllers/user.php
/models/user.php
/views/useradd/view.html.php
/views/useradd/tmpl/default.php
/views/useradd/tmpl/default.xml
/controller.php
/router.php
As you can see the layouts are inside each view's tmpl folder.
router.php
Let's start from this last file: router.php defines our custom SEF rules so, after Joomla passes the call to our component (usually with the params
?option=com_componentname) we can takeover and interpret the URL as we wish. It is a bit hard to get started with but does provide the most flexibility and power. We don't really need to implement it at all for this simple example: so back to our registration now.
First step: show the "new user" form.
You would typically bind this to a menu item, pointing to the /views/useradd/tmpl/default.php; the /views/useradd/tmpl/default.xml contains the definition of the layout so it's available in the menu manager. Very often there is only one layout per view.
Control is passed to the view /views/useradd/view.html.php , and the view will then load an instance of its own model (automatically chosen based on the view name, you can load other models of course) to gather any initialization data.
The view then renders the layout, and presents it to the user.
The layout's responsibility includes generating a form with an appropriate action (endpoint) and security tokens if appropriate:
<form action="index.php?option=com_mycomponent">
<input type="hidden" task="user.save">
<?php echo JHtml::_('form.token');?>
as you see it doesn't really matter if you want to use <input or params on the url, and you can most often mix them.
Form interaction
For autocompletion the form may need to invoke some backend controller methods, i.e. the method emailAvailable() in the /controllers/user.php
It does not make sense to have such functionality indexed, so we'll invoke the method directly with a non-SEF url:
index.php?option=com_ourcomponent&task=user.emailAvailable
followed by any other parameter. This will work in both get and post.
The controller /controllers/user.php's emailAvailable() method will return a json structure and then invoke exit() as we don't want the CMS to kick in at all. An alternative solution is to add the param &format=json in the call.
{"email":"johndoe#example.com", "available":true}
Saving the data
When the user submits the form, processing is first handled by the controller since a task is specified. (see above task=user.save). Joomla will invoke the method save() in the controller /controllers/user.php.
This time, however, our controller is responsible for returning information to the user. After processing the data, it may choose to re-render the registration form showing an error, or a thank you page. In either case the controller simply sets the redirect, letting Joomla handle the rendering when appropriate.
$this->setRedirect(JRoute::_('index.php?option=com_yourcomponent&view=useradd', false));
More control
Each time a controller task is not specified, the display() method of the main controller is invoked. You can add custom logic there.
Joomla fires several events during a view rendering; these can be intercepted by a system plugin or - if you add in the calls - other kinds of plugins as well. You may even create your own types of plugins. Do not try to instantiate a view manually from a controller, as this may inhibit plugin firing.
Small insight,
1) Directory Structure
controllers/
controller1
controller2
controller3
models/
modelForTableA
modelForTableB
views/
layout1
2) View and layout and task
check this answer
3) More routing techniques with SEF.
Hope it helps.
solved with this. I cannot delete this question because there already exists other answer.
Could any moderator close or delete this? Thank you
https://joomla.stackexchange.com/questions/18774/joomla-terminology-view-layout-task-and-component-development/18799#18799
Let's say I have a simple ASP MVC3 list controller, with an add method, with an id parameter.
List:
http://localhost/MVCAPP/ListFoo/
Add method
http://localhost/MVCAPP/ListFoo/Add?id=1
In my Add method, I update my Viewmodel with the added element, then makes a call to:
return View("ListFoo", viewModel);
The updated list is displayed, and everything's almost fine.
The problem is that with such a return, the URL in the address bar is still
http://localhost/MVCAPP/ListFoo/Add?id=1
And if the user hits F5, another item will be added, which I'd like to prevent.
I know I can filter out such a behavior in the controller, but I'd rather prefer to redirect the browser address bar to:
http://localhost/MVCAPP/ListFoo/
Do you know any way to do this?
By the way, I'm not sure trying to control the address bar content is the right way to look at this issue...
Use the Action.RedirectToAction method to redirect the client after the work is done in the controller.
Besides that, you could use POST as FormMethod to send data to the server.
That is why you need to use PRG: Post-Redirect-Get when you are doing any such form post.
Have a look here.
So the best option is to redirect the user to a GET method to display the page.
Are it in any way possible to execute another action in the same on in another controller from an action, action filter or in any other way without doing a physical redirect.
The reason for this is that I have a dynamic paging system, where the user will load a url, for an example
/1/some-page-title
This url is maped to the controller “Home” and the action “Element”, this action will then load a row from the database where the element id is “1”. Depending from the data on the element from the database will the page be rendered as a contact form, an image gallery and so on.
Now I could map the paths so
/Page/1/some-title/ will render a normal html page,
/Contact/1/some-title/ will render a contact form
/Gallery/1/some-title/ will render a gallery
But I would prefer the paths to be simple.
There are problems with this answer, it's been a long time since I did anything thing with ASP MVC, so I'm not actually aware of what the problems are.
Unfortunately I can't delete an accepted answer.
So, I'm striking through the answer as it was, if you can actually answer this, or make it better, please do so.
Yes, very simple really :)
Say you're in controller C action A. You want to "redirect" to controller B action Z, just call the other controller action from the current one, returning it's result.
public ActionResult A()
{
return B.Z()
}
You may be looking for Html.RenderAction or Html.Action. However, these are used in the view and not the controller.
Right now, I'm working on my first WP7 app and have run into some questions, which I haven't been able to answer despite reading what I could find online. Please consider an app that has a main page, a parameters page and a results page. In the parameters page, the user can enter or update numbers in various textboxes. Hitting the back button takes the user back to the main page, where there is a button called "Calculate". Hitting that button should take the data, perform a calculation with it and take the user to the results page presenting a grid with the results.
In a file called Calculator.cs I have a class called Calculator inside a folder called Models. I also have my MainViewModel.cs, ParametersViewModel.cs, and ResultsViewModel.cs files inside the ViewModels folder and the corresponding MainPage.xaml, along with Parameters.xaml and Results.xaml inside a folder called Views. I'm assuming that all the data will be manipulated within the instance of the Calculator class and then a results set will be returned and directed to Results.xaml. I'm just at a loss as to where to instantiate the Calculator class, pass it data, then retrieve the results. I'm also somewhat puzzled how I will trigger the automatic navigation to the Results page when the calculation is done.
Any help with this would be greatly appreciated.
UPDATE: Passing a complex object to a page while navigating in a WP7 Silverlight application has some more info on the same subject. I can go into App.xaml.cs and add something like this:
public class Foobar
{
public string barfoo = "hah!";
}
public static Foobar myfoob = new Foobar();
Then access it from a ViewModel page, e.g. AboutViewModel.cs, like this:
public AboutViewModel()
{
string goo = App.myfoob.barfoo;
}
But at this point I'm still uncertain what unforseen effects that might have. I'm going to tackle serialization/tombstoning at this point to see what happens with either this approach or by using the same DataContext across pages. Otherwise, one of the posters in the link above mentioned serializing the params and passing them between pages. My concern there would be whether or not there is a character limit as with HTTP GET. Seems there is: URI Limits in Silverlight
There are of course lots of possible designs - and lots of them are correct in different ways!
Here's one I might use:
The Calculate button press should trigger the Navigate to the Results page
On navigate to, the Results page should show some animation (maybe just a progress bar)
On navigate to, the Results page should create a new ResultsViewModel, passing in the MainViewModel as parameters
the constructor (or some init method) of the ResultsViewModel should spark up a thread to do the calculation
when this calculation is complete, then the relevant properties of the ResultsViewModel will get set
at which point the databinding on the Results page will clear the animation and show the results
Other solutions are definitely available - will be interested to read what other people suggest and prefer.
As an aside, one thing to watch out for on your Results page is tombstoning - could be an interesting challenge!
I know how to use Zend_Acl to allow certain resources to certain usergroups but how do i use it to allow only specific parts of the page to be shown? For example
I have a button to delete a post via AJAX on the page but i only want to show the button to Admins only. I can use Zend_Acl to block access to the controller post/delete but i can't use it to block the button from showing.
// in controller
$this->view->allow_delete_post = $acl->isAllowed($role, 'delete_post');
.
// in template
<? if ($this->allow_delete_post): ?>[button html]<? endif; ?>
Would that not do it?
You can also write a custom static ACL class which you can then call directly from within your view script.
Since ACL is normally handled at plugin level it means that if your visitor is seeing the view then ACL has already allowed the resource, therefor inside your view you can now do something like this...
if(My_Custom_Acl::getIsAllowed('some_resource', 'delete_post_action'){
I did not specify the role name in the custom getIsAllowed() method, because at this point ACL is already suppose to know the user's Identity and the Role.
Hope this helps
Although Christof gave a good solution, an alternative is to split the views. Although this starts to violate DRY, when you have about 200 different admin things/controls, it's getting heavy in the view - thus splitting the view with $this->render('view') and $this->render('edit') for permissions from the controller is sometimes easier. Then only the edit view script has the edit links. But again, it's DRY, so not optimal, but an alternative. I guess you have to weigh it up, which one is more DRY, repeating the ACL check or the stuff in 2 views...