Код выше сначала преобразует входные данные к число, а затем проверяет. Это значит, что я могу передать пустую строку, false или пустой массив и оно благополучно приведется к числу. Можно ли как-то проверять, что пользователь передает именно число?
Используйте поддержку null значений с помощью allowNull @Assert\NotBlank(allowNull=true) Разные типы можно валидировать через @Assert\Type(type="integer")
Нужно сменить тайпхинт с int на string, иначе передаваемое пользователем значение будет конвертировано в int еще до начала валидации и вы никак не узнаете, что там передавал пользователь изначально.