I have a page:
class page_membership extends Page{
public init(){
parent::init();
}
public register(){
}
public reset_password(){
}
}
How do I access from the url to :
http://localhost/membership/reset_password
http://localhost/membership/register
What are the necessary adjustment I need to do in order to invoke page sub methods like in codeigniter controller?
Thanks
I believe you should name your methods page_register() and page_reset_password() instead.
Doubts are about *reset_password*, because it uses underscore and underscore most likely will be converted to reset/password.
Related
There is a model data:
class Order extends Model
{
}
How to write a custom method inside the Order class so that it can be called in constructor like this:
Order::myMethod()
Order->myMethod()
Where myMethod is:
public function myMethod() {
return DB::query(<SQL QUERY>);
}
Purpose is to move SQL queries inside model's class, that don't mess this code in controllers.
Rather create a custom function in Model, You can use traits to achieve the desired output.
Please follow either steps:-
https://medium.com/#kshitij206/traits-in-laravel-5db8beffbcc3
https://www.conetix.com.au/blog/simple-guide-using-traits-laravel-5
Guess you are asking about the static functions:
class Order extends Model {
public static function myMethod() {
}
}
and you can call it anywhere like
Order::myMethod();
You can achieve the desired behavior using magic methods __call and __callStatic
if your real method is static you can use __call() to intercept all "non static" calls and use it to call the static and use __callStatic to forward the calls to a new instance to that class .
Your methods should be always static because if a non static method exists and you are calling it statically php raises an error
Non-static method Foo::myMethod() should not be called statically
No problem if your method is static
class Order extends Model {
public static function myMethod() {
return static::query()->where(...)->get(); // example
}
public function __call($name, $arguments) {
return forward_static_call_array([__CLASS__, $name], $arguments);
}
public static function __callStatic($name, $arguments) {
return call_user_func_array([app(__CLASS__), $name], $arguments);
}
}
(new Order())->myMethod();
Order::myMethod();
I can't understand your exact problem is. but if you are using laravel, then you can write custom method inside the ABC model like this
class ABC extends Model
{
//here is your fillable array;
public function abc()
{
//Here is your Eloquent statement or SQL query;
}
}
just call this abc() method inside the controller like this
use ABC;
class AbcController extends Controller
{
private $_abc; // it is private variable
// this is constructor
public function __construct(ABC $abc)
{
$this->_abc= $abc;
}
public function abcMethod()
{
$this->_abc->abc();
}
}
Thanks
I don't believe I'm understanding your intention. You've stated:
Purpose is to move SQL queries inside model's class, that don't mess this code in controllers.
Why does the Order->myMethod() need calling inside the constructor? If you're trying to design your data access layer to work efficiently, you can use data repositories.
I am playing around with the idea of having a base controller that uses a generic repository to provide the basic CRUD methods for my API controllers so that I don't have to duplicate the same basic code in each new controller. But am running into problems with the routing attribute being recognized when it's in the base controller. To show exactly what the problem I'm having I've created a really simple WebAPI controller.
When I have a Get method in the main Controller and it inherits from the ApiController directly I don't have any problems and this works as expected.
[RoutePrefix("admin/test")]
public class TestController : ApiController
{
[Route("{id:int:min(1)}")]
public string Get(int id)
{
return "Success";
}
}
When I move the Get method into a base controller it is returning the contents of the 404 page.
[RoutePrefix("admin/test")]
public class TestController : TestBaseController
{
}
public class TestBaseController : ApiController
{
[Route("{id:int:min(1)}")]
public string Get(int id)
{
return "Success";
}
}
Some more interesting notes:
I can access the action at GET /Test/1. So it is finding it based on the default route still.
When I try to access POST /admin/test, it returns the following JSON
{
"Message":"No HTTP resource was found that matches the request URI 'http://test.com/admin/test'.",
"MessageDetail":"No type was found that matches the controller named 'admin'."
}
Does anyone know of a way to get the routing to work with attributes from a base controller?
Attribute routes cannot be inherited. This was a deliberate design decision. We didn't feel right and didn't see valid scenarios where it would make sense to inherit them.
Could you give a more realistic scenario as to where you would want to use this?
[Update(3/24/2014)]
In the upcoming 5.2 release of MVC Web API, there is going to be an extensibility point called System.Web.Http.Routing.IDirectRouteProvider through which you can enable the inheritance scenario that you are looking for here. You could try this yourself using the latest night builds(documentation on how to use night builds is here)
[Update(7/31/2014)]
Example of how this can be done in Web API 2.2 release:
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
//---------
public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory>
GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
{
// inherit route attributes decorated on base class controller's actions
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>
(inherit: true);
}
}
Using Web API 2.2, you can:
public class BaseController : ApiController
{
[Route("{id:int}")]
public string Get(int id)
{
return "Success:" + id;
}
}
[RoutePrefix("api/values")]
public class ValuesController : BaseController
{
}
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory>
GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
{
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>
(inherit: true);
}
}
as outlined here: http://www.asp.net/web-api/overview/releases/whats-new-in-aspnet-web-api-22
Got it.
[Route("api/baseuploader/{action}")]
public abstract class BaseUploaderController : ApiController
{
[HttpGet]
public string UploadFile()
{
return "UploadFile";
}
}
[Route("api/values/{action}")]
public class ValuesController : BaseUploaderController
{
[HttpGet]
public string Get(int id)
{
return "value";
}
}
One caveat here is that the route action paramter must be the same as the action name. I could not find a way to get around that. (You cannot rename the route with a RouteAttribute)
Why does T4MVC uses virtual for controller methods? Changing a
public ActionResult Details (string Id)
to:
public virtual ActionResult Details (string Id)
I have already seen other questions about T4MVC but didn't understand why.
Usually if a framework/library needs virtual methods (see also Nhibernate) it means somewhere/sometime your methods will be overridden.
So T4MVC marks your action methods as virtual because it's overrides them.
Lets take a simple controller:
public partial class HomeController : Controller
{
public virtual ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
}
If you go to the generated HomeController.generated.cs under the T4MVC.tt you will find a generated class which inherits from your controller and overrides your action method:
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class T4MVC_HomeController: MvcApplication8.Controllers.HomeController {
public T4MVC_HomeController() : base(Dummy.Instance) { }
public override System.Web.Mvc.ActionResult Index() {
var callInfo = new T4MVC_ActionResult(Area, Name, ActionNames.Index);
return callInfo;
}
}
I haven't used T4MVC so I don't know why and for what purpose T4MVC creates this generated class.
The only benefit I can see for making them virtual is to allow the developer to 'Go to Implementation/Definition' where The T4MVC helpers are used. This works because the Controller's type on the static Helper 'MVC' is the base controller type.
public static partial class MVC
{
public static HomeController Home = new T4MVC_HomeController();
}
So in the following snippet, Go to Definition on the Action Name will go to Base Implementation:
#Url.Action(MVC.Home.Index())
+1 David Ebbo for such an intuitive feature. I was mind blown when I realized this!
PS: this does not work for the parameterless actions added via the partial function, instead they navigate to the generated code, unfortunately.
An existing RedirectToAction signature is
RedirectToAction(string action, RouteValueDictionary routeValues);
I wish to make.
RedirectToAction(RouteValueDictionary routeValues);
So I created the following
public static class MvcControllerExtension
{
public static RedirectToRouteResult RedirectToAction
(this Controller controller, RouteValueDictionary routeValues)
{
return controller.RedirectToAction
(routeValues["Action"].ToString(), routeValues);
}
}
However, the IDE for that code is showing a Recursive Call because it can only see itself.
It does not see this signature.
I have included using System.Web.Mvc; in the extension class.
How can I fix this? thanks.
Additional:
Here is the extention source code.
Note the recursive symbol.
(Sorry, SO is having issues uploading images to imgur.com. Will retry soon).
Why do an extension? RedirectToAction is a helper method in the Controller class, so why not create yours as a protected method in your base controller class?
public abstract class MyControllerBase : Controller
{
protected RedirectToRouteResult RedirectToAction(RouteValueDictionary routeValues)
{
return RedirectToAction(routeValues["Action"].ToString(), routeValues);
}
}
What namespace is MvcControllerExtension in - it must be in the same namespace or have the import for it.
I am creating an application in mvc3 and wondering how to deal with database data which is required for all application requests, some of them depends on a session, some of them depends on url pattern basically all data is in database.
Like to know best practice
What I do in my applications and consider to be the best practice is to load your common data to the ViewBag on the Controller constructor.
For every project, I have a DefaultController abstract class that extends Controller. So, every controller in the project must inherit from DefaultController, instead of Controller. In that class' constructor, I load all data common to the whole project, like so:
// DefaultController.cs
public abstract class DefaultController : Controller
{
protected IRepository Repo { get; private set; }
protected DefaultController(IRepository repo)
{
Repo = repo;
ViewBag.CurrentUser = GetLoggedInUser();
}
protected User GetLoggedInUser()
{
// your logic for retrieving the data here
}
}
// HomeController.cs
public class HomeController : DefaultController
{
public HomeController(IRepository repo) : base(repo)
{
}
// ... your action methods
}
That way you will always have the logged in user available in your views.
I do the same as #rdumont but with one exception: I create a CommonViewModel which I use to define all common properties that I use.
public class CommonViewModel
{
public string UserName {get;set;}
public string Extension {get;set; }
}
Declare a property in the base controller:
public abstract class BaseController : Controller
{
protected CommonViewModel Commons { get; private set; }
protected virtual void OnResultExecuting(ResultExecutingContext filterContext)
{
ViewBag.Commons = Commons;
}
}
By doing so I get everything almost typed. The only cast that I need to do is to cast ViewBag.Commons to the CommonViewModel.
Best is to avoid ViewBag at all.
See this answer, which details how to use Html.RenderAction() for that purpose:
Best way to show account information in layout file in MVC3
I'd suggest using a base ViewModel class.
So a base class with properties/functions which should be available at any point.