How to dynamically load a component with settings in CakePHP 2? - cakephp

I understand that we can pass settings for a component when we define the component at the start of a controller. Example from the CakePHP 2.0 Cookbook
public $components = array(
'Auth' => array(
'authorize' => array('controller'),
'loginAction' => array(
'controller' => 'users',
'action' => 'login'
)
),
'Cookie' => array('name' => 'CookieMonster')
);
But I usually load components on the fly like so (also from the Cookbook)
$this->OneTimer = $this->Components->load('OneTimer');
While using the second method (loading a component on the fly), how can I pass settings to it so that I can use them in the constructor to correctly setup the component based on the settings?
Any help would be greatly appreciated.

2 minutes after asking the question I looked at the load function in the library and found that settings is the second argument for the function.
public function load($component, $settings = array())
So I just need to supply the settings as the second parameter when I load components on the fly.

Related

CakePHP 2.7.1 unauthorizedRedirect

In my AppController I have this code for the component
public $components = array(
'Acl',
'Auth' => array(
'authorize' => array(
'Actions' => array('actionPath' => 'controllers')
),
'unauthorizedRedirect' => array(
'controller' => 'member',
'action' => 'index'
)
),
'Session',
'DebugKit.Toolbar'
);
So, unauthorizedRedirect is working fine. I tried to type the URL the user has no access to and fortunately, I am redirected to 'localhost/appname/member/'.
My concern is that, this only applies to one type of logged in user.
Let us say a logged in user tried to access localhost/appname/admin/add_post/. Since only admins have access to that page, the user will be redirected to localhost/appname/member/. What if it's an admin who accessed an unauthorized page? Of course, that admin will have to redirected somewhere, but not to localhost/appname/member/.
How can I solve this?
I believe there are many ways. You are already using the ACL which is one way. Or another "lazy" way to do this is to use the beforeFilter method inside the AppController.
Ok, so after several hours of researching and stuff I was able to come up with a solution.
This is the code for the AppCntroller:
public $components = array(
'Acl',
'Auth' => array(
'authorize' => array(
'Actions' => array('actionPath' => 'controllers')
),
'unauthorizedRedirect' => false
),
'Session',
'DebugKit.Toolbar'
);
What this does is rather than redirecting the user to another page, it will just show 'error400.ctp'.
Now, we don't want to show the default CakePHP error layout so we still have to edit it or make a custom one.
Create a new file under 'View/Layouts/your_error_file.ctp'. After that, go to 'View/Errors/error_file.ctp' and paste the following code:
$this->layout = 'your_error_file'

CakePHP 2.3 Plugin doesn't seem to extend appcontroller

I've created a plugin called 'IssueTracker', which is located in app/Plugin/IssueTracker. I've created a Controller called Tickets and it is accessible at www.example.com/issue_tracker/tickets/. But, only for logged in users with the rank 'Admin'.
That wasn't exactly what I was hoping for, so I added in my Plugin/IssueTracker/Controller/TicketsController.php the following:
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('index');
}
I hoped that with this piece of code (which I'm using in several other controllers in my app/Controller/ that it would inherit from my AppController.php file. The TicketsController.php file extends the IssueTrackerAppController (like this):
class TicketsController extends IssueTrackerAppController {
//functions goes in here
}
And in my Plugin/Controller folder I've created the file IssueTrackerAppController which extends the AppController.
In my AppController.php file I've allready defined that 'index' and 'view' are public actions. But, for some reason, it doesn't work in my plugin.
Is there something that I'm overseeing? When I access www.example.com/issue_tracker/tickets as a not logged in user (Guest), it tells me that I need to login. If I'm logged in as a user, but not as an Admin, the Auth component won't allow me in and presents the login form.
There should be a way to get Auth working in a plugin, right?
EDIT
Below is the AppController.php snippet where I've configured Auth:
public $components = array(
'Auth' => array(
'loginAction' => array('controller' => 'users', 'action' => 'login', 'plugin' => false),
'loginRedirect' => array('plugin' => false, 'controller' => 'ervaringen', 'action' => 'add'),
'logoutRedirect' => array('plugin' => false, 'controller' => 'ervaringen', 'action' => 'index'),
'authorize' => array('controller'),
'flash' => array(
'element' => 'error',
'key' => 'auth',
'params' => array(
'heading' => 'Waarschuwing!')
),
'authError' => 'Je moet inloggen om deze inhoud te bekijken.',
),
'Session',
'DebugKit.Toolbar'
);
Mystery solved.
After rescanning all the code in the plugin, I noticed that one of my coworkers on the project used $variable = $this->requestAction(link/here/with/id/etc);, which leads towards a controller function. That particular function wasn't allowed in any way by the beforeFilter(), causing a 'function denied' bij the Auth system.
I've added this particular function in $this->Auth->allow('function'); in the beforeFilter() of the plugin and now it is working.

want to remove action name from url CakePHP

i am working on a Cakephp 2.x.. i want to remove the action or controller name from url ... for example i am facing a problem is like that
i have a function name index on my Messages controller in which all the mobile numbers are displaying
the url is
www.myweb.com/Messages
now in my controller there is a second function whose name is messages in which i am getting the messages against the mobile number
so now my url becomes after clicking the number is
www.myweb.com/Messages/messages/823214
now i want to remove the action name messages because it looks weired...
want to have a url like this
www.myweb.com/Messages/823214
When connecting routes using Route elements you may want to have routed elements be passed arguments instead. By using the 3rd argument of Router::connect() you can define which route elements should also be made available as passed arguments:
// SomeController.php
public function messages($phoneNumber = null) {
// some code here...
}
// routes.php
Router::connect(
'/messages/:id', // E.g. /messages/number
array('controller' => 'messages', 'action' => 'messages'),
array(
// order matters since this will simply map ":id"
'id' => '[0-9]+'
)
);
and you can also refer link above given by me, hope it will work for you.
let me know if i can help you more.
REST Routing
The example in the question looks similar to REST routing, a built in feature which would map:
GET /recipes/123 RecipesController::view(123)
To enable rest routing just use Router::mapResources('controllername');
Individual route
If you want only to write a route for the one case in the question
it's necessary to use a star route:
Router::connect('/messages/*',
array(
'controller' => 'messages',
'action' => 'messages'
)
);
Usage:
echo Router::url(array(
'controller' => 'messages',
'action' => 'messages',
823214
));
// /messages/823214
This has drawbacks because it's not possible with this kind of route to validate what comes after /messages/. To avoid that requires using route parameters.
Router::connect('/messages/:id',
array(
'controller' => 'messages',
'action' => 'messages'
),
array(
'id' => '\d+',
)
);
Usage:
echo Router::url(array(
'controller' => 'messages',
'action' => 'messages',
'id' => 823214 // <- different usage
));
// /messages/823214
in config/routes.php
$routes->connect('/NAME-YOU-WANT/:id',
['controller' => 'CONTROLLER-NAME','action'=>'ACTIOn-NAME'])->setPass(['id'])->setPatterns(['id' => '[0-9]+']
);
You can use Cake-PHP's Routing Features. Check out this page.

Routing with named parameters

I have a URL that contains named parameters, which I want to map to a more user friendly URL.
Take, for example, the following URL:
/videos/index/sort:published/direction:desc
I want to map this to a more friendly URL, like:
/videos/recent
I have tried setting it up in the Router, but it doesn't work.
Code samples from the Router:
Router::connect(
'/videos/recent/*',
array('controller' => 'videos', 'action' => 'index'),
array('sort' => 'published', 'direction' => 'desc'
));
Which doesn't work. And the following also doesn't work:
Router::connect(
'/videos/recent/*',
array('controller' => 'videos', 'action' => 'index', 'sort' => 'published', 'direction' => 'desc'));
Any ideas?
Use get args
The easiest way to have routes work is to avoid named arguments all together. With pagination thats easy to achieve using appropriate config:
class FoosController extends AppController {
public $components = array(
'Paginator' => array(
'paramType' => 'querystring'
)
);
}
In this way when you load /videos/recent you should find it includes urls of the form:
/videos/recent?page=2
/videos/recent?page=3
Instead of (due to route mismatching)
/videos/index/sort:published/direction:desc/page:2
/videos/index/sort:published/direction:desc/page:3
But if you really want to use named args
You'll need to update your route definition - there's no page in the route config:
Router::connect(
'/videos/recent/*',
array(
'controller' => 'videos',
'action' => 'index',
'sort' => 'published',
'direction' => 'desc'
)
);
As such, if there is a page named parameter (which there will be for all urls generated by the paginator helper), the route won't match. You should be able to fix that by adding page to the route definition:
Router::connect(
'/videos/recent/*',
array(
'controller' => 'videos',
'action' => 'index',
'sort' => 'published',
'direction' => 'desc',
'page' => 1
)
);
Though even if it works, you may find it to be fragile.
lets see on [Router::connect documentation](Routes are a way of connecting request urls to objects in your application)
Routes are a way of connecting request urls to objects in your application
So, it's map urls to objects and not url to url.
You have 2 options:
use Router::redirect
Something like that:
Router::redirect( '/videos/recent/*', '/videos/index/sort:published/direction:desc');
but seems that's not that you want exactly
use Router::connect
use normal Router::connect which will connect url to some action which make appropriate scope. Something like that:
Router::connect(
'/videos/recent/*',
array(
'controller' => 'videos',
'action' => 'recent'
)
);
and in VideosController
public function recent() {
$this->request->named['sort'] = 'published';
$this->request->named['direction'] = 'desc';
$this->index();
}
it works and I saw such usage, but not sure, that is will satisfy you too.
as for me, I like normal named cakephp parameters. If such scope (published and desc) is your default state, just code default state in index action. For over cases i think it's normal to use ordinary named parameters.

Defining a custom table for AuthComponent

I've created a simple CMS to manage several small websites built on CakePHP. After successfully migrating the plugin from 1.3 to 2.0 I'm running into a problem with the AuthComponent after updating Cake to the latest version 2.1.2.
The classnames of the plugin are all prefixed by the plugin's name to avoid duplicate classnames, as the application shares most of its tables with the plugin. So there are cases when I have a UsersController for the main application and a PluginNameUsersController for my CMS plugin (or a PostsController and a PluginNamePostsController). The plugin models rely on $useTable to find the correct database table (so PluginNamePostsController still uses posts).
Since upgrading to the 2.1.* branch of Cake the AuthComponent has ceased to work as it expects a non-existent pluginname_users table instead of referring to users.
Is it possible to define a custom table for the AuthComponent or is there any other method to get this working? Also, is this behaviour expected?
The component is configured in PluginNameAppController as follows:
public $components = array(
'Session', 'RequestHandler',
'Auth'=> array(
'loginAction' => array(
'controller' => 'pluginname_users',
'action' => 'login',
'plugin' => 'pluginname'
),
'loginRedirect' => array(
'controller' => 'pluginname_posts',
'action' => 'index',
'plugin' => 'pluginname'
),
'authenticate' => array(
'Form' => array(
'userModel' => 'PluginNameUser',
'fields' => array('username', 'password')
)
)
)
);
The AuthComponent is actually unaware of tables and such. By using a custom model, you can define $table on it to work on a different table. So, the first thing is to set up your plugin's model to use the proper table:
class PluginNameUser extends PluginAppModel {
public $table = 'users';
}
Then, tell your authentication methods to use the plugin's model by using the dot syntax.
'authenticate' => array(
'Form' => array(
'userModel' => 'PluginName.PluginNameUser',
'fields' => array('username', 'password')
)
)
Now when FormAuthenticate tries to authenticate, it will try and find the user using that model, which it now knows is in PluginName. It loads the model, which you've set to use the users table, and looks for the user there.

Resources