收据实体包含一组票证。每张票都有$amount
属性。目前尚无法将票数之和限制为大于或等于0。
请注意,最初创建的收据没有任何票证。然后在javascript对话框中由TicketController
在给定收据中添加/编辑故障单。
通过调试我发现调用Constraint
但未调用ConstraintValidator
根据我对此similar SO question的接受答案:
public function editTicketAction(Request $request, ReceiptTotal $rcptTotal, $id)
{
$em = $this->getDoctrine()->getManager();
$ticket = $em->getRepository('AppBundle:Ticket')->find($id);
$receipt = $ticket->getReceipt();
$total = $rcptTotal->getReceiptTotal($receipt);
$form = $this->createForm(TicketType::class, $ticket,
[
'validation_groups' => ['edit'],
'cancel_action' => $this->generateUrl('homepage'),
'rcptTotal' => $total,
]);
$form->handleRequest($request);
...
}
$total = $rcptTotal->getReceiptTotal($receipt);
通过服务提供当前的门票总数。
use AppBundle\Validator\Constraints\NonNegative;
...
public function buildForm(FormBuilderInterface $builder, array $options)
{
...
$form->add(
'amount', TextType::class,
[
'label' => 'Amount',
'label_attr' => ['style' => 'color: red;'],
'constraints' => [
new NonNegative(['rcptTotal' => $options['rcptTotal']])
]
]
);
class NonNegative extends Constraint
{
protected $rcptTotal;
public function __construct($options)
{
$this->rcptTotal = $options['rcptTotal'];
}
public $message = 'Receipt total may not be less than zero';
public function validatedBy()
{
return get_class($this) . 'Validator';
}
public function getRcptTotal()
{
return $this->rcptTotal();
}
}
class NonNegativeValidator extends ConstraintValidator
{
public function validate($amount, Constraint $constraint)
{
$total = $contraint->getRcptTotal() + $amount;
if ($total < 0) {
$this->context->buildViolation($constraint->message)
->addViolation();
}
}
}
答案 0 :(得分:0)
它需要实体验证回调和故障单属性的组合。该属性为$rcptTotal
,设置为给定收据的总票数。
->add(
'amount', TextType::class,
[
'label' => 'Amount',
'label_attr' => ['style' => 'color: red;'],
]
)
->add('rcptTotal', HiddenType::class, [
'data' => $options['rcptTotal'],
])
...
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Ticket::class,
'validation_groups' => [],
'required' => false,
'rcptTotal' => null,
));
}
/**
* @Assert\Callback(groups={"edit"})
*/
public function validateEdit(ExecutionContextInterface $context)
{
$receipt = $this->getReceipt();
$total = 0;
$tickets = $receipt->getTickets();
foreach ($tickets as $value) {
$total += ($this->getId() !== $value->getId()) ? $value->getAmount() : $this->getAmount();
}
if (0 > $total) {
$context->buildViolation('Receipt total may not be < 0!')
->atPath('amount')
->addViolation();
}
}
/**
* @Assert\Callback(groups={"add"})
*/
public function validateAdd(ExecutionContextInterface $context)
{
$total = $this->getRcptTotal();
if (0 > $total + $this->getAmount()) {
$context->buildViolation('Receipt total may not be < 0!')
->atPath('amount')
->addViolation();
}
}
private $rcptTotal;
public function setRcptTotal($rcptTotal)
{
$this->rcptTotal = $rcptTotal;
}
public function getRcptTotal()
{
return $this->rcptTotal;
}
public function addTicketAction(Request $request, TicketArtist $owner, ReceiptTotal $rcptTotal, $id)
{
$em = $this->getDoctrine()->getManager();
$receipt = $em->getRepository('AppBundle:Receipt')->findOneBy(['id' => $id]);
$total = $rcptTotal->getReceiptTotal($receipt);
$ticket = new Ticket();
$form = $this->createForm(TicketType::class, $ticket,
[
'validation_groups' => ['add'],
'cancel_action' => $this->generateUrl('homepage'),
'rcptTotal' => $total,
]);
...
}
public function editTicketAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$ticket = $em->getRepository('AppBundle:Ticket')->find($id);
$form = $this->createForm(TicketType::class, $ticket,
[
'validation_groups' => ['edit'],
'cancel_action' => $this->generateUrl('homepage'),
]);
$form->handleRequest($request);
...
}