タグ別アーカイブ: symfony2

Symfony2 with custom validator

昨日の投稿の後にちゃっかり自分でカスタムバリデート作っているコード見つけたので一応ここに貼り付けておく。symfonyの公式ドキュメントにもそのまんま記載してある。

ただこれだとヤヤ面倒くさめなのでAssert\Trueなんかの手軽さでAssertのエラーメッセージをカスタマイズしたい!

<?php
// src/Hc100/DemoBundle/Validator/constraints/ExistsDepartmentNumber.php

namespace Hc100\DemoBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class ExistsDepartmentNumber extends Constraint
{
  public $message = '部門番号 "%string%" が部門マスタに登録されていません';

  public function validatedBy()
  {
    return 'existsdepartmentnumber';
  }
}

validatedByには src/Hc100/DemoBundle/Resources/config/services.xml に定義してあるserviceを返す

<?php
// src/Hc100/DemoBundle/Validator/constraints/ExistsDepartmentNumberValidator.php

namespace Hc100\DemoBundle\Validator\Constraints;

use Doctrine\ORM\EntityManager;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Hc100\DemoBundle\Entity\Department;

class ExistsDepartmentNumberValidator extends ConstraintValidator
{
  private $entityManager;

  public function __construct(EntityManager $entityManager)
  {
    $this->entityManager = $entityManager;
  }

  public function validate($value, Constraint $constraint)
  {
    if ($value == '')
      return;

    $department = $this->entityManager->getRepository('Hc100DemoBundle:Department')
      ->findMatchByDepartmentNumber($value);
    if (!$department) {
      $this->context->addViolation($constraint->message, array('%string%' => $value));
    }
  }
}

src/Hc100/DemoBundle/Resources/config/services.xmlにサービスを追記

<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

  <services>
    <service id="hc100_validator.constraint.existsdepartmentnumber" class="Hc100\DemoBundle\Validator\Constraints\ExistsDepartmentNumberValidator">
      <argument type="service" id="doctrine.orm.entity_manager"/>
      <tag name="validator.constraint_validator" alias="existsdepartmentnumber" />
    </service>

  </services>
</container>

あとはEntityの中でカスタムAssertを追加

use Hc100\DemoBundle\Validator\Constraints as Hc100Assert;

  /**
   * 部門
   * @var string $department_number
   *
   * @ORM\Column(name="department_number", type="integer")
   * @Hc100Assert\ExistsDepartmentNumber()
   */
  private $department_number;

symfony2 Assert customizing messages

EntityのバリデーションのAssertで通らなかった時に指定するメッセージ文字列、これにplaceholderを使えないか検索してみたんだけどどうやらできない模様。時間がなくてソースコードまでは確認してない

例えば、こんな事をしたいと思った

/*
 * @Assert\True(message = "未登録部門 {{ value }}")
 */
public function isValidDepartmentNumber() {
  return (valid) ? true : false;
}

もちろん、これは出来ないでのそのまま {{ value }} という文字列がエラーとして表示される

ウェブ上のフォームの場合は入力文字列(送信した値)が画面上に出ているだろうから、あえて何がバリデーションで失敗したかなんてエラー文字列に入れる必要はない。しかし今回はバッチ的な処理の中でEntityをいくつも作成してそれを検証する形だったので、まとめた処理のエラーを出す場合に単純なエラー原因だけでは何がどういった理由でエラーになったのか非常に分かりづらいという問題に陥った

こんな処理

for (someloop) {
  // validate
  $errors = $this->container->get('validator')->validate($entity);
  if (count($errors) > 0) {
    // if error, stack error list
    foreach ($errors as $error) {
       $this->errors[] = $error->getMessage();
    }
  }
}

結局ちょう場当たり的な対応をした

for (someloop) {
  // validate
  $errors = $this->container->get('validator')->validate($entity);
  if (count($errors) > 0) {
    // if error, stack error list
    foreach ($errors as $error) {
      $_str = $error->getMessage();
      // custom error messaging
      $_str = preg_replace("/{{ value }}/", ' ('.$entity->getDepartmentNumber().')', $_str);
      $this->errors[] = $_str;
    }
  }
}

symfony2関連のサンプルコードってまだまだ少ない感じがするなぁ