Correct way to retrieve mails by IMAP in symfony2 - symfony

I have to develop simple mail client in symfony2 using IMAP. Im wondering what is best way to retrieve messages from server (lets take a gmail as example)?
I did something like this:
public function indexAction($name)
{
$user = 'adress#gmail.com';
$password = 'password';
$mailbox = "{imap.gmail.com:993/imap/ssl}INBOX";
$mbx = imap_open($mailbox , $user , $password);
$ck = imap_check($mbx);
$mails = imap_fetch_overview($mbx,"1:5");
return $this->render('HtstMailBundle:Mail:index.html.twig',array('name'=>$name,'mail'=>$mails));
}
is this right way, or not? It works, but is it compatible with symfony "standards"?

This has nothing to do with symfony "standards". But you can make your code more OOP if you move all login to a service class and use symfony DepencyInjection to create and get your service:
public function indexAction($name)
{
$user = 'adress#gmail.com';
$password = 'password';
$mailbox = "{imap.gmail.com:993/imap/ssl}INBOX";
$mails = $this->get("mail.checker")->receive($user, $password, $mailbox);
return $this->render('HtstMailBundle:Mail:index.html.twig',array('name'=>$name,'mail'=>$mails));
}
Class declaration:
class MailChecker
{
public function receive($user, $password, $mailbox)
{
...imap_check()...
}
}
service declartion:
services:
mail.checker:
class: Project\YourBundle\Service\MailChecker

You can also use this Symfony bundle for that and use it as a service. I is designed for old Symfony2 but tested it with Symfony 3 and works :)

Related

How to create a new FOSUserBundle user programatically using the same validation as on web form?

I am running a Symfony 2.8 based web app using FOSUserBundle to manage users. Creating new users with a web form is absolutely no problem.
Now I would like to add a feature to create new users with a REST api. Of course submitting username, password, email, etc. to a controller is no big deal:
public function registerAction(Request $request) {
$requestJson = json_decode($request->getContent(), true);
$username = $requestJson[JSON_KEY_USERNAME];
$email = $requestJson[JSON_KEY_MAIL];
$password = $requestJson[JSON_KEY_PASSWORD];
...
$this->registerUser($username, $email, $password);
...
}
private function registerUser($username, $email, $password, $locale, $timezone, $currency) {
$userManager = $this->get('fos_user.user_manager');
$emailExist = $userManager->findUserByEmail($email);
$userNameExists = $userManager->findUserByUsername($username);
if ($emailExist || $userNameExists)
return false;
$user = $userManager->createUser();
$user->setUsername($username);
$user->setEmail($email);
$user->setPlainPassword($password);
...
$user->setLocked(0);
$user->setEnabled(0);
$userManager->updateUser($user);
return true;
}
However, this performs no validation at all. If for example the username is empty an NotNullConstraintViolationException is thrown when persisting the user object.
Of course I could manually re-implement the same validation process which is used by the RegistrationForm (username not empty, not taken, no invalid characters, password min length, e-mail format, etc.) and pass back the same error messages but this would mean to reinvent the wheel.
Is it somehow possible to run the exact same validation which is used by the RegistrationForm?
Symfony validator can work independently. In a controller you can use validator service like this:
$violations = $this->get('validator')->validate($user, null, ['your_groups_here']);
// Or inject Symfony\Component\Validator\Validator\ValidatorInterface into a service.
It will return a ConstraintViolationListInterface, you can loop trough this object.
You can check FOSUserBundle validation groups here: https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/config/validation.xml

In Symfony2 how can I get a users full list of roles

I would like to pass the authenticated users list of roles to my front end apps, so I can use the same access control structure in the front and back end.
I was looking in the security / authentication classes as that is where the isGranted function are for me to do this
$this->container->get('security.context')->isGranted('ROLE_SUPER_ADMIN')
I can't find anything to get a list of roles though, is this not a supported feature?
nb: I don't want the entire role hierarchy, just the list of roles for the authenticated user
I ended up adding a new repository function and a service method to get this info.
MyProject/UserBundle/Entity/Repository/UserRepository
public function getRoles($userId)
{
$queryBuilder = $this->createQueryBuilder('u');
$queryBuilder
->select('u.id, u.roles AS user_roles, g.roles AS group_roles')
->leftJoin('u.groups', 'g')
->andWhere('u.id = :user_id')
->setParameter('user_id', $userId);
return $queryBuilder->getQuery()->getArrayResult();
}
MyProject/UserBundle/Service/UserService
public function getUserRoles($user)
{
$groupRoles = $this->repository->getRoles($user->getId());
$roles = array('user_roles' => array(), 'group_roles' => array());
foreach ($groupRoles as $groupRole) {
$roles['user_roles'] = array_merge($roles['user_roles'], $groupRole['user_roles']);
$roles['group_roles'] = array_merge($roles['group_roles'], $groupRole['group_roles']);
}
return $roles;
}
This gives me an array like this
"roles":{
"user_roles":[],
"group_roles":["ROLE_ADMIN","ROLE_ONE","ROLE_TWO","ROLE_BEST"]
}
Assuming you're using the Symfony security component, the user interface which your user class implements has this already included:
$user = $this->get('security.token_storage')->getToken()->getUser();
var_dump($user->getRoles());
http://api.symfony.com/3.1/Symfony/Component/Security/Core/User/UserInterface.html#method_getRoles

fosuserbundle ldap configuration for strange use case

I'm trying to create a fosuserbundle for a quite strange use case, which is mandatory requirement, so no space to diplomacy.
Use case is as follow:
users in a mongo db table populated by jms messages -no registration form
users log in by ldap
user record not created by ldap, after a successful login username is checked against mongodb document
Considering that ldap could successfully log in people that exhist in ldap but cannot access site (but login is still successful), what could be the best way to perform such authentication chain?
I was thinking about some possible options:
listen on interactive login event, but imho there's no way to modify an onSuccess event
create a custom AuthenticationListener to do another check inside onSuccess method
chain authentication using scheb two-factor bundle
any hint?
I've used Fr3DLdapBundle which can be incorporate with FOSUserBundle quite easily (I'm using the 2.0.x version, I have no idea if the previous ones will do the same or be as easy to set up).
In the LdapManager (by default) it creates a new user if one is not already on the database which is not what I wanted (and doesn't seem to be what you want) so I have added my own manager that checks for the presence of the user in the database and then deals with the accordingly.
use FR3D\LdapBundle\Ldap\LdapManager as BaseLdapManager;
.. Other use stuff ..
class LdapManager extends BaseLdapManager
{
protected $userRepository;
protected $usernameCanonicalizer;
public function __construct(
LdapDriverInterface $driver,
$userManager,
array $params,
ObjectRepository $userRepository,
CanonicalizerInterface $usernameCanonicalizer
) {
parent::__construct($driver, $userManager, $params);
$this->userRepository = $userRepository;
$this->usernameCanonicalizer = $usernameCanonicalizer;
}
/**
* {#inheritDoc}
*/
public function findUserBy(array $criteria)
{
$filter = $this->buildFilter($criteria);
$entries = $this->driver->search(
$this->params['baseDn'], $filter, $this->ldapAttributes
);
if ($entries['count'] > 1) {
throw new \Exception('This search can only return a single user');
}
if ($entries['count'] == 0) {
return false;
}
$uid = $entries[0]['uid'][0];
$usernameCanonical = $this->usernameCanonicalizer->canonicalize($uid);
$user = $this->userRepository->findOneBy(
array('usernameCanonical' => $usernameCanonical)
);
if (null === $user) {
throw new \Exception('Your account has yet to be set up. See Admin.');
}
return $user;
}

How to set session variables for all the controllers in Symfony2?

How do I create and access Symfony 2 session variables in my controllers.
I used like this.
$session = new Session();
$session->start();
$session->set('loginUserId',$user['user_id']);
I want to know how to use the above session variable in all my controllers to access.
One way of using Sessions in Symfony in controller is:
setting:
$this->get('session')->set('loginUserId', $user['user_id']);
getting:
$this->get('session')->get('loginUserId');
If you use standard framework edition
From the docs:
Symfony sessions are designed to replace several native PHP functions.
Applications should avoid using session_start(),
session_regenerate_id(), session_id(), session_name(), and
session_destroy() and instead use the APIs in the following section.
and:
While it is recommended to explicitly start a session, a sessions will
actually start on demand, that is, if any session request is made to
read/write session data.
So sessions is started automatically and can be accessed e.g. from controllers via:
public function indexAction(Request $request)
{
$session = $request->getSession();
...
}
or:
public function indexAction()
{
$session = $this->getRequest()->getSession();
// or
$session = $this->get('session');
...
}
than:
// store an attribute for reuse during a later user request
$session->set('foo', 'bar');
// get the attribute set by another controller in another request
$foobar = $session->get('foobar');
// use a default value if the attribute doesn't exist
$filters = $session->get('filters', array());
http://symfony.com/doc/current/components/http_foundation/sessions.html
use Symfony\Component\HttpFoundation\Session\Session;
$session = new Session();
$session->start();
// set and get session attributes
$session->set('name', 'Drak');
$session->get('name');
// set flash messages
$session->getFlashBag()->add('notice', 'Profile updated');
// retrieve messages
foreach ($session->getFlashBag()->get('notice', array()) as $message) {
echo '<div class="flash-notice">'.$message.'</div>';
}

how to get the session variable in the view in symfony2

Thanks for your valuable suggestions
i have created a login system where i want to store the id's of users in session variables
this is my controller for login system
use Symfony\Component\HttpFoundation\Session\Session;
class successController extends Controller
{
public function successAction(Request $request)
{
--some code for form--
$repository = $em->getRepository('RepairStoreBundle:users');
$query = $repository->auth($name,$password);
$error="sorry invalid username or password";
if($query== false)
{
return $this->render('RepairLoginBundle:login:login.html.php', array(
'form' => $form->createView(),'error'=>$error,));
}
else
{
$role=$query[0]['role'];
$id=$query[0]['id'];
if($role == 1)
{
$session = new Session();
$session->start();
$session->set('id',$id);
$result=$repository->display();
return $this->render('RepairLoginBundle:login:success.html.php',array('result'=>$result,));
}
else
{
$session = new Session();
$session->start();
$session->set('id',$id);
$res= $repository->edit($id);
return $this->render('RepairLoginBundle:login:user.html.php',array('res'=>$res));
}
}
}
}
when admin logins with role=1 it will render to success.html.php
in this view how can i get the session variable which i have set in the controller.
i have used $session->get('id');
it is giving me server error please help with this
Upfront Authentication should better be done with the Security Component in Symfony2.
Read more about it in The Book - Security. You should probably also take a look at FOSUserBundle
Accessing the session from a PHP template in symfony2:
echo $app->getSession()->get('whatever');
Session Handling
There is an article in the official documentation:
Components/HttpFoundation - Session Data Management
The API documentation for the Session Component can be found here:
http://api.symfony.com/master/Symfony/Component/HttpFoundation/Session/Session.html
In the symfony2 standard-edition you can get the session from within a controller with:
$session = $this->getRequest()->getSession();
As you already have the request as an argument in successAction you could access the session with:
$session = $request->getSession();
Set a value with ( $value needs to be serializable ):
$session->set('key',$value);
Get a value with:
$session->get('key');
Saving (and closing) the session can be done with:
$session->save();
You should also loook at the SessionBag class.
you create a SessionBag and register it with the session. see:
Symfony API
In the registered SessionBag - which implements AttributeBagInterface - you can get and set your key/value's as desired.
TIP: If you want to get the current User and you have a container aware controller ( container injected )
you can use:
$user = $this->container->get('security.context')->getToken()->getUser();
if you are extending Symfony's Controller class in the standard-edition - the shorter way is:
$user = $this->get('security.context')->getToken()->getUser();
or even shorter (Symfony > 2.1.x):
$user = $this->getUser();
Alternative ( If your controller is not container aware ):
Define the controller as a service and inject #security.context:
YAML:
# src/Vendor/YourBundle/Resources/config/services.yml
services:
my.controller.service:
class: Vendor\YourBundle\Controller\successController
arguments: ["#security.context"]
Vendor\YourBundle\Controller\successController:
protected $securityContext;
public function __construct(SecurityContextInterface $securityContext)
{
$this->securityContext = $securityContext;
}
then in your action:
$user = $this->securityContext->getToken()->getUser();
Note:: you have to use the service in your routing aswell if you choose the controller-as-service variant. example routing.yml :
[...]
route_name:
pattern: /success
defaults: { _controller: my.controller.service:successAction }
[...]
[...]
Note... you can also inject the session with "#session"
# src/Vendor/YourBundle/Resources/config/services.yml
[...]
arguments: ["#security.context","#session"]
Note injecting the whole container is resource-heavy. advanced developers inject their needed services one-by-one and not the whole container.
Tip: Normally Controller classes are written with a capital first letter - example: *S*uccessController
General TIP: You have unnecessary dublicate code in your example:
// 'if' and 'else' execute the same stuff here
// result: dublicate code = more code = harder to read
if($role == 1)
{
$session = new Session();
$session->start();
[...]
}
else
{
$session = new Session();
$session->start();
[...]
}
should better be ...
// better: put this stuff before the if/else statement
$session = new Session();
$session->start();
if($role == 1)
{
[...]
}
else
{
[...]
}

Resources