CakePHP v3.x API prefixed routes - cakephp

I have fallowing routes:
Router::scope('/', function (RouteBuilder $routes) {
Router::prefix('api', function ($routes) {
$routes->extensions(['json', 'xml']);
$routes->resources('JobChemicals');
$routes->fallbacks('DashedRoute');
});
Url: /api/job_chemicals/2.json - WORKS
Url: /api/job-chemicals/2.json - NOT
Action JobChemicalsController::2() could not be found, or is not accessible. Why?! I am using DashdRoute not underscored. Any ideas? I know it is small thinks, but it makes me crazy.

$routes->fallbacks('DashedRoute');
This only affects the fallback routes, not the call to $routes->resources.
Resource routes default to underscores
As noted in the question, underscored urls work.
As also noted in the docs, resource routes default to underscores:
By default, multi-worded controllers’ URL fragments are the underscored form of the controller’s name. E.g., BlogPostsController‘s URL fragment would be /blog_posts.
You can specify an alternative inflection type using the inflect option:
Router::scope('/', function ($routes) {
$routes->resources('BlogPosts', [
'inflect' => 'dasherize' // Will use ``Inflector::dasherize()``
];
});
The above will generate URLs styled like: /blog-posts/*.
The reason for this discrepancy is legacy (in 3.0 underscores were the default url inflection for everything), but the fix is simple - just include the inflect option to the resources call.

Related

Cakephp 3.6 - Missing Controller Error

I am having this error which does not seem to make sense. I am using this plugin: https://github.com/hashmode/cakephp-tinymce-elfinder. I am in need of creating and admin route. However, even though CakePHP sees the plugin, it does not see the Controller within it. I don't see what I am doing wrong.
This is my route for /admin/elfinder:
Router::prefix('admin', function ($routes) {
$routes->connect('/elfinder', ['plugin' => 'CakephpTinymceElfinder', 'controller' => 'Elfinders', 'action' => 'elfinder']);
});
This is the controller/action I am trying to access
https://github.com/hashmode/cakephp-tinymce-elfinder/blob/master/src/Controller/ElfindersController.php
But I get the following error:
2018-06-01 15:20:33 Error: [Cake\Routing\Exception\MissingControllerException] Controller class Elfinders could not be found.
Request URL: /admin/elfinder
It is definitely finding the Plugin. Why can't CakePHP find the controller?
According to the official CookBook you need to configure your prefixed routes in the following way. Hope this helps.
Router::plugin('YourPlugin', function ($routes) {
$routes->prefix('admin', function ($routes) {
$routes->connect('/:controller');
});
});
https://book.cakephp.org/3.0/en/development/routing.html#prefix-routing
Some time ago I wrote a plugin for my personal needs. I needed to bind its controllers to the /shop and /shop/api URLs. I managed to do it like this
Router::scope('/shop',['plugin'=>'MyPlugin'] ,function (RouteBuilder $routes) {
$routes->prefix('api', function($routes) {
$routes->extensions(['json']);
$routes->connect('/:controller');
$routes->resources('Categories');
$routes->resources('Products');
$routes->resources('Prices');
$routes->resources('Pricetypes');
});
$routes->connect('/:controller');
$routes->fallbacks(DashedRoute::class);
});

Laravel API route conflict with web root

In one of my website in laravel, when I tried to integrate angularjs4 everything works fine. But I am facing a conflict issue with api routes and route defined in web
The code in my web.php is as follows
Route::get('/{path?}', function () {
return view('site');
})->where('path', '.*')
->name('siteapp');
Since the above code route everything to the view "site", I cannot able to add api request routes in api.php, example is given below
The link www.mysite.com/api/user routes to the route in "web.php" which should be from api.php
Route in my api.php
Route::get('user', function (Request $request) {
return ['name' => 'demo'];
})->middleware('jwt.auth');
Is there any regular expression to skip the path begin with www.mysite.com/api/something
I.e. from web.php. Is there any rule to skip path? begin with api in this line "where('path', '.*')"?
As a brief is it possible to skip path begin with api in the rule where('path', '[api]! [---allow all other string-]')
Please adivice
You can use a regEx for that like this :
Route::get('/{path?}', function () {
return view('site');
})->where('path', '^(?!api).*$')
->name('siteapp');

Angular 1.5 $routerOnActivate on Root Router

I want to make sure that the user is logged in properly before proceeding to any of the components he/she's trying to reach, if they're not logged in. Send them to login.
My idea is to do a check in the $routerOnActivate in the root router. Which to me would solve the issue for any sub routes.
However nothing seems to happen if i just try to log something. Example:
angular
.module('app')
.config(function($locationProvider) {
$locationProvider.html5Mode(true);
})
.value('$routerRootComponent', 'app')
.component('app', {
templateUrl:'landing.html',
controller: MainController,
$routeConfig: [
{ path: '/', name: 'Dashboard', component: 'dashboard', useAsDefault: true },
{ path: '/media', name: 'Media', component: 'media'}
...
]
});
function MainController(){
this.$routerOnActivate = function(next, previous){
console.log('activated', next, previous);
};
}
The same code this.$routerOnActivate works if i put it in any of the Components which are specified in the routeConfig. However obviously I don't want to make the same check in every component, but rather solve it once globally.
What is the approach for 1.5?
Instead of performing a check when you load a page, use following:
Angular has a special component lifecycle hook to handle these edge cases named $canActivate - to check whether it should try to activate it or not. You may talk to a authentication/authorization service to validate that for a given user's state, are they allowed to reach your component or not.
This way your component will be smart enough to encapsulate any checks required to activate itself.
Also, you can inject any service like $http or your custom service to talk to your server. In the code snippet below, I mimic this call using $timeout that just returns true, if you return false, your component will not activate.
angular.module('app').component('someComponent', {
template: 'this is an inline component template',
$canActivate: function ($timeout) {
return $timeout(function(){
return true;
}, 2000);
}
});
Use another hook named $routerOnActivate to read the next and previous routes. If you are interested in the params of a route, use next.params which is an object that will always have the parameters that were passed to that route. e.g. next.params.id where id is the parameter that was passed to the requested route.
Use $canActivate using TypeScript:
I've written a post regarding how to use write AngularJS components in TypeScript and have some drafts to use router lifecycle hooks that I'll publish today. Till then, here is the code to use some hooks using TypeScript below:
class ReviewDetailsComponent implements ng.IComponentOptions {
templateUrl = 'app/components/review-details.component.html';
// function member for this hook doesn't work!!
// so either use lambda expression or function directly.
$canActivate = $timeout => $timeout(() => true, 3000);
controllerAs = 'model';
controller = ['$http', ReviewDetailsController];
}
angular.module('app').component('reviewDetails', new ReviewDetailsComponent());
The typescript code above is same as javascript code snippet above that uses $canActivate.
Unfortunately, it didn't worked when this is defined as a function member in class like $canActivate() and the generated javascript is this member defined using prototype like ReviewDetailsComponent.prototype.$canActivate.
But it works well when written using lambda expression syntax or a function directly. If you are using a class to define a component, it is good to choose lambda expression in this case.
Use $routerOnActivate using TypeScript
The linked controller in this case also uses another lifecycle hook named $routerOnActivate and this works well if defined as a function member:
interface IReviewDetailsController {
id: number;
$routerOnActivate(next, previous);
}
class ReviewDetailsController implements IReviewDetailsController {
id: number;
constructor(private $http: angular.IHttpService) { }
$routerOnActivate(next, previous) {
this.id = next.params.id;
// talk to cache or server to get item by id
// & show that on UI
}
}
Paste from my comment as requested
What about perform your check on the loading on the page ? This would run perfectly in an angular.run.
And if you want to handle session expiration, you can add an interceptor to all requests and watch for a 401 response.

Laravel 5 routing not working when using slashes inside groups?

I am facing a little weird problem with a simple routing in Laravel 5. Below, I have to commented code snippets.
// It works when I call /tribut.updateStatus URL
$router->group(['prefix' => 'admin', 'before' => 'isLogged|isAdmin'], function ($router) {
$router->resource('tribut', 'Admin\TributController');
$router->get('tribut.updateStatus', 'Admin\TributController#updateStatus');
});
// Does not work when I call: /tribut/updateStatus URL
$router->group(['prefix' => 'admin', 'before' => 'isLogged|isAdmin'], function ($router) {
$router->resource('tribut', 'Admin\TributController');
$router->get('tribut/updateStatus', 'Admin\TributController#updateStatus');
});
I want to use the second route option. Is it possible? What am I doing wrong? When I call the routing that does not work, the screen goes blank. No error is shown, neither in log files.
The problem is that $router->resource('tribut') registers a route that caches everything with GET tribut/* because it thinks * is an id.
The solution is pretty simple, just define the explicit get route before the resource route:
$router->group(['prefix' => 'admin', 'before' => 'isLogged|isAdmin'], function ($router) {
$router->get('tribut/updateStatus', 'Admin\TributController#updateStatus');
$router->resource('tribut', 'Admin\TributController');
});

Is there a pattern for reusing a resolver across modules in angularJS

I have a modular structure to my App meaning I have many config files with route definition in them. I am trying to use a resolver to check if the user is authenticated or not before I move them to the next route view.
right now I can reuse a function in the config as my resolve method i.e.
function resolverFunc(Auth, $state){
if(!Auth.isLoggedIn()){
$state.go('login');
}
}
$stateProvider.state('state1', {
url: "/myurl",
resolver:{
loggedIn: resolverFunc
}
}
)
.state('state2',{
url: '/url2',
resolver:{
loggedIn: resolverFunc
}
})
the problem is that I have to define the resolverfunc in every module. Because every module has it's own module.config() where the routes are defined for that module.
Is there a simpler solution. I hate to have to re-write this function in every config file for all the modules with routes

Resources