Есть несколько возможностей, как бы вы этого достигли, это действительно зависит от вашей ситуации, бизнес-логики приложения и т. Д. (Также вы должны указать ветвь Doctrine, 1.x или 2.x)
Это ограничение целостности, делайте это на уровне базы данных: скажем, у вас есть триггер preUpdate для вашей таблицы, который либо вызовет исключение (это могут делать только некоторые БД, например Postgres, Oracle), либо ничего не сделает, просто остановите операция обновления.
Как и предполагал @jensgram, вы можете переопределить метод validator и либо вернуть недопустимое состояние, либо вызвать исключение, потому что это не проблема проверки, так как это ограничение целостности и логики, IMHO
Используйте метод preSave, либо пропустите сохранение (но пользователь ничего не заметит), либо снова выбросите из него исключение.
В вашем приложении вы не должны позволять пользователю вообще попадать в эту ситуацию. Ваш графический интерфейс должен быть явным и четко отображать, что счет-фактура закрыт и не может быть изменен в дальнейшем.
Лично я бы использовал этот сценарий:
Во-первых, решение № 4, не позволяйте пользователю делать это. Чтобы быть в безопасности, внедрите триггер непосредственно в базе данных, чтобы предотвратить ошибку в моем приложении в изменении закрытого счета, но делайте это молча, без ошибок, просто пропустите операцию сохранения (решение № 1). У этого подхода есть еще одно преимущество. Если вы окажетесь в ситуации, когда вам нужно будет подключиться к базе данных из любого другого приложения, это ограничение целостности будет сохранено.