Future Proofing Changes to Validation of Username/Password Field in ZFCUser - php

I've been looking around at how to change the actual validation process of the registration fields in the ZFCUser module in Zend Framework 2.
There is a lot about extending and adding new fields etc. to the form but not validating these fields or extending the existing validation.
I have taken a look inside the code and found the RegistrationForm.php file and added my customer Regular Expression filters.
This works well and as expected but I am worried about this being over-written on any future upgrade.
How would I go about doing this so it is upgrade safe? Is it a case of extending a specific class or adding it as a local file in my custom modules as I have done with the view files.

I've same problem as you, and also do not find proper solution. But IMHO better way than change original source code is to override one of the ZfcUser services.
There is a service called 'zfcuser_change_password_form' defined in zfc-user Module.php. If you create own service with same name - the original one will be overriden. So, first you need to define your own filter / validator class (YourFilter), then in your Module.php add:
public function getServiceConfig()
{
return array(
// ...
'factories' => array(
// ...
'zfcuser_change_password_form' => function ($sm) {
$options = $sm->get('zfcuser_module_options');
$form = new \ZfcUser\Form\ChangePassword(
null, $sm->get('zfcuser_module_options')
);
$form->setInputFilter(
new \YourModule\Form\YourFilter($options)
);
return $form;
},
),
);
}
Such solution allows to update zfcuser without overriding your changes.

Related

Symfony Controller magic method?

I am trying to use Symfony to replicate behavior in an existing Framework (zikula). This framework is extensible using modules which are basically extended symphony bundles. The old framework had urls like so
index.php?module=foo&type=bar&func=zip
which in symfony speak roughly translates to
index.php?bundle=foo&controller=bar&method=zip
The framework has an AbstractController which has a magic method like:
public function __call($method, $args)
{
$event = new \Zikula\Core\Event\GenericEvent($this, array('method' => $method, 'args' => $args));
$this->eventManager->dispatch('controller.method_not_found', $event);
if ($event->isPropagationStopped()) {
return $event->getData();
}
}
so, if you created a url with a method that didn't exist in the bundle, you could create a listener to capture it and send a response that looks like and behaves like it came from the specified bundle. We use this to call module services that are available to all modules and provided in a separate module but look like they are served by the 'host' module.
Now I am trying to replicates this using symfony and routing.
the first problem is generating a route that doesn't technically exist. Is this possible?
The second problem is capturing the RouteNotFoundException (which I know how to do, we already have listeners for other exceptions).
The last problem is making it appear that the bundle is serving up the response when it is actually being served by an event listener (or something else). This last part is important because other content in the response needs to come from the module/bundle.
I have tried changing the current listener to a controller, and also tried adding a method to our extension of symfony's AbstractController, but haven't yet achieved what I am hoping to achieve. I'm hoping for some suggestions on new ideas or methods to try.
I gave up trying to replicate the exact behavior as it seems impossible (it is also pretty difficult to describe). So I have resorted to a normal controller with standard route, but I found a way to make it appear to belong to the original 'host' module. Thanks to Gerry, ggioffreda and DerStoffel for offering ideas.

Extending & overriding ZfcUser behaviour

I'm using ZfcUser with ht-user-registration and scn-social-auth and there are 2 fairly minor enhancements I want to achieve to extend my implementation, but I'm not having much success so far:
ht-user-registration sends new users an email after registering and denies them access until they've activated their account, this is working fine. What I'd like to do to extend this is redirect the user after registration so that they are sent to a page telling them to check their e-mail rather than to the login page, which is the default behaviour of ZfcUser. I have tried adding an event listener to the module bootstrap that looks like this:
$response = $e->getResponse();
// indicate that we intend to redirect after register action
// set the redirection location to the home page
$response->getHeaders()->addHeaderLine('Location', 'home');
$response->setStatusCode(302);
$response->sendHeaders();
$em = \Zend\EventManager\StaticEventManager::getInstance();
$em->attach('ZfcUser\Service\User', 'register', function($event) use ($response) {
// don't allow anything else to process this event
$event->stopPropagation();
// return the redirect response
return $response;
});
This is called correctly but the redirect never happens and the user still ends up at the login page. Is there something else I need to do to execute the redirect? Or maybe there's a better way entirely to achieve this?
I'd like to add layout variables so that I can modify page titles and navigation in my layout template for the ZfcUser pages. In order to do this I made an override of the UserController from ZfcUser like this :
class UserController extends \ZfcUser\Controller\UserController
{
public function loginAction()
{
$this->layout()->setVariables(array(
'view_title' => 'Reports Login',
));
return parent::loginAction();
}
}
And then overrode the invokable for zfcuser in the config like this:
'controllers' => array(
'invokables' => array(
'Application\Controller\Index' => 'Application\Controller\IndexController',
'zfcuser' => 'Application\Controller\UserController',
),
),
The framework tries to instantiate my UserController at the right point but fails with an InvalidArgumentException: 'You must supply a callable redirectCallback' which I can see is required to construct the base controller but doesn't get passed to my overridden version - any clues why not? I can't find a working example of this to help.
Maybe there's a much easier way to inject layout variables into another module's controller actions?
[EDIT] I have found a simple but not very elegant way of doing this. Since my module overrides the views for both login and registration then it's possible to set layout variables within the view, thus I was able to add a one liner to the top of each view to set the layout variable, e.g.:
<?php $this->layout()->setVariable('view_title', 'Register for an account'); ?>
This doesn't feel correct, but works. If there's a better solution I'd like to know.

How do I add an input field to the form->create method globally in cakephp 1.2

I am trying to add a hidden input on all of my forms as a part of $form->create() function (kinda like how rails does) so I can add in a custom csrf token.
Is there anyway I can override the helper to add a input after it?
The easiest way will be to add the security component cake provides.
By using the Security Component you automatically get CSRF and form tampering protection. Hidden token fields will automatically be inserted into forms and checked by the Security component.
You should not be doing that anyway i.e. in the way you asked the question (form->create). Create a helper and use that, you can also store the CSRF in the user's session if you are wondering where to put the value.
Overriding Core Helpers via Aliases in CakePHP 2.x
In CakePHP 2.x its possible to overriding the default helpers by using an 'alias' for your own helper. This will allow your to create a 'drop-in' replacement for the built-in CakePHP helpers without changing the rest of your code.
For example:
app/Controller/AppController.php
class AppController extends Controller {
public $helpers = array(
'Form' => array(
'className' => 'FancyFormHelper'
)
);
}
app/View/Helper/FancyFormHelper.php
App::uses('FormHelper', 'View/Helper');
class FancyFormHelper extends FormHelper {
public function create($model = null, $options = array())
{
$output = parent::create($model, $options);
// append your hidden fields
return $output . $this->createCSRFfield(); // Or whatever you name your method
}
}
Documentation: Using and Configuring Helpers

Zend Framework: Controllers in separate directories

I'm quite new in Zend framework, but quickly learning. I've encountered the following problem, but I don't really know if my solution is good :)
I've created an application which uses widgets. Widget is a class which implements Widget_Interface and is executed by Widget_Manager.
Widgets can be loaded via WidgetController (which calls Widget_Manager, etc). Now the problem I encountered is: widgets can also be configured, and to make the code more transparent, I'd like a widget to have its own controller (currently, it is only a class). But the problem is, I'd like all widget configurations to be addressed via WidgetController, and then passed to specific widget controller.
An example: let's say I've got a widget named 'scrobbler'. Now when configuring it in the UI, I'd like to make Ajax request with updated settings. I could make a request like http://myapp.com/scrobbler/update-info/, so the framework would run ScrobblerController and I'd process the information from here on.
My idea is to make a request on http://myapp.com/widget/update/scrobbler/, so the framework runs WidgetController. WidgetController would then call ScrobblerController and pass other parameters.
I'm aware of _forward() function in Zend_Controller, but I'd like to have widget controllers and my application's controllers separated (let's say application controllers in /application/controllers and widget controllers in /application/controllers/widgets).
Is it possible to make this and what do I have to add to the Zend framework configuration? Hope I didn't complicate too much :)
Nice day
Edit:
Solved this using modular structure, and moved common classes into root directory.
You coud probably utilize Controller helpers instead of controllers in this case. So let's say that WidgetController is responsible for updating all types of widgets. The updateAction would need to find information on which widget type you wish to configure, this is the scrobbler parameter. You would need to name this parameter so it can be accessed easily. This can be done by either adding a route or adding the name before scrobbler in the uri.
Solution 1: Add a route:
In Bootstrap:
public function __initRoutes () {
$route = new Zend_Controller_Router_Route(
'widget/update/:type',
array (
'controller' => 'widget',
'action' => 'update'
),
array (
'type' => '[a-z_-]*'
)
);
/* #var $fc Zend_Controller_Front */
$fc = $this->bootstrap('FrontController')->getResource('FrontController');
/* #var $router Zend_Controller_Router_Rewrite */
$router = $fc->getRouter();
$router->addRoute('update-widget', $route);
}
Solution 2: Add the parameter name in the uri:
Make requests to /widget/update/type/widgetName instead.
Now, in the WidgetController::updateAction, you can fetch the widget to update using $this->_getParam('type').
So the code could look something like:
class WidgetController extends Zend_Controller_Action
{
public function updateAction ()
{
$widgetName = $this->_getParam('type');
$this->view->result = $this->_helper->Widgets->update($widgetName);
}
}
class App_Controller_Helper_Widgets extends Zend_Controller_Action_Helper
{
public function update($widgetName)
{
$widgetManager = new App_Model_WidgetManager();
$widget = $widgetManager->load($widgetName);
$widget->setOptions($this->getRequest()->getParams());
return $widget->save();
}
}

CakePHP 1.3 Plugin Shortcut Route

I searched a lot around the web but I couldn't find any specific sollution to this.
In CakePHP 1.3, different from 1.2, if you had a controller inside a plugin, and both had the same name, you could access through "<plugin>/<action>", and it would call the 'default' controller. But in 1.3, according to this:
http://cakeqs.org/eng/questions/view/setting_up_magic_routes_for_plugins_in_cakephp_1_3
It was removed, and only the 'index' action in the default plugin controller can be accessed this way.
I thought about adding extra code in my routes.php file, and loop through all the plugins in my app, making such routes for every action in the controllers named after the plugin, but it doesn't seem like it's the right thing to do...
any other suggestions to make this work in 1.3? or at least some very specific code documentation of this particular change? I've already read something in the 1.3.0-RC4 annoucement, but it was not clear enough..
thanks
Assuming a plugin named "test", you could do something like this in app/plugins/test/controller/test_controller.php:
<?php
class TestController
extends AppController
{
public function index()
{
// Is there any additional args passed to us?
if(count($this->passedArgs) > 0)
{
// Is this a request for one of our actions?
$actualAction = $this->passedArgs[0];
if(is_callable(array($this, $actualAction)))
{
// Yup. Do it.
return call_user_func_array(array($this, $actualAction), array_slice($this->passedArgs, 1));
}
}
// Default functionality here.
die("Index of plugin requested.");
}
public function another($param1, $param2)
{
die("{$param1}, {$param2}");
}
}
You'll also have to add the following to app/config/routes.php:
Router::connect("/test/*", array("plugin" => "test", "controller" => "test"));
With this done, a request to /test/another/one/two will correctly render "one, two" in the browser, and a request to /test will display "Index of plugin requested."
I think this isn't a bad way to go, minimal fuss on the plugin consumer side, only a little bit of fluff in the plugin code.

Categories