I've got a problem with Assert/Callback validation. I used this as a sample for my code, but Symfony just ignores the validation function. This is the relevant part of my entity code
namespace Vendor\Bundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo; // gedmo annotations
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\ExecutionContext;
/**
* #Assert\Callback(methods={"isValidFirma"})
* #ORM\Entity(repositoryClass="Vendor\Bundle\Entity\UserProfileRepository")
* #ORM\Table(name="user_profile")
*/
class UserProfile
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
//...
public function isValidFirma(ExecutionContext $context){
$context->addViolationAtSubPath('Firma', 'Company name must be present', array(), null);
// as of sf 2.3 use addViolationAt() instead [reference: https://github.com/propelorm/PropelBundle/issues/234 ]
}
//...
}
isValidFirma is never invoked. I tried validation.yml file instead of annotation as well, no success. I cleared the cache about fifty times, after every change, didn't help either. What could be the problem?
The solution. The problem was in used validator groups. The assert validator has to be a part of that group, or else it wont trigger.
This piece of code in form class file was the culprit:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$vg = array('my-profile');
$resolver->setDefaults(array(
'validation_groups' => $vg
));
}
changing the line with assert to
* #Assert\Callback(methods={"isValidFirma"}, groups={"my-profile"})
did the trick.
Related
// This is my entity class object
use Doctrine\ORM\Mapping as ORM;
class PayOrder {
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string",unique=true)
*/
private $pay_no;
};
// I use it in my function, this is the Repository
use Doctrine\ORM\EntityManager;
use Exception;
use Psr\Container\ContainerInterface;
use Doctrine\ORM\Mapping;
class PayOrderRepository extends \Doctrine\ORM\EntityRepository {
public function get( PayOrder $payOrder ) {
$pay_no=$payOrder->getPayNo();
// It will occurs a exception, how to fix it, any one can help me?
return $this->findBypayno($pay_no);
}
};
Besides that, I can't find the document to fix the problem.
I want to use the field name pay_no, and I want to use the repository
findbyxxx, but I do not how to use it correctly.
Change your property name to $payNo.
Probably in your entity look like that;
//...
/**
* #ORM\Column(type="string", length=255)
*/
$pay_no
//....
Change it like that;
//...
/**
* #ORM\Column(name="pay_no", type="string", length=255)
*/
$payNo
//....
After that,
Remove old getter/setter for $pay_no
For Symfony2 run app/console doctrine:generate:entities
For Symfony4 run bin/console make:entity --regenerate
Goodluck. If you have any question or blocker please write me.
Or just use
$this->findBy(['pay_no' => $payOrder->getPayNo());
The findByX method are just intercepted method calls - see line up 177 to 179 that are transformed to findBy calls.
I try generate CRUD controllers for my entities.
For example I wanna generate CRUD controller for AppBundle\Entity\User\User:
namespace AppBundle\Entity\User;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\Group;
/**
* #ORM\Entity
* #ORM\Table(name="user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
Generate entities:
$ app/console generate:doctrine:entities AppBundle
Generate crud:
$ app/console doctrine:generate:crud --entity=AppBundle:User\User
This command generete follow controller:
class UserController extends Controller
{
/**
* Lists all User\User entities.
*
* #Route("/", name="user_user_index")
* #Method("GET")
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$user\Users = $em->getRepository('AppBundle:User\User')->findAll();
return $this->render('user/user/index.html.twig', array(
'user\Users' => $user\Users,
));
}
/**
* Finds and displays a User\User entity.
*
* #Route("/{id}", name="user_user_show")
* #Method("GET")
*/
public function showAction(User $user\User)
{
return $this->render('user/user/show.html.twig', array(
'user\User' => $user\User,
));
}
}
What the $user\Users? Symfony 2.8!
Maybe I can't use more directories in the Entity folder?
if you used the same namespace in your CRUD generation command as you have in this question, I expect that symfony is getting confused.
you have used:
AppBundle\Entity\User\User
note the extra \User.
If this isnt a typo, your entity should reside in the base Entity directory. The unusual path has probably confused it.
One would have thought however, that the generate command should have validated the string first.
According to Symfony docs it should be possible to use a NotEqualTo constraint with objects
value
type: mixed [default option]
This option is required. It defines the value to compare to. It can be a string, number or object.
I have the following entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\UniqueConstraint;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\NotEqualTo;
/**
* Class Template
* #ORM\Entity(repositoryClass="NoteRepository")
* #ORM\Table(uniqueConstraints={#UniqueConstraint(name="note_unique",columns={"from_id", "to_id"})})
*/
class Note
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
* #var $id int
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Template")
* #var $from Template
* #NotBlank()
* #NotEqualTo(value="$to")
*/
protected $from;
/**
* #ORM\ManyToOne(targetEntity="Template")
* #NotBlank()
* #var $to Template
*/
protected $to;
/**
* #ORM\Column(type="text")
* #var $notes string
*/
protected $notes;
}
I want to avoid getting $from == $to, how can I configure the constraint to use an instance of the class Template at validation time or more generrally how can I configure the constraint to use an object
Right now if a dump the values that the validator is receiving
class NotEqualToValidator extends AbstractComparisonValidator
{
/**
* {#inheritdoc}
*/
protected function compareValues($value1, $value2)
{
var_dump($value1);
var_dump($value2);
return $value1 != $value2;
}
}
I get
object(AppBundle\Entity\Template)
string '$to' (length=3)
Okay, despite Symfony docs states to be possible pass object to NotEqualTo Constraint it isn't true when using YML or Annotations.
So in order to dynamically unsure Note::$to is equals (or not equals) to Note::$from you could to use either Getters Constraint Targets or Callback Constraint.
However, there is a third option much easier (IMO): Expression Constraint
Expression Constraint approach
This constraint allows you to use an expression for more complex,
dynamic validation. See Basic Usage for an example. See Callback for a
different constraint that gives you similar flexibility.
Here is an example based on your question:
use Symfony\Component\Validator\Constraints as Assert;
/*
* Entity class...
*/
class Note
{
//...
/**
* #ORM\ManyToOne(targetEntity="Template")
* #var $from Template
* #Assert\NotBlank()
* #Assert\Expression('not (value == this.getTo())')
*/
protected $from;
//...
}
That is, just add #Assert\Expression('not (value == this.getTo())') to $from property.
Constraints Targets: Getters approach
use Symfony\Component\Validator\Constraints as Assert;
/*
* Entity class...
*/
class Note
{
//...
/**
* #Assert\isFalse(message='"from" cannot be equals to "to"')
* #return bool True if self::$from is not equals to self::$to
*/
function isFromAndToNotEqual()
{
return !($this->getFrom() != $this->getTo());
}
//...
}
Setting the property path validation:
Be aware taking this approach (Getters As Constraints Targets) and using validation with forms, it'll not show error messages next/closer to form field.
However, you always can set/config the error_mapping option (in Form type) in order to show the custom errors display next to a specific field, thus the solution would be something like this:
<?php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class MyType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('from')
->add('to')
// more fields...
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
//...
# it cause error message display next to
# "from" field (or whaterver field you which).
'error_mapping' => array(
'fromAndToNotEqual' => 'from',
),
));
}
}
Please note the current solutions is based on Symfony 2.7, but it
should be work nicely on other older versions (except some details for
Form class, etc).
I am trying to find my feet with Symfony and Doctrine and although I'm guessing it's far from elegant, I have managed to get the below working IF I use findall(). My main issue is that I'm trying to only return events which are yet to occur. Below is my attempt using expr()->gr():
My controller:
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use AppBundle\Form\Type\RegistrationType;
use AppBundle\Form\Model\Registration;
use AppBundle\Entity\Events;
use Doctrine\ORM\EntityRepository;
class DefaultController extends Controller
{
/**
* #Route("/events", name="events")
*/
public function eventsAction(Request $request)
{
$calendar = $this->getDoctrine()
->getRepository('AppBundle:Events');
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->where($criteria->expr()->gt('EventDate',date('Y-m-d H:i:s') ));
$list=$calendar->matching($criteria);
return $this->render('default/events.html.twig', array(
'title' => 'Events',
'list' => $list,
));
}
}
My Events.php entity is:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Events
*
* #ORM\Table(name="Events")
* #ORM\Entity
*/
class Events
{
/**
* #var \DateTime
*
* #ORM\Column(name="EventDate", type="date", nullable=false)
*/
private $eventdate;
When I try to load the page I get:
Unrecognized field: EventDate
I'm assuming it's a case-sensitive issue somewhere? I have it in my database (EventDate) and my Events entity annotation specifies name="EventDate". I've tried changing private $eventdate to private $EventDate but this gives me an even more serious looking error so I quickly retreated:
FatalErrorException in DateType.php line 53: Error: Call to a member function format() on a non-object
I have no experience using criteria, but this is very easy to accomplish using the Doctrine Query Language (DQL).
$em = $this->getDoctrine()->getManager();
$result = $em->createQuery(
'SELECT e FROM AppBundle:Events e
WHERE e.eventdate > :date'
)
->setParameter(':date', $date)
->getResult();
$date has to be an instance of \DateTime.
I've tried to search for this error but the fact that I haven't found anything leads me to believe that I'm doing something silly. I'll include the relevant code below, but basically I'm using multiple table inheritance (or Class Table Inheritance) and trying to use the Doctrine ORM findBy() method to query based on the discriminator column, which results in the following ORMException being thrown: "Unrecognized field: type".
Here is the code that triggers the exception:
// $this->em is an instance of \Doctrine\ORM\EntityManager
$repository = $this->em->getRepository('JoeCommentBundle:Thread');
return $repository->findOneBy(array(
'type' => $this->type,
'related_id' => $id
));
Here is the relevant code for the 'base' abstract entity:
<?php
namespace Joe\Bundle\CommentBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="comment_threads")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap( {"story" = "Joe\Bundle\StoryBundle\Entity\StoryThread"} )
*/
abstract class Thread
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(name="related_id", type="integer")
*/
protected $relatedId;
/** MORE FIELDS BELOW.... **/
And finally, here is the code for the concrete thread entity:
<?php
namespace Joe\Bundle\StoryBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Joe\Bundle\CommentBundle\Entity\Thread as AbstractThread;
/**
* #ORM\Entity
* #ORM\Table(name="story_comment_threads")
*/
class StoryThread extends AbstractThread
{
/**
* #ORM\OneToOne(targetEntity="Story")
* #ORM\JoinColumn(name="story_id", referencedColumnName="id")
*/
protected $story;
}
I've double checked my schema, and the type column definitely exists, so I'm not sure what could be causing this. Any ideas? Thanks.
Rob, when querying your actually using the parent entity and trying to filter on the discriminator value. Instead, work on the repository relative to the child entity you want to fetch. Doctrine will do the rest for you. So in your case you want to get the repository for StoryThread.
$repository = $this->em->getRepository('JoeCommentBundle:StoryThread');
return repository->find($id);
You cannot use the discriminator column as a standard entity property.
Instead you may do the following:
$dql = 'SELECT e FROM JoeCommentBundle:Thread e
WHERE e.related_id = :related_id AND e INSTANCE OF :type';
$query = $em->createQuery($dql);
$query->setParameters(array(
'type' => $this->type,
'related_id' => $id
));
$record = $query->getSingleResult();