Create sql query in sonata admin - sql

I use sonata admin in my project. i created two admin classes exam and student. i want to create an action in exam class that shows all students that should pass the exam after creating a new exam, this is the sql query that i want:
"Select * from student,exam where student.codeAdministration=exam.codeAdministration"
examAdmin.php:
<?php
namespace Exam\ExamBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Validator\ErrorElement;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
class ExamAdmin extends Admin
{
////
protected function configureFormFields(FormMapper $formMapper)
{
//////
}
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
////
}
protected function configureListFields(ListMapper $listMapper)
{
/////
}
protected function configureShowField(ShowMapper $showMapper)
{
//////
}
}
i tried this query without putting the condition of WHERE but it does not work:
protected function configureListFields(ListMapper $listMapper)
{
$query = $this->modelManager->getEntityManager()->createQuery('SELECT s FROM Exam\ExamBundle\Entity\student s');
$listMapper
->add('student', 'sonata_type_model', array('required' => true, 'query' => $query))
}
How can i create this action with this query??
exam.php:
<?php
namespace Exam\ExamBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
class Exam
{
/**
* #var integer
*/
private $idExam
////////
/**
* #var \Examens\ExamensBundle\Entity\Administration
*/
private $codeAdministration;
//////
public function getIdExam()
{
return $this->idExam;
}
///////
public function setCodeAdministration(\Exam\ExamBundle\Entity\Administration $codeAdministration = null)
{
$this->codeAdministration = $codeAdministration;
return $this;
}
/**
* Get codeAdministration
*
* #return \Exam\ExamBundle\Entity\Administration
*/
public function getCodeAdministration()
{
return $this->codeAdministration;
}
///////
}

Related

symfony 4 string instead of UploadedFile in form collection entity with file type create

I have the following error: "Argument 1 passed to App\Service\FileUploader::upload() must be an instance of Symfony\Component\HttpFoundation\File\UploadedFile, string given"
I applied the solution found in this post but it did not change anything. Quite normal, it's not excactly the same error. Can anyone help me please ?
My goal here is to attach multiple documents to a company from the company screen.
I have been trying to solve the problem since yesterday morning. Now, it's time for me to make a break away from keyboard for 1 or 2 hours ...
Here is the code:
Document entity
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\DocumentRepository")
*/
class Document
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $fichier;
/**
* #var UploadedFile
*/
private $file;
// ...
}
Entreprise entity
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\EntrepriseRepository")
*/
class Entreprise
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Document", mappedBy="entreprise", orphanRemoval=true, cascade={"persist"})
*/
private $documents;
// ...
public function __construct()
{
$this->documents = new ArrayCollection();
}
// ...
public function getDocuments()
{
return $this->documents;
}
public function addDocument(Document $document)
{
if (!$this->documents->contains($document)) {
$this->documents[] = $document;
//...
}
return $this;
}
public function removeDocument(Document $document)
{
if ($this->documents->contains($document)) {
$this->documents->removeElement($document);
}
return $this;
}
}
Entreprise Form Typenamespace App\Form\Type;
use App\Entity\Entreprise;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
class EntrepriseType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('documents', CollectionType::class, [
'entry_type' => DocumentType::class,
'entry_options' => ['label' => false],
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
])
// ...
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Entreprise::class,
]);
}
}
Entreprise Controller
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\HttpFoundation\Request;
use App\Entity\Entreprise;
use App\Form\Type\EntrepriseType;
use App\Repository\EntrepriseRepository;
use App\Service\FileUploader;
class EntrepriseController extends AbstractController
{
/**
* #Route("/entreprise/{id}", name="entreprise_detail")
* #Route("/entreprise/new", name="entreprise_new")
*/
public function index(Entreprise $entreprise = null, Request $request, ObjectManager $manager, FileUploader $fileUploader)
{
if (!$entreprise) {
$entreprise = new Entreprise();
}
$formDetail = $this->createForm(EntrepriseType::class, $entreprise);
$formDetail->handleRequest($request);
if ($formDetail->isSubmitted() && $formDetail->isValid()) {
$this->setDefault($entreprise);
// Téléchargement des nouveaux documents rattachés à l'entreprise
$documents = $entreprise->getDocuments();
foreach ($documents as $document) {
if (!$document->getId()){
/** #var Symfony\Component\HttpFoundation\File\UploadedFile $file */
$file = $document->getFile();
$document->setFichier($fileUploader->upload($file));
}
}
// Mise à jour de la base de données
$manager->persist($entreprise);
$manager->flush();
return $this->redirectToRoute('entreprise_detail', ['id'=> $entreprise->getId()]);
}
return $this->render('entreprise/index.html.twig', [
'formDetail' => $formDetail->createView(),
'entreprise' => $entreprise,
]);
}
// ...
}
PS : Sorry if my english is not good enough but if you want, you can answer in french.
I had the same issue and solved it by removing the type casting in the getFile() and setFile() in the entity. I suppose this is located in your Document entity.
Look for:
public function getFile(): ?string
{
return $this->file;
}
public function setFile(string $file): self
{
$this->file = $file;
return $this;
}
and replace it with
public function getFile()
{
return $this->file;
}
public function setFile($file): self
{
$this->file = $file;
return $this;
}
This will make sure that the file property will have an Instance of the UploadedFile class instead of invoking the __toString method of the same class (due to casting of type to string).

FOSUserBundle - changes in default configuration, overriding some default settings

I am quite new in Symfony 2. I have to build an application in Symfony 2 (I'm using 2.8 and also latest version of FOSUser Bundle). Majority of work is done, although I have to do some changes in default security settings. I was looking for them for two days and I have only really foggy concept how this can be fixed. The supposed changes are following:
REGISTRATION - I have enabled confirmation by e-mail and I don't know how to make to the confirmation link expire after one hour and/or after one usage (one click). There is setting in config.yaml settting ttl, but only for password resseting.
REGISTRATION - Before confirming users are prevented from logging in and there is Symfony 2 Exception - Disabled Account working, rendering short message about it. Actually I have to set redirection to another page (I suppose template) to render custom message that 'this account is blocked...' and link to send another link with confirmation token (Am I right? The link in email is confirmation token?).
RESETTING - As mentioned before ttl for link (token?) ressetting password is set for one hour, but I don't know how to make it expire after one usage (one click).
I know how to override some template of FOSUser, but I have no clear idea which of files should I override to change these things.
I have noticed that my FOSUser uses Symfony 2 Exceptions files and if I have changed content of message in my Exception file, it has changed also on my page, but I don't know how to make it well and override it, adding all necessary features.
I was trying to override AuthenticationListener (from FOSUser) with use of Compiler Pass (http://symfony.com/doc/current/cookbook/service_container/compiler_passes.html), but I don't know if it worked, because any changes in overriden Listener were not visible. Actually I don't know if this is the file I should override.
I have check a few Stackoverflow questions, but I haven't found an answer.
FOSUser Bundle - Prevent Disabled users from logging in
This doesn't work for me, because users are prevented and I need only override message of exception and create redirection with another link sending confirmation one.
FOS user bundle authentication
I have tried to implement the solution pointed here, but it didn't work and I am not sure if I really need such a complicated solution.
Thanks for help in advance and I someone need to see my files, configuration just write and I will post here necessary ones.
I have finally figured all these things out. If someone has a similar problem i advise to read these topics in Symfony documentation:
Overriding FOSUser B controllers
Hooking into a controller
It turns out that for described features I need to override some files form FOSUser Bundle, sometimes Controller was enough, sometimes I needed to modify EventListener (actually I have even created my own event). There is more than one way.
The hardest part was one-click link for ressetting password. I have used a flag, which is set to false while sending an e-mail and set true while clicking on link to prevent from using link once more. The problem is, that Resetting Controller is 'executed' two times, so while clicking submit there was redirection, beacuse flag was true. I have added some counting in session in order to omit the part of code which checks the flag, when you hit the submit button (second usage of the Reset Method in Resetting Controller), but it prevented only from clicking submit second time, so actually you can not use the link two times, but you can see form two times, which is not an effect I wanted to reach, but is far better than nothing. If someone has an idea how to upgrade it I will be gratefull
<?php
namespace My\UserBundle\Controller;
use FOS\UserBundle\Controller\ResettingController as FOSResettingController;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\Event\GetResponseUserEvent;
use FOS\UserBundle\Event\FilterUserResponseEvent;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use My\UserBundle\Entity\User;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use My\UserBundle\UserEvents;
/**
* Controller managing the resetting of the password
*
* #author Thibault Duplessis <thibault.duplessis#gmail.com>
* #author Christophe Coevoet <stof#notk.org>
*/
class ResettingController extends FOSResettingController
{
/**
* Request reset user password: submit form and send email
*/
public function sendEmailAction(Request $request)
{
$username = $request->request->get('username');
/** #var $user UserInterface */
$user = $this->get('fos_user.user_manager')->findUserByUsernameOrEmail($username);
if (null === $user) {
return $this->render('FOSUserBundle:Resetting:request.html.twig', array(
'invalid_username' => $username
));
}
if ($user->isPasswordRequestNonExpired($this->container->getParameter('fos_user.resetting.token_ttl'))) {
return $this->render('FOSUserBundle:Resetting:passwordAlreadyRequested.html.twig');
}
if (null === $user->getConfirmationToken()) {
/** #var $tokenGenerator \FOS\UserBundle\Util\TokenGeneratorInterface */
$tokenGenerator = $this->get('fos_user.util.token_generator');
$user->setConfirmationToken($tokenGenerator->generateToken());
}
$this->get('fos_user.mailer')->sendResettingEmailMessage($user);
$user->setPasswordRequestedAt(new \DateTime());
$user->setPasswordRequestedClicked(false);
$this->get('fos_user.user_manager')->updateUser($user);
$_SESSION['views'] = 1;
return new RedirectResponse($this->generateUrl('fos_user_resetting_check_email',
array('email' => $this->getObfuscatedEmail($user))
));
}
/**
* Reset user password
*/
public function resetAction(Request $request, $token)
{
/** #var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */
$formFactory = $this->get('fos_user.resetting.form.factory');
/** #var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->get('fos_user.user_manager');
/** #var $dispatcher \Symfony\Component\EventDispatcher\EventDispatcherInterface */
$dispatcher = $this->get('event_dispatcher');
$user = $userManager->findUserByConfirmationToken($token);
//Here there is a reaction for using expired token (column confirmation token === null) - redirection to page with possibility of sending another one.
if (null === $user) {
return $this->redirectToRoute('fos_user_invalid_token_click');
}
if ($_SESSION['views'] == 1){
$event = new GetResponseUserEvent($user, $request);
$dispatcher->dispatch(UserEvents::RESETTING_RESET_CLICK_CHECK, $event);
if (null !== $event->getResponse()) {
return $event->getResponse();
} else {
$user->setPasswordRequestedClicked(true);
$userManager->updateUser($user);
$_SESSION['views']++;
$_SESSION['views']++;
}
} else {
$_SESSION['views']++;
}
if ($_SESSION['views'] == 5){
$event = new GetResponseUserEvent($user, $request);
$dispatcher->dispatch(UserEvents::RESETTING_RESET_CLICK_CHECK, $event);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
}
$event = new GetResponseUserEvent($user, $request);
$dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_INITIALIZE, $event);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
$form = $formFactory->createForm();
$form->setData($user);
$form->handleRequest($request);
if ($form->isValid()) {
$event = new FormEvent($form, $request);
$dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_SUCCESS, $event);
$userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
$url = $this->generateUrl('fos_user_profile_show');
$response = new RedirectResponse($url);
}
$dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
return $response;
}
$userManager->updateUser($user);
return $this->render('FOSUserBundle:Resetting:reset.html.twig', array(
'token' => $token,
'form' => $form->createView(),
));
}
public function InvalidTokenTtlMessageAction() {
return $this->render('UserBundle:Resetting:invalidTokenTtlRes.html.twig');
}
public function InvalidTokenClickMessageAction() {
return $this->render('UserBundle:Resetting:invalidTokenClickRes.html.twig');
}
}
My listener:
<?php
namespace My\UserBundle\EventListener;
use FOS\UserBundle\EventListener\ResettingListener as FOSResettingListener;
use FOS\UserBundle\FOSUserEvents;
use My\UserBundle\UserEvents;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\Event\GetResponseUserEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use My\UserBundle\Entity\User;
class ResettingListener extends FOSResettingListener
{
private $router;
private $tokenTtl;
public function __construct(UrlGeneratorInterface $router, $tokenTtl)
{
$this->router = $router;
$this->tokenTtl = $tokenTtl;
}
public static function getSubscribedEvents()
{
return array(
UserEvents::RESETTING_RESET_CLICK_CHECK => 'onResettingClickCheck',
FOSUserEvents::RESETTING_RESET_INITIALIZE => 'onResettingResetInitialize',
FOSUserEvents::RESETTING_RESET_SUCCESS => 'onResettingResetSuccess',
);
}
public function onResettingClickCheck(GetResponseUserEvent $event){
//checking if link hasn't expired due to its usage
if ($event->getUser()->isPasswordRequestedClicked() === true){
$event->setResponse(new RedirectResponse($this->router->generate('fos_user_invalid_token_click')));
}
}
public function onResettingResetInitialize(GetResponseUserEvent $event)
{
//checking if link hasn't expired due to exceeding token Ttl
if (!$event->getUser()->isPasswordRequestNonExpired($this->tokenTtl)) {
$event->setResponse(new RedirectResponse($this->router->generate('fos_user_invalid_token_ttl')));
}
}
public function onResettingResetSuccess(FormEvent $event)
{
/** #var $user \FOS\UserBundle\Model\UserInterface */
$user = $event->getForm()->getData();
$user->setConfirmationToken(null);
$user->setPasswordRequestedAt(null);
$user->setEnabled(true);
}
}
and my User entity:
<?php
namespace My\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
use My\BackendBundle\Entity;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* User
*
* #ORM\Table(name="user")
* #ORM\Entity(repositoryClass="My\UserBundle\Repository\UserRepository")
*/
class User extends BaseUser
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer", nullable = false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #Gedmo\Slug(fields={"username"})
* #ORM\Column(length=128, unique=true)
*/
private $slug;
/**
*
* #ORM\ManyToMany(targetEntity="\My\BackendBundle\Entity\Event", mappedBy="users")
* #ORM\JoinColumn(name="id", referencedColumnName="id", nullable=false)
* #ORM\OrderBy({"date"="ASC"})
*
*/
protected $events;
/**
* #var \Doctrine\Common\Collections\ArrayCollection $event_org
* #ORM\OneToMany(targetEntity="\My\BackendBundle\Entity\Event", mappedBy="user_org", cascade={"all"})
*/
protected $event_org;
/**
* #var \DateTime
* #ORM\Column(name="confirmation_token_requested_at", type="datetime")
*/
protected $confirmationTokenRequestedAt;
/**
* #var boolean
* #ORM\Column(name="password_requested_clicked", type="boolean", nullable=true)
*/
protected $passwordRequestedClicked;
public function __toString()
{
return $this->getUsername();
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
public function __construct()
{
parent::__construct();
$this->event_org = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add event
*
* #param \My\BackendBundle\Entity\Event $event
*
* #return User
*/
public function addEvent(\My\BackendBundle\Entity\Event $event)
{
$this->events[] = $event;
$event->addUser($this);
return $this;
}
/**
* Remove event
*
* #param \My\BackendBundle\Entity\Event $event
*/
public function removeEvent(\My\BackendBundle\Entity\Event $event)
{
$this->events->removeElement($event);
}
/**
* Get events
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getEvents()
{
return $this->events;
}
/**
* Set slug
*
* #param string $slug
*
* #return User
*/
public function setSlug($slug)
{
$this->slug = $slug;
return $this;
}
/**
* Get slug
*
* #return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* Add eventOrg
*
* #param \My\BackendBundle\Entity\Event $eventOrg
*
* #return User
*/
public function addEventOrg(\My\BackendBundle\Entity\Event $eventOrg)
{
$this->event_org[] = $eventOrg;
return $this;
}
/**
* Remove eventOrg
*
* #param \My\BackendBundle\Entity\Event $eventOrg
*/
public function removeEventOrg(\My\BackendBundle\Entity\Event $eventOrg)
{
$this->event_org->removeElement($eventOrg);
}
/**
* Get eventOrg
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getEventOrg()
{
return $this->event_org;
}
/**
* Set confirmationTokenRequestedAt
*
* #param \DateTime $confirmationTokenRequestedAt
*
* #return User
*/
public function setConfirmationTokenRequestedAt(\DateTime $date = null)
{
$this->confirmationTokenRequestedAt = $date;
return $this;
}
/**
* Gets the timestamp that the user requested a confirmation_token.
*
* #return null|\DateTime
*/
public function getConfirmationTokenRequestedAt()
{
return $this->confirmationTokenRequestedAt;
}
public function isConfirmationTokenNonExpired($ttl)
{
return $this->getConfirmationTokenRequestedAt() instanceof \DateTime &&
$this->getConfirmationTokenRequestedAt()->getTimestamp() + $ttl > time();
}
/**
* Set passwordRequestedClicked
*
* #param boolean $passwordRequestedClicked
*
* #return User
*/
public function setPasswordRequestedClicked($boolean)
{
$this->passwordRequestedClicked = (Boolean) $boolean;
return $this;
}
/**
* Get passwordRequestedClicked
*
* #return boolean
*/
public function getPasswordRequestedClicked()
{
return $this->passwordRequestedClicked;
}
/**
* Checks whether the user has used password request.
*
*
* #return Boolean true if the user is enabled, false otherwise
*/
public function isPasswordRequestedClicked() {
return $this->passwordRequestedClicked;
}
}
If someone would like to get code for remaining problems, please write me a message and I will provide it here :).
Resetting controller:
<?php
namespace My\UserBundle\Controller;
use FOS\UserBundle\Controller\ResettingController as FOSResettingController;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\Event\GetResponseUserEvent;
use FOS\UserBundle\Event\FilterUserResponseEvent;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use My\UserBundle\Entity\User;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use My\UserBundle\UserEvents;
class ResettingController extends FOSResettingController
{
public function sendEmailAction(Request $request)
{
$username = $request->request->get('username');
$user = $this->get('fos_user.user_manager')->findUserByUsernameOrEmail($username);
if (null === $user) {
return $this->render('FOSUserBundle:Resetting:request.html.twig', array(
'invalid_username' => $username
));
}
if ($user->isPasswordRequestNonExpired($this->container->getParameter('fos_user.resetting.token_ttl'))) {
return $this->render('FOSUserBundle:Resetting:passwordAlreadyRequested.html.twig');
}
if (null === $user->getConfirmationToken()) {
$tokenGenerator = $this->get('fos_user.util.token_generator');
$user->setConfirmationToken($tokenGenerator->generateToken());
}
$this->get('fos_user.mailer')->sendResettingEmailMessage($user);
$user->setPasswordRequestedAt(new \DateTime());
$user->setPasswordRequestedClicked(false);
$this->get('fos_user.user_manager')->updateUser($user);
$_SESSION['views'] = 1;
return new RedirectResponse($this->generateUrl('fos_user_resetting_check_email',
array('email' => $this->getObfuscatedEmail($user))
));
}
public function resetAction(Request $request, $token)
{
$formFactory = $this->get('fos_user.resetting.form.factory');
$userManager = $this->get('fos_user.user_manager');
$dispatcher = $this->get('event_dispatcher');
$user = $userManager->findUserByConfirmationToken($token);
//Here there is a reaction for using expired token (column confirmation token === null) - redirection to page with possibility of sending another one.
if (null === $user) {
return $this->redirectToRoute('fos_user_invalid_token_click');
}
if ($_SESSION['views'] == 1){
$event = new GetResponseUserEvent($user, $request);
$dispatcher->dispatch(UserEvents::RESETTING_RESET_CLICK_CHECK, $event);
if (null !== $event->getResponse()) {
return $event->getResponse();
} else {
$user->setPasswordRequestedClicked(true);
$userManager->updateUser($user);
$_SESSION['views']++;
$_SESSION['views']++;
}
} else {
$_SESSION['views']++;
}
if ($_SESSION['views'] == 5){
$event = new GetResponseUserEvent($user, $request);
$dispatcher->dispatch(UserEvents::RESETTING_RESET_CLICK_CHECK, $event);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
}
$event = new GetResponseUserEvent($user, $request);
$dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_INITIALIZE, $event);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
$form = $formFactory->createForm();
$form->setData($user);
$form->handleRequest($request);
if ($form->isValid()) {
$event = new FormEvent($form, $request);
$dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_SUCCESS, $event);
$userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
$url = $this->generateUrl('fos_user_profile_show');
$response = new RedirectResponse($url);
}
$dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
return $response;
}
$userManager->updateUser($user);
return $this->render('FOSUserBundle:Resetting:reset.html.twig', array(
'token' => $token,
'form' => $form->createView(),
));
}
public function InvalidTokenTtlMessageAction() {
return $this->render('UserBundle:Resetting:invalidTokenTtlRes.html.twig');
}
public function InvalidTokenClickMessageAction() {
return $this->render('UserBundle:Resetting:invalidTokenClickRes.html.twig');
}
}

Laravel Auth Custom Driver Error

FYI : I'm very new to Laravel and doing my best to learn it properly.
Working on an auth driver that uses a soap service to authenticate.
Error I get when trying to test with Auth::attempt()
Symfony \ Component \ Debug \ Exception \ FatalErrorException (E_COMPILE_ERROR)
Declaration of Project\Providers\AuthUserProvider::retrieveByToken() must be compatible with Illuminate\Auth\UserProviderInterface::retrieveByToken($identifier, $token)
Here is the driver...
<?php namespace Project\Providers;
use Illuminate\Auth\UserProviderInterface;
use Illuminate\Auth\GenericUser;
use Illuminate\Auth\UserInterface;
class AuthUserProvider implements UserProviderInterface {
/**
* External webservice for authentication
*/
private $webservice;
/**
* The user object.
*/
private $user;
/**
* Constructor
*
* #return void
*/
public function __construct(\Project\Webservice\AuthCheckApi $webservice)
{
$this->webservice = $webservice;
$this->user = null;
}
/**
* Retrieves a user by id
*
* #param int $identifier
* #return mixed null|array
*/
public function retrieveByID($identifier)
{
$this->user = is_null($this->user) ? $this->webservice->find($identifier) : $this->user;
return $this->user;
}
/**
* Tries to find a user based on the credentials passed.
*
* #param array $crendtials username|password
* #return mixed bool|UserInterface
*/
public function retrieveByCredentials(array $credentials)
{
if(!$user = $this->webservice->byusername($credentials['username'],$credentials['password'])) return false;
return new GenericUser($user);
}
/**
* Validates the credentials passed to the ones in webservice.
*
* #param UserInterface $user
* #param array $credentials
* #return bool
*/
public function validateCredentials(\Illuminate\Auth\UserInterface $user, array $credentials)
{
$validated = $this->webservice->validateCredentials($user,$credentials['username']);
return true;
}
/**
* Needed by Laravel 4.1.26 and above
*/
public function retrieveByToken()
{
return true;
}
/**
* Needed by Laravel 4.1.26 and above
*/
public function updateRememberToken()
{
return false;
}
}
Thanks for any help.
You are implementing the UserProviderInterface so you need to add the complete definition of all functions of the interface, here you are forgetting the arguments for the last two function
public function retrieveByToken($identifier, $token)
{
}
public function updateRememberToken($user, $token)
{
}

Zend Framework 2 - Service method require as parameter InputFilter

I have a bit OOD question.
I have service:
namespace Front\Service\Course;
use Front\ORM\EntityManagerAwareInterface;
use Zend\Http\Request;
use Zend\InputFilter\InputFilter;
use Front\InputFilter\Course\CreateFilter;
class Create implements EntityManagerAwareInterface
{
/**
* #var \Doctrine\Orm\EntityManager
*/
protected $entityManager = null;
public function create(CreateFilter $createFilter)
{
if (!$createFilter->isValid()) return false;
/* #var $courseRepository \Front\Repositories\CourseRepository */
$courseRepository = $this->getEntityManager()->getRepository('Front\Entities\Course');
$course = $courseRepository->findByName($createFilter->getCourse());
}
/* (non-PHPdoc)
* #see \Front\ORM\EntityManagerAwareInterface::getEntityManager()
*/
public function getEntityManager()
{
return $this->entityManager;
}
/* (non-PHPdoc)
* #see \Front\ORM\EntityManagerAwareInterface::setEntityManager()
*/
public function setEntityManager(\Doctrine\ORM\EntityManager $entityManager)
{
$this->entityManager = $entityManager;
return $this;
}
}
And controller :
class CreateController extends \Zend\Mvc\Controller\AbstractController
{
public function onDispatch(MvcEvent $e)
{
$jsonModel = new JsonModel();
/* #var $courseCreateService \Front\Service\Course\Create */
$courseCreateService = $this->getServiceLocator()->get('Front\Service\Course\Create');
$courseCreateFilter = new CreateFilter();
$courseCreateFilter->setData($this->params()->fromPost());
if (!$courseCreateFilter->isValid()) {
$jsonModel->setVariable('status', 0);
$jsonModel->setVariable('message', $courseCreateFilter->getMessages());
return;
}
$courseCreateService->create($courseCreateFilter);
}
}
By service method declaration :
public function create(CreateFilter $createFilter)
i force user of the Service to use CreateFilter container which derived from Zend/InputFilter every time when he want to create new Course.
My question is: Might it be better when i will send to the service layer not the Typed object but simple value?
On example in my case it is might looks like:
public function create($courseName)
My CreateFilter looks like:
class CreateFilter extends InputFilter
{
public function __construct()
{
$input = new Input('name');
$validatorChain = new ValidatorChain();
$validatorChain->addValidator(new StringLength(array('max'=>60)))
->addValidator(new NotEmpty());
$input->setRequired(true)->setValidatorChain($validatorChain);
$this->add($input);
}
/**
* #return string | null
*/
public function getCourse()
{
return $this->getValue('name');
}
}
If you provide a concrete class name as you're doing now, you're forever tied to a concrete implementation of the class or one derived from it. If you decide later that you want to use a different class entirely, you have to refactor your service class code, whereas with an interface, you only need to implement it in your new class and your service will continue to work without any changes.
Without any interface at all, your service class would have to do extra checks to first see if it's an object and then if it implements the method you're expecting before it can even begin doing its job. By requiring an interface you remove the uncertainty, and negate the need for checks.
By providing an interface you create a contract between your methods and the classes they're expecting as arguments without restricting which classes may enter into the contract. All in all, contract by interface is preferable to contract by class name, but both are preferable to no contract at all.
I usually bind my entities to my form, so they are populated with the data from the form. This way, you inject the entity to your service and imho that's much cleaner. The service should not be aware of how you got your data.
My "admin" controller for an entity Bar usually is injected with three objects: the repository (to query objects), the service (to persist/update/delete objects) and the form (to modify objects for the user). A standard controller is then very CRUD based and only pushes entities to the service layer:
<?php
namespace Foo\Controller;
use Foo\Repository\Bar as Repository;
use Foo\Form\Bar as Form;
use Foo\Service\Bar as Service;
use Foo\Entity\Bar as Entity;
use Foo\Options\ModuleOptions;
use Zend\Mvc\Controller\AbstractActionController;
class BarController extends AbstractActionController
{
/**
* #var Repository
*/
protected $repository;
/**
* #var Service
*/
protected $service;
/**
* #var Form
*/
protected $form;
/**
* #var ModuleOptions
*/
protected $options;
public function __construct(Repository $repository, Service $service, Form $form, ModuleOptions $options = null)
{
$this->repository = $repository;
$this->service = $service;
$this->form = $form;
if (null !== $options) {
$this->options = $options;
}
}
public function getService()
{
return $this->service;
}
public function getRepository()
{
return $this->repository;
}
public function getForm()
{
return $this->form;
}
public function getOptions()
{
if (null === $this->options) {
$this->options = new ModuleOptions;
}
return $this->options;
}
public function indexAction()
{
$bars = $this->getRepository()->findAll();
return array(
'bars' => $bars,
);
}
public function viewAction()
{
$bar = $this->getBar();
return array(
'bar' => $bar,
);
}
public function createAction()
{
$bar = $this->getBar(true);
$form = $this->getForm();
$form->bind($bar);
if ($this->getRequest()->isPost()) {
$data = $this->getRequest()->getPost();
$form->setData($data);
if ($form->isValid()) {
// Bar is populated with form data
$this->getService()->create($bar);
return $this->redirect()->toRoute('bar/view', array(
'bar' => $bar->getId(),
));
}
}
return array(
'form' => $form,
);
}
public function updateAction()
{
$bar = $this->getBar();
$form = $this->getForm();
$form->bind($bar);
if ($this->getRequest()->isPost()) {
$data = $this->getRequest()->getPost();
$form->setData($data);
if ($form->isValid()) {
$this->getService()->update($bar);
return $this->redirect()->toRoute('bar/view', array(
'bar' => $bar->getId(),
));
}
}
return array(
'bar' => $bar,
'form' => $form,
);
}
public function deleteAction()
{
if (!$this->getRequest()->isPost()) {
$this->getRequest()->setStatusCode(404);
return;
}
$bar = $this->getBar();
$this->getService()->delete($bar);
return $this->redirect()->toRoute('bar');
}
protected function getBar($create = false)
{
if (true === $create) {
$bar = new Entity;
return $bar;
}
$id = $this->params('bar');
$bar = $this->getRepository()->find($id);
if (null === $bar) {
throw new Exception\BarNotFoundException(sprintf(
'Bar with id "%s" not found', $id
));
}
return $bar;
}
}
I made a gist file on Github with this full code (it's better readable) and the service. The service relies on the interface, so you can even swap out the entity object by another one having the same interface.
Check the full thing out here: https://gist.github.com/juriansluiman/5472787
Thanks all for answering, owing to answers and analyzing, i have reached conclusion which most applicable for my situation. I agree that Service in my case should not wait concrete object, it is should wait an abstraction with getCourse method.
And i completely agree with "Crisp" answer:
All in all, contract by interface is preferable to contract by class name, but both are preferable to no contract at all.
So i need to extract Interface with one method
getCourse
or
getName
, and remove
if (!$createFilter->isValid()) return false;
so Interface:
interface CourseInterface
{
/**
* #return String
**/
public function getName();
}
and Service:
class Create implements EntityManagerAwareInterface
{
/**
* #var \Doctrine\Orm\EntityManager
*/
protected $entityManager = null;
/**
* #param CourseInterface $course
* #param UserInterface $creator
*/
public function create(CourseInterface $course)
{
$courseEntity = new Course();
$courseEntity->setName($course->getName());
$this->entityManager->persist($courseEntity);
$this->entityManager->flush();
.....
Thanks all.

Adding custom data type (geometry) in Doctrine 2.1.7. Method canRequireSQLConversion() is not called

I am trying to add Geometry type to Doctrine. My Doctrine DBAL version and ORM versions are 2.1.7.
I tried to follow the instructions here:
Doctrine 2 Types - Custom Mapping Types.
I successfully created the new datatype, but I have problems with convertToPHPValueSQL method. I want function ST_AsText(' .. ') to always be called when getting the geometry column from database (database is PostgreSQL 9.1 + PostGIS 2.0.0).
Doctrine DBAL 2.1 documentation says like this:
The job of Doctrine-DBAL is to transform your type into SQL
declaration. You can modify the SQL declaration Doctrine will produce.
At first, you must to enable this feature by overriding the
canRequireSQLConversion method:
<?php
public function canRequireSQLConversion()
{
return true;
}
Then you override the methods convertToPhpValueSQL and
convertToDatabaseValueSQL :
<?php
public function convertToPHPValueSQL($sqlExpr, $platform)
{
return 'MyMoneyFunction(\''.$sqlExpr.'\') ';
}
public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
{
return 'MyFunction('.$sqlExpr.')';
}
Now we have to register this type with the Doctrine Type system and
hook it into the database platform:
<?php
Type::addType('money', 'My\Project\Types\MoneyType');
$conn->getDatabasePlatform()->registerDoctrineTypeMapping('MyMoney', 'money');
I did like this (lot of code is placeholder code, but if I did something stupid, all advice is welcome):
<?php
namespace Minupeenrad\Types;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* Class for database column "geometry".
*
* #author Rauni Lillemets
*/
class GeometryType extends Type {
const GEOMETRY = 'geometry';
const SRID = 3301;
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform) {
return 'geometry';
}
//Should create WKT object from WKT string. (or leave as WKT string)
public function convertToPHPValue($value, AbstractPlatform $platform) {
return $value; //+
}
//Should create WKT string from WKT object. (or leave as WKT string)
public function convertToDatabaseValue($value, AbstractPlatform $platform) {
return $value; //+
}
public function getName() {
return self::GEOMETRY;
}
public function canRequireSQLConversion() {
return true;
}
//Should give WKT
public function convertToPHPValueSQL($sqlExpr, $platform) {
return 'ST_AsText(\''.$sqlExpr.'\') '; //+
}
//Should create WKB
public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform) {
return 'ST_GeomFromText(\''.$sqlExpr.'\', '.self::SRID.')'; //+
}
}
Now I added Entity that uses this column:
<?php
namespace Minupeenrad\Entities;
/**
* Field
*
* #author Rauni Lillemets
* #Entity
* #Table(name="myfields.fields")
*/
class Field extends GeometryObject {
/**
* #Id
* #Column(type="integer")
* #GeneratedValue
*/
private $id;
/**
* #ManyToOne(targetEntity="User")
*/
private $user;
/**
* #Column(type = "string", length = "40")
*/
private $fieldNumber;
public function getId() {
return $this->id;
}
public function getUser() {
return $this->user;
}
public function setUser($user) {
$this->user = $user;
}
public function getFieldNumber() {
return $this->fieldNumber;
}
public function setFieldNumber($fieldNumber) {
$this->fieldNumber = $fieldNumber;
}
}
?>
But if I do like this:
$entity = $em->find('\Minupeenrad\Entities\Field', 1);
Doctrine does SQL request to database like this:
SELECT t0.id AS id1, t0.fieldNumber AS fieldnumber2, t0.geometry AS geometry3, t0.user_id AS user_id4
FROM myfields.fields t0
WHERE t0.id = ?
Doctrine does not use my convertToPHPValueSQL method, although canRequireSQLConversion() returns true. Furthermore, I added some debug code to see if canRequireSQLConversion() is even called, and it is not called. What am I doing wrong?
PS: I tried to search Stack Overflow, but I only came up with GIS extension for Doctrine 2, which links to Doctrine 2.1.x manual that I already read.
EDIT: I will read here: http://docs.doctrine-project.org/en/latest/cookbook/advanced-field-value-conversion-using-custom-mapping-types.html
EDIT2: Fixed function getSqlDeclaration(), that was wrong in my code. Added comments.
It seems like a more complete tutorial.
Found the answer.
In Doctrine 2.1.7, if I used $em->find(), eventually BasicEntityPersister()_getSelectColumnSQL() was called. It has following code: (taken from https://github.com/doctrine/doctrine2/blob/2.1.x/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php)
/**
* Gets the SQL snippet of a qualified column name for the given field name.
*
* #param string $field The field name.
* #param ClassMetadata $class The class that declares this field. The table this class is
* mapped to must own the column for the given field.
* #param string $alias
*/
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
{
$columnName = $class->columnNames[$field];
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform);
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
$this->_rsm->addFieldResult($alias, $columnAlias, $field);
return "$sql AS $columnAlias";
}
This code obviously does not respect method "canRequireSQLConversion"
In latest Doctrine version, 2.3.1 (see https://github.com/doctrine/doctrine2/blob/2.3/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php):
/**
* Gets the SQL snippet of a qualified column name for the given field name.
*
* #param string $field The field name.
* #param ClassMetadata $class The class that declares this field. The table this class is
* mapped to must own the column for the given field.
* #param string $alias
*/
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
{
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias)
. '.' . $this->quoteStrategy->getColumnName($field, $class, $this->_platform);
$columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]);
$this->_rsm->addFieldResult($alias, $columnAlias, $field);
if (isset($class->fieldMappings[$field]['requireSQLConversion'])) {
$type = Type::getType($class->getTypeOfField($field));
$sql = $type->convertToPHPValueSQL($sql, $this->_platform);
}
return $sql . ' AS ' . $columnAlias;
}
So the answer is to update my ORM.