Zend Framework 2 - bjyauthorize - Link new user with role - php

I'm using bjyauthorize and I works great for existing users. I now are in need to add users dynamically.
I can set the connection between User and Role manually in the table UserRoleLinker but how do I it the way it is meant to be for new users? Maybe I missed something trivial?

The ZfcUser User service triggers a register.post event after the user is inserted in the db, so you just need to listen to that event. You can do that by attaching a listener to the shared events manager in your module bootstrap.
The event instance received by your listener contains the user service itself, plus the user data, and the form that was used during registration, which should be enough to make the link
public function onBootstrap(MvcEvent $e)
{
$app = $e->getApplication();
$events = $app->getEventManager();
$shared = $events->getSharedManager();
$sm = $app->getServiceManager();
$shared->attach('ZfcUser\Service\User', 'register.post', function ($e) use ($sm) {
$userService = $e->getTarget();
$newUser = $e->getParam('user');
$registrationForm = $e->getParam('form');
// do something with the new user info, eg, assign new user role...
});
}

Here's the full solution:
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
//You need a copy of the service manager and it has to be set as a member for the lambda function to call it
$this->sm = $e->getApplication()->getServiceManager();
$zfcServiceEvents = $e->getApplication()->getServiceManager()->get('zfcuser_user_service')->getEventManager();
$zfcServiceEvents->attach('register.post', function($e) {
/** #var \User\Entity\UserPdo $user */
$user = $e->getParam('user');
//This is the adapter that both bjyAuthorize and zfcuser use
$adapter = $this->sm->get('zfcuser_zend_db_adapter');
//Build the insert statement
$sql = new \Zend\Db\Sql\Sql($adapter);
//bjyAuthorize uses a magic constant for the table name
$insert = new \Zend\Db\Sql\Insert('user_role_linker');
$insert->columns(array('user_id', 'role_id'));
$insert->values(array('user_id' => $user->getId(), 'role_id' => 'user'), $insert::VALUES_MERGE);
//Execute the insert statement
$adapter->query($sql->getSqlStringForSqlObject($insert), $adapter::QUERY_MODE_EXECUTE);

Related

Zend 3 onBootstrap get adapter

I started using zend 3 a few months ago for a project and now I'm stuck.
I have a customized authentication (not using zend authentication module) which is working fine but I need to validate every time i access a redirected page.
Because on every page's url goes a token that is used to check in database, and I'm trying to do inside the function onBootStrap().
I learned to use factories, models, mappers and I'm currently using them in some controllers, but i can't find a way to achieve, at least if i could get the dbAdapter from the bootstrap event to use, it will be enough.
Any thoughts?
You can use lazy event for this job. here's you are a simple example.
public function onBootstrap(EventInterface $e)
{
/** #var \Interop\Container\ContainerInterface $container */
$container = $e->getApplication()->getserviceManager();
$events = $e->getApplication()->getEventManager();
$events->attach(MvcEvent::EVENT_ROUTE, new LazyListener([
'listener' => Listener::class,
'method' => 'onRoute'
], $container));
}
So you can check you auth on Listener class' "onRoute" method. If MvcEvent::ROUTE event is too early for you, you can use other MvcEvents too.
Hope this can solve your problem.
To get the adapter and use it in tablegateway
public function onBootstrap(EventInterface $event){
$container = $event->getApplication()->getServiceManager();
$dbAdapter = $container->get(AdapterInterface::class);
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new TableObjectClass());
$tableGateway = new TableGateway("Table name", $dbAdapter, null, $resultSetPrototype);
$mapper = new TableObjectClassMapper($tableGateway);
//and use $mapper to get data from the table and store it as TableObjectClass
$data = $mapper->fetch()->current();
}

Need separate error handler for each module in zend framework 2

I am using zend framework 2 for API. The folder structure is as follows
Project
Config
Module
Api
Module.php
Apiv2
Module.php
The code in module.php in both modules as below :
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
$eventManager->attach(MvcEvent::EVENT_DISPATCH_ERROR,array($this, 'handleError'));
$eventManager->attach(MvcEvent::EVENT_RENDER_ERROR,array($this, 'handleError'));
}
public function handleError(MvcEvent $evt)
{
//this is to force the error handleing so that our responses are also correct and
$router = $evt->getRouter();
$uriString = $router->getRequestUri();
$uri = new Uri($uriString);
$queryArr = $uri->getQueryAsArray();
$js = new JsonModel();
$exception = $evt->getParam('exception');
if(!$exception){
$valueToEncode = array(
'errorcode'=>"1",
'message' =>$evt->getError(),
'statuscode'=>404,
'file'=>$evt->getName(),
'line'=>0
);
}
else{
....
}
}
I want different code in handleError method of Apiv2 module than the code in Api module. But The code conflicts for both modules.
Please give me solution so that each module's error handler method should work separately.

ZF2 - Make onbootstrap events in one module supersede every other module

I have a ZF2 module called "Browsercheck", when used with other modules, checks the user's browser and shows an "Unsupported Browser" page if the browser is not supported. The issue I am having is, that the following code which is onBootstrap of the "Browsercheck" is not taking the first preference when other modules encounter an exception or a 404 error. IT works otherwise.
How can I make sure this code executes for every event and supersede any other event? Ideally in ZF1, I use code like this in index.php.. but not sure how it should be in ZF2. Basically if the browser is not supported, it shouldn't matter whether it's a 404 or an exception. It should go ahead and render the unsupported browser page.
public function onBootstrap(MvcEvent $e)
{
$sharedEvents = $e->getApplication()->getEventManager()->getSharedManager();
$sharedEvents->attach('Zend\Mvc\Controller\AbstractController','dispatch',
function($event)
{
$browser = new \BrowserCheck\Service\BrowserCheck();
if (!$browser->isCompatible())
{
$viewModel = new \Zend\View\Model\ViewModel();
$viewModel->setTerminal(true);
$request = $event->getRequest();
$response = $event->getResponse();
$viewModel->setTemplate('browser-check/index/index.phtml');
//Replace the entire view
$event->setViewModel($viewModel);
$event->stopPropagation();
$response->setStatusCode(200);
return $viewModel;
}
});
}
UPDATE:
$browserEventListener = function($event)
{
$browser = new \BrowserCheck\Service\BrowserCheck();
if (!$browser->isCompatible())
{
$viewModel = new \Zend\View\Model\ViewModel();
$viewModel->setTerminal(true);
$request = $event->getRequest();
$response = $event->getResponse();
$viewModel->setTemplate('browser-check/index/index.phtml');
//Replace the entire view
$event->setViewModel($viewModel);
$event->stopPropagation();
$response->setStatusCode(200);
return $viewModel;
}
};
$sharedEvents = $e->getApplication()->getEventManager()->getSharedManager();
$sharedEvents->attach('Zend\Mvc\Controller\AbstractController',
array('dispatch','dispatch.error'), $browserEventListener, 100);
The problem here is that you register your event listener on the dispatch event, which occurs after bootstrap and after route events. If the event listener triggered at route event cannot identify the route, you receive a 404 error page and the application lifecycle is terminated before any other dispatch event listener could be invoked.
In order to invoke your event listener before any routing is applied, you now have two options:
either register your event listener on bootstrap event with lower prio (e.g. lower than 10000)
or to register it on route listener with some higher priority, 10 should be enough
According to ZF2 doc page, onBoostrap() module methods are called with priority 10000 and onRoute() methods of \Zend\Mvc\ModuleRouteListener and \Zend\Mvc\RouteListener are called with priority 1 (higher the number higher the priority).
EDIT:
You should be doing something like this:
public function onBootstrap(MvcEvent $e)
{
/* ... all the default stuff here ... */
$this->registerBrowserCheckEvent($e);
}
private function registerBrowserCheckEvent(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$browserEventListener = function ($event) {
$browser = new \BrowserCheck\Service\BrowserCheck();
if (!$browser->isCompatible()) {
$viewModel = new \Zend\View\Model\ViewModel();
$viewModel->setTerminal(true);
$request = $event->getRequest();
$response = $event->getResponse();
$viewModel->setTemplate('browser-check/index/index.phtml');
//Replace the entire view
$event->setViewModel($viewModel);
$event->stopPropagation();
$response->setStatusCode(200);
return $viewModel;
}
};
$eventManager->attach(MvcEvent::EVENT_BOOTSTRAP, $browserEventListener, 100);
}
Also please notice that ZF2 uses PSR-2 (at least) and your code should follow this convention as well (mind the small differences between your code and mine).

ZF2 from any module redirect to module login

I study ZF2 and have problem with login process. I have two modules login and moduleExample.
Login module is based on http://samsonasik.wordpress.com/2012/10/23/zend-framework-2-create-login-authentication-using-authenticationservice-with-rememberme/
I can redirect moduleExample to login route with condition hasIdentity() in Controllers, but can I set redirecting to this module at one place? Controllers will probably be more. I've already tried in onBootstrap method (Module.php), but then it is redirected everywhere (in all modules).
Where I can do what I describe?
It is possible to handle the login redirection at one place, one way is to define a custom event which is called in the routing event chain. To do this, you have to add the handler in your Module.php (preferably in the authentication module):
class Module
{
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$sm = $e->getApplication()->getServiceManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
//attach event here
$eventManager->attach('route', array($this, 'checkUserAuth'), 2);
}
public function checkUserAuth(MvcEvent $e)
{
$router = $e->getRouter();
$matchedRoute = $router->match($e->getRequest());
//this is a whitelist for routes that are allowed without authentication
//!!! Your authentication route must be whitelisted
$allowedRoutesConfig = array(
'auth'
);
if (!isset($matchedRoute) || in_array($matchedRoute->getMatchedRouteName(), $allowedRoutesConfig)) {
// no auth check required
return;
}
$seviceManager = $e->getApplication()->getServiceManager();
$authenticationService = $seviceManager->get('Zend\Authentication\AuthenticationService');
$identity = $authenticationService->getIdentity();
if (! $identity) {
//redirect to login route...
$response = $e->getResponse();
$response->setStatusCode(302);
//this is the login screen redirection url
$url = $e->getRequest()->getBaseUrl() . '/auth/login';
$response->getHeaders()->addHeaderLine('Location', $url);
$app = $e->getTarget();
//dont do anything other - just finish here
$app->getEventManager()->trigger(MvcEvent::EVENT_FINISH, $e);
$e->stopPropagation();
}
}
}
what you tried is correct, so then you just need this little bit here
$controller = $e->getTarget();
$params = $e->getApplication()->getMvcEvent()->getRouteMatch()->getParams();
if(!$params['controller'] == 'your login conroller path e.g. RouteFolder/Controller/LoginControllerName'){
return $controller->redirect()->toRoute('your redirect route')
}
do a
print_r($params['controller'])
and see what it returns and you will understand what i mean
so the event onBoostrap wont redirect you if your current location is the controller where the user comes to login

FosUserBundle and custom user registration

I am trying to figure out the registration process of the FosUserBundle and have been unable to do so.
I want to be able to register a user manually using custom fields and have been unable to see that in the code.
I have the registerAction in FosUserBundle and following it anywhere does not show me where the information is actually stored in the database:
public function registerAction()
{
$form = $this->container->get('fos_user.registration.form');
$formHandler = $this->container->get('fos_user.registration.form.handler');
$confirmationEnabled = $this->container->getParameter('fos_user.registration.confirmation.enabled');
$process = $formHandler->process($confirmationEnabled);
if ($process) {
$user = $form->getData();
if ($confirmationEnabled) {
$this->container->get('session')->set('fos_user_send_confirmation_email/email', $user->getEmail());
$route = 'fos_user_registration_check_email';
} else {
$this->authenticateUser($user);
$route = 'fos_user_registration_confirmed';
}
$this->setFlash('fos_user_success', 'registration.flash.user_created');
$url = $this->container->get('router')->generate($route);
return new RedirectResponse($url);
}
return $this->container->get('templating')->renderResponse('FOSUserBundle:Registration:register.html.'.$this->getEngine(), array(
'form' => $form->createView(),
'theme' => $this->container->getParameter('fos_user.template.theme'),
));
}
How do I register a user manually?
Thanks
Have you read this in the FOSUserBundle docs?
Using the UserManager
Apparently the service UserManager has the responsibility to actually save and update the user, you could create your own UserManager by following the guide.
Edit: Symfony has incorporated the documentation for the FOSUserBundle into their own documentation, as so the new link for the documentation is:
https://symfony.com/doc/master/bundles/FOSUserBundle/index.html

Categories