Laravel - Laravel utilizando Validator?

25 respostas Resolvido
laravel
Cleiton_Conceicao

Estou querendo fazer minhas validações no Controller, preciso validar se a data inicial é maior que a data de término, queria saber se é possível validar utilizando o método Validator do Laravel?

Meu código:

$validator = Validator::make($request->all(),[
        'paciente' => 'required',
        'local' => 'required',
        'tipo' => 'required',
        'event_start_date'=>'required',
        'event_start_time'=>'required',
        'event_end_time'=>'required',
    ], 
    [
        'required' => 'O campo :attribute é obrigatório',
    ], [
        'paciente'      => 'Paciente',
        'Sala'     => 'Sala de Atendimento',
        'tipo'  => 'Tipo de Atendimento',
        'event_start_date'=>'Data Início',
        'event_start_time'=>'Horário Inicial',
        'event_end_time'=>'Horário Término',
    ]
  );

25 Respostas

Dragoon

Quais são os campos e como vem o dado da tela, exemplo dd/mm/YYYY dias mês e ano?

Acho que deve fazer uma validador complemento, mas fique tranquilo quem tem sim como resolver

Cleiton_Conceicao

Os dados vem dessa forma dd/mm/YYYY.

Dragoon

Tem que criar validador vou implementar e posto aqui.

Qual versão do seu Laravel?

Cleiton_Conceicao

A versão é a 5.7

Dragoon

Existe algumas formas de fazer isso, eu particularmente prefiro construir uma classe e usar o método dela da seguinte forma:

Crie uma pasta em app com o nome de Validators, sendo que o seu namespace será <?php namespace App\Validators , veja o código:

<?php namespace App\Validators;

use Carbon\Carbon;

class MinorDateThat
{
    public function validate($attribute, $value, $parameters, $validator)
    {
        if (count($parameters) === 0)
            throw new \Exception("Parameter name not reported");
        $param = $parameters[0];
        $minorDate = Carbon::createFromFormat("d/m/Y", $value);
        $greaterDate = Carbon::createFromFormat("d/m/Y", $this->getParamValue($validator->getData(), $param));
        return ($minorDate && $greaterDate && ($minorDate->lessThanOrEqualTo($greaterDate)));
    }

    protected function getParamValue($data, $param)
    {
        if (in_array($param, array_keys($data)))
            return $data[$param];
        throw new \Exception("Not informed value");
    }
}

Após essa criação de arquivo vai na pasta app\Providers abra o arquivo AppServiceProvider.php e no seu método boot() acrescente esse código:

<?php namespace App\Providers;

use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{

    public function boot()
    {
        Validator::extend('minordate','\App\Validators\MinorDateThat@validate');
    }

    public function register()
    {
     
    }
}

e preste atenção também nos use que tem que existir que no caso é o use Illuminate\Support\Facades\Validator; para que você possa usar o método extend como demostrado no código, e isso serve para registrar esse novo jeito de validar um dado na sua tela.

Pronto agora é na parte do Validator você deve configurar o nome minordate e seu parâmetro que é o nome do outro campo a ser utilizado para a comparação de data.

Exemplo v.blade.php

@extends('_layout')
@section('content')
    <h3 class="page-header">Verificação de Datas</h3>
    @if ($errors->any())
        <div class="alert alert-danger">
            <ul>
                @foreach ($errors->all() as $error)
                    <li>{{ $error }}</li>
                @endforeach
            </ul>
        </div>
    @endif
    <div class="table-responsive">
        <form action="{{route('data.store')}}" method="post" enctype="multipart/form-data">
            <input type="hidden" name="_token" value="{{{ csrf_token() }}}"/>
            <div class="form-group">
                <label for="datai" class="label-primary">Data Inicial</label>
                <input type="text" class="form-control" name="datai" id="datai" value="{{old('datai')}}" />
            </div>
            <div class="form-group">
                <label for="dataf" class="label-primary">Data Final</label>
                <input type="text" class="form-control" name="dataf" id="dataf"  value="{{old('dataf')}}" />
            </div>
            <div>
                <button class="btn btn-block btn-success">Enviar</button>
            </div>
        </form>
    </div>
@endsection

nesse v.blade.php tem duas datas a datai e a dataf quero que a datai seja menor ou igual a dataf e no código do Controller segue:

public function store(Request $request)
{
	$rules =  [
		'datai' => 'required|date_format:d/m/Y|minordate:dataf',
		'dataf' => 'required|date_format:d/m/Y'
	];
	$messages = [
		'datai.required' => 'Data inicial é requerida',
		'datai.date_format' => 'Data inicial está em formato inválido',
		'datai.minordate' => 'Data inicial tem que ser menor que data final',
		'dataf.required' => 'Data final é requerida',
		'dataf.date_format' => 'Data final está em formato inválido',
	];
	Validator::make($request->all(), $rules, $messages)->validate();
	return 'Ok';
}

ou seja, minordate:dataf está validando se a data é menor ou igual a dataf. Isso eu fiz de acordo com você precisava talvez ajustes a serem feitos mediante suas regras de negócio, mas, isso resolve essa parte.

No Laravel existe até after:date que é uma validação após o problema é que essa validação tem um formato especifico e para data em formato do Brasil pode dar problema em alguns tipos de data …

Cleiton_Conceicao

estou tentando adaptar esse seu exemplo no meu código porém não estou conseguindo. vou deixar o código pra ver se vc consegue me dar uma força.
meu validator atualmente está assim… queria incluir essa sua validação na minha existente.

$validator = Validator::make($request->all(),[
        'paciente' => 'required',
        'local' => 'required',
        'event_start_date'=>'required',
        'event_start_time'=>'required',
        'event_end_time'=>'required', 
        //'event_start_date' => 'before:event_end_date',
    ], 
    [
        'required' => 'O campo :attribute é obrigatório',
    ], [
        'paciente'      => 'Paciente',
        'local'     => 'Sala de Atendimento',
        'event_start_date'=>'Data Início',
        'event_start_time'=>'Horário Inicial',
        'event_end_time'=>'Horário Término',
      // 'event_end_date'=>'Data de Término',
    ]
  );    
         $feed_back=array(); 
        if ($validator->passes()){

}
Dragoon

Outra forma:

<?php namespace App\Validators;

use DateTime;

class MinorDateThat
{
    public function validate($attribute, $value, $parameters, $validator)
    {
        if (count($parameters) <= 1)
        {
            throw new \Exception("Parameter name not reported");
        }

        $param = $parameters[0];
        $format = $parameters[1];
        $data = $validator->getData();

        $minorDate = $this->parseDateTime($value, $format);
        $greaterDate = $this->parseDateTime($this->getParamValue($data, $param), $format);

        return $this->isDateTimeInstance($minorDate) &&
            $this->isDateTimeInstance($greaterDate) &&
            $this->isLessThanOrEqualTo($minorDate, $greaterDate);
    }

    protected function isDateTimeInstance($datetime)
    {
        return $datetime instanceof DateTime;
    }

    protected function isLessThanOrEqualTo($dateTime1, $dateTime2)
    {
        return $dateTime1 <= $dateTime2;
    }

    protected function parseDateTime($value, $format = 'Y-m-d H:m:s')
    {
        return \DateTime::createFromFormat($format, $value);
    }

    protected function getParamValue($data, $param)
    {
        if (in_array($param, array_keys($data)))
            return $data[$param];
        throw new \Exception("Not informed value");
    }
}

Montando a regra:

$rules = [
	'datai' => 'required|date_format:d/m/Y|minordate:dataf,d/m/Y',
	'dataf' => 'required|date_format:d/m/Y'
];

minordate depois os parâmetros que são: o campo a ser comparado (dataf) e o formato que vem da tela (d/m/Y).

Essa é melhor do que a outra, eu utilizei o próprio DateTime porque ele não retorna uma exceção se a data for inválida …

Dragoon

Quais são os campos para comparação?

Observação: a validação é colocado de uma só vez com a separação | para cada validação acho eu que você está fazendo um validação por linha, não é isso é uma linha para cada item da tela, exemplo, se você tem um campo que é uma data e ela tem que ser digitada então a validação é

'campo' => 'required|date_format:d/m/Y'

ou seja, tudo no mesmo array para conferir

Se por acaso for aqui:

Na versão 1:

[
    'paciente' => 'required',
    'local' => 'required',
    'event_start_date'=>'required|date_format:d/m/Y|minordate:event_start_date',
    'event_start_time'=>'required',
    'event_end_time'=>'required', 
    'event_start_date' => 'required|date_format:d/m/Y',
]

Na versão 2:

[
    'paciente' => 'required',
    'local' => 'required',
    'event_start_date'=>'required|date_format:d/m/Y|minordate:event_start_date,d/m/Y',
    'event_start_time'=>'required',
    'event_end_time'=>'required', 
    'event_start_date' => 'required|date_format:d/m/Y',
]
Cleiton_Conceicao

Estou fazendo assim, os campos de comparação são o event_start_date e event_end_date:

$validator = Validator::make($request->all(),[
    'paciente' => 'required',
    'local' => 'required',
    'event_start_date'=>'required',
   
    'event_start_time'=>'required',
    'event_end_time'=>'required', 
    'event_start_date' => 'required|date_format:d/m/Y|minordate:event_end_date',
    'event_end_date' => 'required|date_format:d/m/Y'
], 
[
    'required' => 'O campo :attribute é obrigatório',
], [
    'paciente'      => 'Paciente',
    'local'     => 'Sala de Atendimento',
    'event_start_date.required' => 'Data inicial é requerida',
    'event_start_date.date_format' => 'Data inicial está em formato inválido',
    'event_start_date.minordate' => 'Data inicial tem que ser menor que data final',
    'event_end_date.required' => 'Data final é requerida',
    'event_end_date.date_format' => 'Data final está em formato inválido',
]);
Dragoon

Olha no meu exemplo por favor

Cleiton_Conceicao

está tudo na mesma linha. vou tirar os outros campos, pra ficar mais fácil o entendimento.

$validator = Validator::make($request->all(),[

        'event_start_date' => 'required|date_format:d/m/Y|minordate:event_end_date',
        'event_end_date' => 'required|date_format:d/m/Y'
    ], 
 [
        'event_start_date.required' => 'Data inicial é requerida',
        'event_start_date.date_format' => 'Data inicial está em formato inválido',
        'event_start_date.minordate' => 'Data inicial tem que ser menor que data final',
        'event_end_date.required' => 'Data final é requerida',
        'event_end_date.date_format' => 'Data final está em formato inválido',
    ]);
Dragoon

OK, mas, o que aconteceu, qual o problema? Cara seja claro…

Cleiton_Conceicao

atualmente para validar os outros campos eu fiz assim, que irá exibir o erro na tela caso encontre algum problema no preenchimento do formulário.
minha ideia é adaptar a sua lógica das validações da data nessa minha lógica.

$validator = Validator::make($request->all(),[
        'paciente' => 'required',
        'local' => 'required',
        'event_start_date'=>'required',
        'event_start_time'=>'required',
        'event_end_time'=>'required', 
        //'event_start_date' => 'before:event_end_date',
    ], 
    [
        'required' => 'O campo :attribute é obrigatório',
    ], [
        'paciente'      => 'Paciente',
        'local'     => 'Sala de Atendimento',
        'event_start_date'=>'Data Início',
        'event_start_time'=>'Horário Inicial',
        'event_end_time'=>'Horário Término',
      // 'event_end_date'=>'Data de Término',
    ]
  );    

         $feed_back=array(); 
        if ($validator->passes()){
            
        $feed_back = new Event();  

        $feed_back->pac_codigo = $request->input('paciente');
        $feed_back->psi_codigo = $request->input('respAte');
        $feed_back->sal_codigo = $request->input('local');
        $feed_back->ate_codigo = $request->input('tipo');
        $feed_back->event_start_date = implode("-", array_reverse(explode("/", $request->input('event_start_date'))));
        $feed_back->event_end_date = implode("-", array_reverse(explode("/", $request->input('event_end_date'))));
        $feed_back->event_start_time = $request->input('event_start_time');
        $feed_back->event_end_time = $request->input('event_end_time');
        $feed_back->event_description = $request->input('event_description');
         //Event::create($request->all());
            $feed_back->save();
           $feed_back['type']='alert-success';
           $feed_back['message']='Consulta marcada com sucesso!';
           $feed_back['error']=array();    
         
        }
        else{
         $feed_back['type']='alert-danger';
          $feed_back['error']=  $validator->errors()->all();
        }
        

         return json_encode($feed_back);
Dragoon

Você seguiu todos os passos?
Você olhou a primeira resposta?
Você fez como está proposto?
O que aconteceu quando fez / se fez?

Cleiton_Conceicao

fiz tudo o que vc falou, não acontece nada…
tirei tudo o que eu fiz anteriormente e continua não acontecendo nada.
veja se a lógica é realmente essa, se vc reparar no código abaixo estou passando a variável $validator no if, onde irá exibir a uma mensagem de erro que, a única diferença da sua lógica agora pra minha é essa.

$rules = [

        'event_start_date' => 'required|date_format:d/m/Y|minordate:event_end_date',
        'event_end_date' => 'required|date_format:d/m/Y'
    ];
      $messages = [
        'event_start_date.required' => 'Data inicial é requerida',
        'event_start_date.date_format' => 'Data inicial está em formato inválido',
        'event_start_date.minordate' => 'Data inicial tem que ser menor que data final',
        'event_end_date.required' => 'Data final é requerida',
        'event_end_date.date_format' => 'Data final está em formato inválido',
    ];
    $validator=Validator::make($request->all(), $rules, $messages)->validate();
         $feed_back=array(); 
        if ($validator->passes()){
Dragoon

O código passado a você foi testado, se você não conseguiu adaptar o problema não é no meu código que ratificando foi testado, agora você dizer que não aconteceu nada é estranho você não pode dizer isso assim dessa forma dessa maneira como se tivesse certeza daquilo que pelo visto não tem, o que você realmente fez, diga o seu passo a passo que ai posso encontrar o problema, porque, sinceridade se você colocou e não gerou erro ou a validação não surtou efeito tem algo que não estou conseguindo ver no seu jeito de programar!

javaflex

Isso é tão simples de fazer em PHP puro que nem precisava esquentar a cabeça com Laravel. Mas se quer usar e seu projeto está estruturado assim, o colega acima já deu uma baita aula pra você aqui. É questão de parar o projeto e estudar isoladamente tutoriais. Depois que dominar adapte o que aprendeu no seu projeto.

Dragoon

O problema na minha visão, não é fazer isso como se fosse independente, porque o código é PHP puro, o grande problema na minha visão é a falta de ler a documentação e quando a gente coloca um código testado, funcional e padrão o cara diz que não está funcionando e não te aponta o problema real.

Falta mesmo ler a documentação e é melhor que faça dentro do código do Framework, porque? Por causa da visualização das validações e manter um padrão.

Bom já fiz o papel de até construir o código, falta mesmo entender aonde o amigo tem problema, mas, fica a dica, nunca dizem o que acontece.

javaflex

O padrão pode ser o que cada equipe definir, pode ser com ou sem framework. Claro, se ele escolheu Laravel então tem que encarar mesmo. Problema que a galera vem aqui e nem debuga…

Dragoon

Amigo a tag é Laravel não sei pra que isso e tem que ser feito do jeito que está não deprecie as coisas, se ele viesse aqui e não fosse Laravel eu faria diferente.

Não debuga e não entendem documentação.

Tente entender uma coisa o problema é tag Laravel não mude o enfoque, eu sei como funciona padrão de equipe…

javaflex

Eu sei, só foi um conselho pra quem está perdendo horas ou dias com Laravel pra atender um requisito tão simples.

Cleiton_Conceicao
Solucao aceita

galera, obrigado pela força. é sempre bom saber outros métodos de resolver um determinado problema.
mas nesse caso resolvi da seguinte forma…
percebi que Dragoon achou que eu estava ofendendo-o de alguma forma, mas não foi a minha intenção. me expressei mal.

$validator = Validator::make($data, [
    'start_date'    => 'required|date',
    'end_date'      => 'required|date|after_or_equal:start_date',
]);
Dragoon

Só esclarecendo que essa forma vai bulgar por causa do estilo da data, então, não deve ser utilizado.

Não fico ofendido, só acho que vocês têm uma certa deficiência em ler documentação do Laravel, que é de fácil entendimento.

Bom assunto encerrado e fica o alerta.

Cleiton_Conceicao

pq irá bugar? testei aqui e está funcionando…
e a documentação não está tão simples assim…

Dragoon

Leia sobre strtotime no PHP.net. Vai funcionar pra certas datas para outras não por causa do cálculo. Esse código é baseado nesse cara, que para datas yyyy-mm-dd, mas não é o seu caso

Bom fica mais mesmo como aviso.

Nota :

Datas nos formatos m/d/y e d-m-y são diferenciadas observando o separador entre os vários componentes: se o separador é uma barra ( / ), o formato Americano m/d/y é utilizado; enquanto que, se o separador for um traço ( - ) ou um ponto ( . ), o formato Europeu d-m-y será utilizado. Entretanto, se o ano foi informado no formato de dois dígitos e o separador for um traço ( - , a string de data será interpretada como y-m-d .

Para evitar uma ambiguidade em potencial, o melhor é utilizar datas que seguem a ISO 8601 ( YYYY-MM-DD ) ou o métodoDateTime::createFromFormat() sempre que possível.

after: date (after_or_equals só muda o sinal)

The field under validation must be a value after a given date. The dates will be passed into the strtotime PHP function:

'start_date' => 'required|date|after:tomorrow'

Então com essas informações essa validação não funciona corretamente em todos os casos dessa pergunta tornando a solução inválida, por causa do formato da data.

A maior intenção aqui é deixar mais clara possível o potencial problema.

Criado 10 de abril de 2019
Ultima resposta 11 de abr. de 2019
Respostas 25
Participantes 3