I want to change the templating of the registration form in my project by extending the new twig layout. However it does not change. It doesnt show any errors, but I am still getting the original view of the form. I did everything I found in documentation, but it still wont change, why?
1) I extended the userBundle.
2) I made created the ApplicationSonataUserBundle and did this:
class ApplicationSonataUserBundle extends Bundle
{
/**
* {#inheritdoc}
*/
public function getParent()
{
return 'SonataUserBundle';
}
}
I made my new controller and overwrited the old one(I only changed the rendered layout):
<?php
namespace Application\Sonata\UserBundle\Controller;
use Sonata\UserBundle\Controller\RegistrationFOSUser1Controller as BaseController;
class Registration1Controller extends BaseController
{
public function registerAction()
{
$user = $this->container->get('security.context')->getToken()->getUser();
if ($user instanceof UserInterface) {
$this->container->get('session')->getFlashBag()->set('sonata_user_error', 'sonata_user_already_authenticated');
$url = $this->container->get('router')->generate('sonata_user_profile_show');
return new RedirectResponse($url);
}
$form = $this->container->get('sonata.user.registration.form');
$formHandler = $this->container->get('sonata.user.registration.form.handler');
$confirmationEnabled = $this->container->getParameter('fos_user.registration.confirmation.enabled');
$process = $formHandler->process($confirmationEnabled);
if ($process) {
$user = $form->getData();
$authUser = false;
if ($confirmationEnabled) {
$this->container->get('session')->set('fos_user_send_confirmation_email/email', $user->getEmail());
$url = $this->container->get('router')->generate('fos_user_registration_check_email');
} else {
$authUser = true;
$route = $this->container->get('session')->get('sonata_basket_delivery_redirect');
if (null !== $route) {
$this->container->get('session')->remove('sonata_basket_delivery_redirect');
$url = $this->container->get('router')->generate($route);
} else {
$url = $this->container->get('session')->get('sonata_user_redirect_url');
}
}
$this->setFlash('fos_user_success', 'registration.flash.user_created');
$response = new RedirectResponse($url);
if ($authUser) {
$this->authenticateUser($user, $response);
}
return $response;
}
$this->container->get('session')->set('sonata_user_redirect_url', $this->container->get('request')->headers->get('referer'));
return $this->container->get('templating')->renderResponse('MpShopBundle:Frontend:registration.html.'.$this->getEngine(), array(
'form' => $form->createView(),
));
}
}
3) I added new Application\Sonata\UserBundle\ApplicationSonataUserBundle(), to the AppKernel.
Did I miss anything? What can be the problem?
UPDATE :
Now I am getting this error: Compile Error: Namespace declaration statement has to be the very first statement in the script. but my namespace is the first statement isnt it?
Related
I am migrating an app from ZF2/3 to Laminas. I have moved the authentication from the Module.php bootstrap, to an aggregatelistener, and would like to redirect to a login page if the user is not logged in for certain routes. This worked fine originally, but i am having trouble after the migration - it is now redirecting 20 to 30 times and causing a "page is not redirecting properly" error.
My Module.php onBoostrap method:
class Module implements ConfigProviderInterface
{
/**
* #param $event
*/
public function onBootstrap(MvcEvent $event)
{
/** #var ApplicationInterface $application*/
$application = $event->getApplication();
/** #var TemplateMapResolver $templateMapResolver */
$templateMapResolver = $application->getServiceManager()->get(
'ViewTemplateMapResolver'
);
// Create and register layout listener
$listener = new LayoutListener($templateMapResolver);
$listener->attach($application->getEventManager());
//Create and register Authentication listener
$authenticationListener = new AuthenticationListener();
$authenticationListener->attach($application->getEventManager());
}
}
The AuthenticationListener class:
class AuthenticationListener extends AbstractListenerAggregate
{
/**
* #param EventManagerInterface $events
* #param int $priority
*/
public function attach(EventManagerInterface $events, $priority = 1)
{
$this->listeners[] = $events->attach(
MvcEvent::EVENT_DISPATCH,
[$this, 'userHasAuthentication']
);
}
/**
* #param MvcEvent $event
*/
public function userHasAuthentication(MvcEvent $event)
{
$authenticationService = $event->getApplication()->getServiceManager()->get(AuthenticationService::class);
if($authenticationService->hasIdentity() === false){
$event->stopPropagation(true);
// ? how to redirect
}
return true;
}
}
I have tried the following approaches to redirecting, and these still end up with the "not redirecting properly" result.
Inside AuthenticationListener::userHasAuthentication:
if($authenticationService->hasIdentity() === false){
$event->stopPropagation(true);
/**#var AbstractActionController $target*/
$target = $event->getTarget();
return $target->redirect()->toRoute('auth.login');
}
...or...
if($authenticationService->hasIdentity() === false){
$event->stopPropagation(true);
/**#var AbstractActionController $target*/
$target = $event->getTarget();
$response = $target->getResponse();
$response->getHeaders()->addHeaderLine('Location', '/login');
$response->setStatusCode(403);
$response->sendHeaders();
return $response;
}
What is the correct way of achieving this?
I think you get redirection loop, cause this listener is also triggered on /login page. You have to check the current route before redirecting.
public function userHasAuthentication(MvcEvent $e)
{
$routeMatch = $e->getRouteMatch();
if ($routeMatch) {
$routeName = $routeMatch->getMatchedRouteName();
if ($routeName !== 'login' && $routeMatch->getParam('loginRequired',true)) {
$auth = $e->getApplication()->getServiceManager()->get(AuthenticationServiceInterface::class);
if ($auth->hasIdentity() === false) {
$response = new \Laminas\Http\PhpEnvironment\Response();
$response->getHeaders()->addHeaderLine('Location', "/login");
$response->setStatusCode(302);
return $response;
}
}
}
}
Adding condition on route param 'loginRequired' allows you disable redirection for chosen paths adding 'loginRequired'=>false in 'defaults' section in route config.
BTW, if you use higher listener priority, or attach it do MvcEvent::ROUTE, you can display login page on every path by changing route match
public function userHasAuthentication(MvcEvent $e)
{
$routeMatch = $e->getRouteMatch();
if ($routeMatch) {
$routeName = $routeMatch->getMatchedRouteName();
if ($routeName !== 'login'
&& $routeName !== 'logout'
&& $routeMatch->getParam('loginRequired', true) !== false
) {
$auth = $e->getApplication()->getServiceManager()->get(AuthenticationServiceInterface::class);
if ($auth->hasIdentity() === false) {
$routeMatch->setParam('controller', LoginController::class);
$routeMatch->setParam('action', 'login');
if ($routeName !== 'home') {
$e->getResponse()->setStatusCode(401);
}
}
}
}
}
On loginAction add
if ($this->auth->hasIdentity()) {
$this->checkTourDismiss($this->auth->getIdentity());
if (isset($_SERVER['REQUEST_URI'])
&& !in_array($_SERVER['REQUEST_URI'], ['/', '/login'])
) {
$this->redirect()->toUrl($_SERVER['REQUEST_URI']);
} else {
$this->redirect()->toRoute('home');
}
}
in the end, so after logging in user stays on URL he started with.
I am building custom mvc framework in php in order to learn and when I am trying to submit my form with an mail that already exists in the database, my validation should prevent me to do so, instead I get this error:
Fatal error: Uncaught Error: Call to a member function findUserByEmail() on null in C:\xampp\htdocs\gacho\App\Controllers\UsersController.php:
UsersController.php
<?php
namespace App\Controllers;
use App\Models\User;
use Core\Controller;
class UsersController extends Controller
{
public function __construct($controller, $action)
{
parent::__construct($controller, $action);
$this->userModel = $this->load_model('User');
}
public function registerAction()
{
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$data = [
'email' => trim($_POST['email']),
];
}
if (empty($data['email'])) {
$data['email_err'] = "Please enter your email!!!";
} else {
if ($this->userModel->findUserByEmail($data['email'])) {
$data['email_err'] = "Email is already taken!";
}
}
}
User.php
<?php
namespace App\Models;
use Core\Database;
class User
{
private $db;
public function __construct()
{
$this->db = new Database();
}
public function findUserByEmail($email)
{
$this->db->query('SELECT * FROM users WHERE email = :email');
$this->db->bind(':email', $email);
$row = $this->db->single();
if ($this->db->rowCount() > 0) {
return true;
} else {
return false;
}
}
}
Controller.php:
<?php
namespace Core;
class Controller
{
protected $_controller;
protected $_action;
public $view;
public function __construct($controller, $action)
{
$this->_controller = $controller;
$this->_action = $action;
$this->view = new View();
}
protected function load_model($model)
{
$modelPath = 'App\Models\\' . $model;
if (class_exists($modelPath)) {
$this->{$model.'Model'} = new $modelPath();
}
}
}
I think the mistake is about $this->userModel , but I'm stuck and any help is appreciated.
The problem is that in __construct of UsersController you have:
$this->userModel = $this->load_model('User');
So you assign to userModel property the return value of load_model method.
load_model method doesn't return anything so $this->userModel is always set to NULL, doesn't matter if load_model succeeded or not.
You should just return new $modelPath(); in load_model if you want to assign it to a property by return value.
Also add throw new Exception($modelPath. 'not found'); at the end of load_model method to be sure it did load the model, and not just failed silently to find it.
Note that $this->userModel is not the same as $this->UserModel (case sensitive) and $modelPath = 'App\Models\\' . $model; - why \ after App, and two \ after Models?
I think you need to access your model in $this->UserModel, since User was passed into the load_model method.
I have opted out of using Laravel's built in User Authentication due to my application's requirements. We rely on a Third Party SSO to authenticate our users, and I was unable to get Socialite to work with their SSO, so I am having to custom build a Controller to handle the authentication process. The Controller is performing b-e-a-utifully up until the part when I need to redirect the user from the Callback Route & Controller to the Member Route & Controller. It won't redirect. Period. I have tried every method I know how to redirect to another route from within the controller and it will not work.
Here is my custom AuthController for Laravel 5.3:
<?php
namespace App\Http\Controllers;
use App\User;
use Curl\Curl;
use App\Http\Controllers\PhealController as Pheal;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Routing\Redirector;
class AuthController extends Controller
{
protected $curl;
private $data;
public function __construct ()
{
$this->curl = new Curl();
$this->pheal = new Pheal();
$this->data = [];
}
public function sendToSSO()
{
$url = env('EVE_SSO_LOGIN')."?response_type=code&redirect_uri=".env('EVE_CALLBACK_URL')."&client_id=".env('EVE_CLIENT_ID')."&scope=".env('EVE_SCOPES');
return redirect($url);
}
public function handleCallback(Request $request)
{
$this->curl->setHeader('Authorization', "Basic ". base64_encode(env('EVE_CLIENT_ID').":".env('EVE_SECRET')));
$this->curl->setHeader('Content-Type', "application/x-www-form-urlencoded");
$this->curl->setHeader('Host', "login.eveonline.com");
$this->curl->post('https://login.eveonline.com/oauth/token', [
'grant_type' => 'authorization_code',
'code' => $request->code
]);
$response = $this->curl->response;
if (isset($response->error)) {
throw new \Exception($response->error_description);
}
$this->data = [
'accessToken' => $response->access_token,
'refreshToken' => $response->refresh_token
];
$this->verifyToken();
}
public function verifyToken ()
{
$this->curl->setHeader('User-Agent', "David Douglas ddouglas#douglaswebdev.net");
$this->curl->setHeader('Authorization', "Bearer ". $this->data['accessToken']);
$this->curl->setHeader('Host', "login.eveonline.com");
$this->curl->get('https://login.eveonline.com/oauth/verify');
$response = $this->curl->response;
if (isset($response->error)) {
throw new \Exception($response->error_description);
}
$this->data['characterID'] = $response->CharacterID;
$this->data['characterName'] = $response->CharacterName;
$this->data['accessTokenExpire'] = $response->ExpiresOn;
try {
$characterInfo = $this->pheal->call('eve', 'CharacterInfo', ['characterID' => $this->data['characterID']])['result'];
} catch (\Exceoption $e) {
abort(404);
}
if (!isset($characterInfo['allianceID'])) {
abort(403, "Care Factor Alliance Members Only. Sorry :-(");
}
if ($characterInfo['allianceID'] !== env('CF-ALLIANCE-ID')) {
abort(403, "Care Factor Alliance Members Only. Sorry :-(");
}
$this->data['corporationID'] = $characterInfo['corporationID'];
$this->data['corporation'] = $characterInfo['corporation'];
$user = User::find($this->data['characterID']);
if ($user) {
$this->updateUserAndLogin($user);
} else {
$this->createNewUserAndLogin();
}
}
private function getData()
{
return $this->data;
}
public function createNewUserAndLogin()
{
dd('To be Created');
}
public function updateUserAndLogin($user)
{
$user->corporationID = $this->data['corporationID'];
$user->corporation = $this->data['corporation'];
$user->accessToken = $this->data['accessToken'];
$user->refreshToken = $this->data['refreshToken'];
$user->accessTokenExpire = $this->data['accessTokenExpire'];
$user->save();
//Auth::login($user);
return redirect('member/dashboard/');
}
}
I have also tried:
return redirect()->route('member.dashboard');
With no luck.
You mean the $this->createNewUserAndLogin()? Maybe trying return $this->updateUserAndLogin($user); and return $this->verifyToken(); so you return the response on the main method of the route?
in my current Silex project I would like to realize a login via Oauth and basic login both. For OAuth, I am using a Silex extension (https://github.com/gigablah/silex-oauth). Unfortunately, now I have problems with integrating the basic login.
My thoughts are that I have to create a custom user provider which provides both OAuth and password via DB, but I don't know how to realize it really.
At this point, I have a really ugly mixture of two User providers. For me, it is logic, but it will not work. I think I am off the track, so it would be really nice, if you can give me some tips - I am trying it for a few days now...
My user provider:
<?php
namespace Core;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\User;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Doctrine\DBAL\Connection;
class UserProvider implements UserProviderInterface
{
private $conn;
private $oauth;
public function __construct($oauth = null)
{
global $app;
if($oauth) { $this->oauth = $oauth; }
$this->conn = $app['db'];
}
/*public function loadAllUsers()
{
$users = $this->conn->executeQuery('SELECT * FROM users')->fetchAll();
$users_object = array();
foreach ($users as $user) {
if (!empty($user['username'])) {
$users_object[$user['username']] = array($user['password'], $user['firstname'], $user['lastname'], explode(',', $user['roles']));
}
}
$oauth = (array)$this->oauth;
print_r($oauth->users);
if (count($oauth['users']) > 0 ) {
print_r($this->oauth);
}
if ($this->oauth) {
if (count($oauth['users'])) {
return $this->oauth;
} else {
} return $users_object;
} else {
return $users_object;
}
}*/
public function loadUserByOAuthCredentials($token)
{
return $this->oauth->loadUserByOAuthCredentials($token);
}
public function loadUserByUsername($username)
{
if ($this->oauth->loadUserByUsername($username)) {
return $this->oauth->loadUserByUsername($username);
} else {
$stmt = $this->conn->executeQuery('SELECT * FROM users WHERE username = ?', array(strtolower($username)));
if (!$user = $stmt->fetch()) {
throw new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));
}
return new User($user['username'], $user['password'], explode(',', $user['roles']), true, true, true, true);
}
}
public function refreshUser(UserInterface $user)
{
if (!$user instanceof User) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
}
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class)
{
return $class === 'Symfony\Component\Security\Core\User\User';
}
}
Thank you in advance, if you need more info, please tell me.
thoras
I'm trying using annotatnions to build and validate zend forms.
But currently I recive an error when I open showformAction:
"Fatal error: Uncaught exception 'Zend\Form\Exception\InvalidElementException' with message 'No element by the name of [username] found in form' ..."
So below is my code. What I doing wrong ?
Entity\User.php
namespace Application\Model;
use Zend\Form\Annotation;
/**
* #Annotation\Hydrator("Zend\Stdlib\Hydrator\ObjectProperty")
* #Annotation\Name("user")
*/
class User
{
/**
* #Annotation\Attributes({"type":"text" })
* #Annotation\Validator({"type":"Regex","options":{"regex":"/^[a-zA-Z][a-zA-Z0-9_-]{1,19}/"}})
* #Annotation\Options({"label":"Username:"})
*/
public $username;
}
Controller\ProductsController.php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\Json\Json;
use Zend\View\Model\JsonModel;
use Zend\View\Model\ViewModel;
use Zend\Debug\Debug;
use Application\Entity\Products;
use Application\Entity\Category;
use Application\Form\ProductsForm;
use Doctrine\ORM\EntityManager;
use Application\Model\User;
use Zend\Form\Annotation\AnnotationBuilder;
class ProductsController extends AbstractActionController {
protected $albumTable;
protected $em;
protected $form;
public function savetodb($data) {
//code save to db ....
}
protected function getForm() {
$entity = new User();
$builder = new AnnotationBuilder();
$this->form = $builder->createForm($entity);
return $this->form;
}
public function showformAction() {
$viewmodel = new ViewModel();
$form = $this->getForm();
$request = $this->getRequest();
//disable layout if request by Ajax
$viewmodel->setTerminal($request->isXmlHttpRequest());
$is_xmlhttprequest = 1;
if (!$request->isXmlHttpRequest()) {
//if NOT using Ajax
$is_xmlhttprequest = 0;
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
//save to db <span class="wp-smiley emoji emoji-wink" title=";)">;)</span>
$this->savetodb($form->getData());
}
}
}
$viewmodel->setVariables(array(
'form' => $form,
// is_xmlhttprequest is needed for check this form is in modal dialog or not
// in view
'is_xmlhttprequest' => $is_xmlhttprequest
));
return $viewmodel;
}
public function validatepostajaxAction() {
$form = $this->getForm();
$request = $this->getRequest();
$response = $this->getResponse();
$messages = array();
if ($request->isPost()) {
$form->setData($request->getPost());
if (!$form->isValid()) {
$errors = $form->getMessages();
foreach ($errors as $key => $row) {
if (!empty($row) && $key != 'submit') {
foreach ($row as $keyer => $rower) {
//save error(s) per-element that
//needed by Javascript
$messages[$key][] = $rower;
}
}
}
}
if (!empty($messages)) {
$response->setContent(\Zend\Json\Json::encode($messages));
} else {
//save to db <span class="wp-smiley emoji emoji-wink" title=";)">;)</span>
$this->savetodb($form->getData());
$response->setContent(\Zend\Json\Json::encode(array('success' => 1)));
}
}
return $response;
}
}
Your annotation should be
/**
* #Annotation\Type("Zend\Form\Element\Text")
* #Annotation\Validator({"type":"Regex","options":{"regex":"/^[a-zA-Z][a-zA-Z0-9_-]{1,19}/"}})
* #Annotation\Options({"label":"Username:"})
*/