I have a project in Kohana 3.3.
I have a lot of controllers, models etc.
Now, I want add one functionality - close the whole site for all users.
Where I can add function, which for example, will redirect users to http://mypage.com/website_is_close ?
Example:
function check(){
$isClose = DB::query(.....)
if($isClose) header("Location: http://mypage.com/website_is_close");
return false;
}
Thanks :)
In Controller_Base all other controllers extend from. E.g.
File application/classes/Controller/Base.php
class Controller_Base extends Controller_Template {
public function before()
{
$isClose = DB::query(.....)
if($isClose)
{
HTTP::redirect("http://mypage.com/website_is_close");
exit ;
}
parent::before();
}
}
All other classes should extend from that class e.g
class Controller_Home extends Controller_Base {}
I personally use this also for every subdirectory e.g.
// As all controllers in the user folder probably need to be supplied with a user anyway
class Controller_User_Base extends Controller_Base {}
class Controller_User_Profile extends Controller_User_Base {}
I think a better approach would be to add a "catch all" route to the beginning of your routes list.
It would catch all URLs and would point to a controller that you would create. This is far cleaner than hacking away at a base controller.
How does this look?
Route::set('closed', '(<url>)', array('url' => '.*'))
->defaults(array(
'controller' => 'Closed',
'action' => 'index',
));
Related
I found this package nest-18n but that dudes thinks that nestjs is only used for api and not mvc.
So sure ?lang=en or ?lang=de works and it changes language but question is how to use that on view?
My first thought was that this is working out of the box with __("Something to translate"). But that will not work (__ is undefined).
Since i18Service.translate method is async you can not add it to view (there is pug then but that is horrible idea). Idea of adding anything on the the view that is async does not make sense at all. So in principle they made package that can not be used outside of api's.
Other thing that i can do is to have something like
class AppController extends BaseController() {
#Get("/")
index() {
return {
someTranslation: await this.getTranslation("give me something to translate"),
// IMAGINE NOW Having 1000 OF TRANSLATION ON INDEX PAGE
}
}
}
where BaseController is:
class BaseController() {
constructor(private readonly i18n: I18nService, lang: string) {
}
async protected getTranslation(stringToTranslate: string) {
return await this.i18n(stringToTranslate, {lang});
}
}
Does anyone have idea how to use any of i18n in nestjs mvc?
...guess I'm the first to ask about this one?
Say you have the following routes, each declared on a different controller:
[HttpGet, Route("sign-up/register", Order = 1)]
[HttpGet, Route("sign-up/{ticket}", Order = 2)]
... you could do this in MVC 5.0 with the same code except for the Order parameter. But after upgrading to MVC 5.1, you get the exception message in the question title:
Multiple controller types were found that match the URL. This can
happen if attribute routes on multiple controllers match the requested
URL.
So the new RouteAttribute.Order property is only controller-level? I know in AttributeRouting.NET you can do SitePrecedence too. Is the only way to have routes like the above when all actions are in the same controller?
Update
Sorry, I should have mentioned these routes are on MVC controllers, not WebAPI. I am not sure how this affects ApiControllers.
If you know that ticket will be an int you can specify that type in the route to help resolve the route:
[HttpGet, Route("sign-up/register")]
[HttpGet, Route("sign-up/{ticket:int}")]
This approach worked for me, per user1145404's comment that includes a link to Multiple Controller Types with same Route prefix ASP.NET Web Api
In case of Attribute routing, Web API tries to find all the controllers which match a request. If it sees that multiple controllers are able to handle this, then it throws an exception as it considers this to be possibly an user error. This route probing is different from regular routing where the first match wins.
As a workaround, if you have these two actions within the same controller, then Web API honors the route precedence and you should see your scenario working.
There are two ways to fix this:
A regex constraint, like here: MVC Route Attribute error on two different routes
Or a custom route constraint, like here: https://blogs.msdn.microsoft.com/webdev/2013/10/17/attribute-routing-in-asp-net-mvc-5/
You can create custom route constraints by implementing the IRouteConstraint interface. For example, the following constraint restricts a parameter to set of valid values:
public class ValuesConstraint : IRouteConstraint
{
private readonly string[] validOptions;
public ValuesConstraint(string options)
{
validOptions = options.Split('|');
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(parameterName, out value) && value != null)
{
return validOptions.Contains(value.ToString(), StringComparer.OrdinalIgnoreCase);
}
return false;
}
}
The following code shows how to register the constraint:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
var constraintsResolver = new DefaultInlineConstraintResolver();
constraintsResolver.ConstraintMap.Add("values", typeof(ValuesConstraint));
routes.MapMvcAttributeRoutes(constraintsResolver);
}
}
Now you can apply the constraint in your routes:
public class TemperatureController : Controller
{
// eg: temp/celsius and /temp/fahrenheit but not /temp/kelvin
[Route("temp/{scale:values(celsius|fahrenheit)}")]
public ActionResult Show(string scale)
{
return Content("scale is " + scale);
}
}
In my opinion, this isn't great design. There are no judgments about what URL you intended and no specificity rules when matching unless you explicitly set them yourself. But at least you can get your URLs looking the way you want. Hopefully your constraint list isn't too long. If it is, or you don't want to hard-code the route string parameter and its constraints, you could build it programmatically outside the action method and feed it to the Route attribute as a variable.
I have 3 models: User, Project, Task
Each user has many projects, each project has many tasks.
I want to do something like:
$user->projects()->tasks() to get the tasks of the projects of a user. projects() is a hasMany() relation and I believe tasks() should be a Scope, but have no idea how to implement it.
Well, suppose you have 3 models defined in this way:
User
class User extends Eloquent
{
public function projects()
{
return $this->hasMany('Project');
}
}
Project
class Project extends Eloquent
{
public function tasks()
{
return $this->hasMany('Task');
}
public function user()
{
return $this->belongsTo('User');
}
}
Task
class Task extends Eloquent
{
public function project()
{
return $this->belongsTo('Project');
}
}
I believe this would be enough to query all the user projects and tasks.
If you already have an instance of User class you can just load the required relations:
$user->load('projects.tasks');
dd($user);
Having belongsTo relations defined allows you to query all the tasks with projects and users they belong to:
Task::with('project.user')->get();
I am not sure about getting just a list of tasks. This is the first solution that comes to my mind:
$tasks = Task::whereHas('project', function($query) use ($user){
$query->whereHas('user', function($query) use ($user){
$query->where('id', $user->id);
});
})->get()
I believe there are other ways to achieve it using query builder and join() method.
I have the following link on my website - http://mywebsite/multimedia/pronounciation/265.mp3
which gets me the file bypassing controllers. But I would like to log request and then return this file. So I created controller which logs request and then reroutes to the file:
class Controller_GetSound extends Controller {
public function action_index() {
Request::factory('multimedia/pronounciation/265.mp3')
->method(Request::POST)
->post($this->request->post())
->execute();
}
}
But it doesn't work as expected. How can I return resource file from controller?
Kohana has a send_file function. That function does a good job on splitting large files and sending correct mime types.
#see http://kohanaframework.org/3.3/guide-api/Response#send_file
Your code should be:
class Controller_GetSound extends Controller {
public function action_index() {
$this->response->send_file('multimedia/pronounciation/265.mp3',TRUE,array(
'mime_type' => 'audio/mpeg',
))
}
}
You actually don't really need to set the mime_type. Kohana will find the correct mime_type for your.
It sounds like you want to implement something known as X-Sendfile. I think?
The controller would look something like this:
class Controller_GetSound extends Controller {
public function action_index() {
$this->response->headers(array(
'Content-Type' => 'audio/mpeg'
'X-Sendfile' => 'multimedia/pronounciation/265.mp3',
);
}
}
In routes I have
Router::connect('/opauth-complete/*', array('controller' => 'app_users', 'action' => 'opauth_complete'));
If I change pointer to controller app_users with anything else and create controller everything works with no error. But I need it to work with AppUsersController.
AppUsersController looks like this
App::uses('UsersController', 'Users.Controller');
class AppUsersController extends UsersController {
public function beforeFilter() {
parent::beforeFilter();
$this->User = ClassRegistry::init('AppUser');
}
// ...
// ...
public function opauth_complete() {
die(1);
}
// ...
// ...
}
So, plugin is CakeDC Users and another plugin that goes to /example/callback after /example/auth/facebook is Opauth plugin.
Error message looks like this
The request has been black-holed
Error: The requested address '/example/opauth-complete' was not found on this server.
This is perfectly possible to make these two plugins work together; when browser points to /example/auth/facebook, it redirects to /example/auth/callback and somehow it needs opauth-complete route to link to specific method.
All works if not pointed to app_users that extends plugin, uses plugin. Does not work only with this case. How can users of these two plugins get around such situation.
I solved it by disabling Security component on Opauth action in my AppUsersController. Thing is that Opauth transfers data using POST and you should either change a method of it (ie: use Sessions, GET) or disable Security component.
For a method change use this in your bootstrap.php or core.php
Configure::write('Opauth.callback_transport', 'session'); // you can try 'get' too
To follow my approach add this to a controller where error occurs and where you place your opauth_complete method
public function beforeFilter() {
// ...
if (isset($this->Security) && $this->action == 'opauth_complete') {
$this->Security->validatePost = false;
$this->Security->csrfCheck = false;
}
// ...
}
P.S. Changing method to Sessions has its drawbacks, you can take a look at comments here at Github Opauth issue #16