Laravel 5.3 - overriding default validation for a delete - validation

I have a table Languages with a language field and an image field. the CRU of CRUD is fine but the delete is firing the default validation. I have defined two validation files in Requests. One is AddNewLanguageRequest which contains:
public function rules()
{
return [
'language' => 'required|max:255|min:5',
'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048'
}
and the other is EditLanguageRequest which contains
public function rules()
{
return [
'language' => 'required|max:255|min:5',
'image' => 'image|mimes:jpeg,png,jpg,gif,svg|max:2048'
];
}
I have a form which shows the language and the image to be deleted and as confirm button and so this form calls a route:
{!! Form::open( array('url'=>'deletelanguage/'.$lang->id)) !!}
The route calls the LanguageController
public function delete(Requests\EditLanguageRequest $request){
//is there an image? If so delete it
$lang = Language::find($request->id);
if (isset($lang->image))
{
if (Storage::exists($lang->image) )
{Storage::delete($lang->image);}
}
$lang->delete();
}
When I try it out I get a validation failure from the EditLanguageRequest.
How can I "turn off" validation for the delete action?

The problem was in this line:
public function delete(Requests\EditLanguageRequest $request
It was of course calling the request so changing it to
public function delete(Request $request)
solved it

Related

Making Laravel 9 validation rule that is unique on 2 columns

I am trying to update a row in the pages table.
The slug must be unique in the pages table on the slug and app_id field combined.
i.e. there can be multiple slugs entitled 'this-is-my-slug' but they must have unique app_id.
Therefore I have found that formula for the unique rule is:
unique:table,column,except,idColumn,extraColumn,extraColumnValue
I have an update method and getValidationRules method.
public function update($resource,$id,$request){
$app_id=22;
$request->validate(
$this->getValidationRules($id,$app_id)
);
// ...store
}
When I test for just a unique slug the following works:
public function getValidationRules($id,$app_id){
return [
'title'=> 'required',
'slug'=> 'required|unique:pages,slug,'.$id
];
}
However, when I try and add the app_id into the validation rules it returns server error.
public function getValidationRules($id,$app_id){
return [
'title'=> 'required',
'slug'=> 'required|unique:pages,slug,'.$id.',app_id,'.$app_id
];
}
I have also tried to use the Rule facade, but that also returns server error. Infact I can't even get that working for just the ignore id!
public function getValidationRules($id,$app_id){
return [
'title'=> 'required',
'slug'=> [Rule::unique('pages','slug')->where('app_id',$app_id)->ignore($id)]
];
}
Any help is much appreciated :)
Thanks for the respsonses. It turned out a couple of things were wrong.
Firstly if you want to use the Rule facade for the validation rules, make sure you've included it:
use Illuminate\Validation\Rule;
The other method for defining the validation rule seems to be limited to the following pattern:
unique:table,column,except,idColumn
The blog post that I read that showed you could add additional columns was for laravel 7, so i guess that is no longer the case for laravel 9.
Thanks for your responses and help in the chat!
I recommend you to add your own custom rule.
First run artisan make:rule SlugWithUniqueAppIdRule
This will create new file/class inside App\Rules called SlugWIthUniqueAppRule.php.
Next inside, lets add your custom rule and message when error occured.
public function passes($attribute, $value)
{
// I assume you use model Page for table pages
$app_id = request()->id;
$pageExists = Page::query()
->where('slug', $slug)
->where('app_id', $app_id)
->exists();
return !$pageExists;
}
public function message()
{
return 'The slug must have unique app id.';
}
Than you can use it inside your validation.
return [
'title'=> 'required|string',
'slug' => new SlugWithUniqueAppIdRule(),
];
You can try it again and adjust this custom rule according to your needs.
Bonus:
I recommend to move your form request into separate class.
Run artisan make:request UpdateSlugAppRequest
And check this newly made file in App\Http\Requests.
This request class by default will consists of 2 public methods : authorize() and rules().
Change authorize to return true, or otherwise this route can not be accessed.
Move your rules array from controller into rules().
public function rules()
{
return [
'title'=> 'required|string',
'slug' => new SlugWithUniqueAppIdRule(),
];
}
To use it inside your controller:
public function update(UpdateSlugAppRequest $request, $resource, $id){
// this will return validated inputs in array format
$validated = $request->validated();
// ...store process , move to a ServiceClass
}
This will make your controller a lot slimmer.

Laravel - request validation

I extedned request class to create my own valdiation rules. In that class I added my custom validation function. In function I check if tags are pass regEx and I would like to filter tags to remove tags shorter then 2 characters.
And later keep in request only tags that passed validation.
public function createPost(PostRequest $request)
{
dd($request->all()); //In this place I would like to keep only tags passed through validation not all tags recived in request
}
Is it possibile to do it? How to set it in Request class?
'tags' => [
'nullable',
'string',
function ($attribute, $value, $fail){
$tagsArray = explode(',', $value);
if(count($tagsArray) > 5) {
$fail(__('place.tags_max_limit'));
}
$tagsFiltered = [];
foreach ($tagsArray as $tag){
$tag = trim($tag);
if(preg_match('/^[a-zA-Z]+$/',$tag)){
$tagsFiltered[] = $tag;
};
}
return $tagsFiltered;
}
],
EDIT:
I think we miss understanding. I would like to after validation have only tags that returned in variable $tagsFiltered; Not the same as recived in input.
You have to create this custom regex rule and use it into rules() function.
Like so:
public function rules()
{
return [
'tag' => 'regex:/[^]{2,}/'
];
}
public function createPost(PostRequest $request)
{
$request->validated();
}
And then just call it via validated() function wherever you want.
first define validation rule with this command:
php artisan make:rule TagsFilter
navigate to TagsFilter rule file and define your filter on passes method:
public function passes($attribute, $value)
{
$tagsArray = explode(',', $value);
$tagsFiltered = [];
foreach ($tagsArray as $tag){
$tag = trim($tag);
if(preg_match('/^[a-zA-Z]+$/',$tag)){
$tagsFiltered[] = $tag;
};
}
return count($tagsArray) > 5 && count($tagsFiltered) > 0;
}
then include your rule in your validation on controller:
$request->validate([
'tags' => ['required', new TagsFilter],
]);

PUT in laravel API

I'm studying api rest with laravel, I was able to implement all methods except PUT. Although the routes and controllers are correctly configured a response to a request using the PUT method is "laravel put Sorry, the page you are looking for could not be found.", As now image.
here is the method code in the controller in app/Http/Controllers/LivroController.php:
public function store(Request $request) {
$livro = $request->isMethod('put') ? Livro::findOrFail($request->livro_id) : new Livro;
$livro->id = $request->input('livro_id');
$livro->nome = $request->input('nome');
$livro->descricao = $request->input('descricao');
$livro->user_id = 1; //$request->user()->id;
if($livro->save()) {
return new LivroResource($livro);
}}
here is the route code in /routes/api.php:
Route::put('livro', 'LivroController#store');
change your postman method to POST and then add new parameter in your Body :
"_method" : PUT
This is because HTML forms do not support PUT, PATCH or DELETE actions. So, when defining PUT, PATCH or DELETE routes that are called from an HTML form, you will need to add a hidden _method field to the form
If you want to create new data, you should use post method,
Route::post('livro', 'LivroController#store');
public function store(Request $request) {
If you want to update exist data you should use put method,
Route::put('livro/{id}', 'LivroController#update');
public function update(Request $request, $id) {
You can use this package https://github.com/durmus-aydogdu/laravel-resource for rest calls. This package highly customizable for rest and resource calls.
Is better that you use controllers type resources and for this case the put method. Also you should validate the request. For example:
public function update(Request $request, $id)
{
$livro = Livro::findOrFail($id);
$validator = Validator::make($request->all(), [
'livro_id' => 'required',
'nome' => 'required',
'descricao' => 'required',
]);
if ($validator->fails()) {
return response()->json(['errors'=>$validator->messages()],Response::HTTP_UNPROCESSABLE_ENTITY);
}else{
$livo->update($request->all());
return response()->json(['livro'=>$livro], Response::HTTP_OK);
}
}

URL friendly in routes

I'm creating url friendly in my app, but it's not working, the app is giving me some issues related with "-".
It's giving me an error of:
ErrorException in PostController.php line 60:
Trying to get property of non-object
My ideal URL is:
http://domain.com/CATEGORY-title-of-post-ID
My route is:
Route::get('{category}-{title}-{id}', 'PostController#show');
PostController show function:
public function show($category,$title,$id)
{
$post = Post::find($id);
$user = Auth::user();
$comments = Comment::where('post_id',$id)
->where('approved',1)
->get();
return view('posts.show',compact('post','comments','user'));
}
Blade View:
<?php
$title_seo = str_slug($feature->title, '-');
?>
<a href="{{url($feature->categories[0]->internal_name."-".$title_seo."-".$feature->id)}}" rel="bookmark">
...</a>
There's a library called Eloquent-Sluggable that will create a unique slug for each post and correctly URL encode it.
To install (taken from the docs):
composer require cviebrock/eloquent-sluggable:^4.1
Then, update config/app.php by adding an entry for the service provider.
'providers' => [
// ...
Cviebrock\EloquentSluggable\ServiceProvider::class,
];
Finally, from the command line again, publish the default configuration file:
php artisan vendor:publish --provider="Cviebrock\EloquentSluggable\ServiceProvider"
To use, add the Sluggable trait to your model:
use Cviebrock\EloquentSluggable\Sluggable;
class Post extends Model
{
use Sluggable;
/**
* Return the sluggable configuration array for this model.
*
* #return array
*/
public function sluggable()
{
return [
'slug' => [
'source' => 'title'
]
];
}
}
When you save an instance of your model, the library will automatically create a slug and save it to the newly created slug column of your model's table. So to access the slug you'd use $model->slug
To achieve your desired slug, rather than create it from title set by default. You can pass the source attribute of the sluggable method an array of field names, using a dot notation to access the attributes of a related model, like so:
public function sluggable()
{
return [
'slug' => [
'source' => ['category.name','title','id']
]
];
}
}
Why are you genering your "friendly URL" manually?
You have route helper function that builds for you a URL based on the given parameters.
Route::get('{category}-{title}-{id}', [
'as => 'post.show',
'uses' => 'PostController#show'
]);
echo route('post.show', ['testing', 'title', 'id']); // http://domain.dev/testing-title-id
This is not the best approach to implement SEO friendly URLs, anyway.
In your controller you ALWAYS use your ID to find a post, that means that category and title are completely useless to determine which resource needs to be served to the user.
You can make your life easier by doing something like:
Route::get('{id}-{slug}', [
'as => 'post.show',
'uses' => 'PostController#show'
]);
echo route('post.show', ['id', 'slug']); // http://domain.dev/id-slug
In your model you create an helper function that generates the slug for your post:
class Post
{
[...]
public function slug()
{
return str_slug("{$this->category}-{$this->title}");
}
}
Then, in your controller you need to check that the slug used to access the article is correct or not, since you don't want Google to index post with wrong slugs. You essentially force a URL to be in a certain way, and you don't lose index points.
class PostController
{
[...]
public function show($id, $slug)
{
$post = Post::findOrFail($id);
$user = Auth::user();
if ($post->slug() !== $slug) {
return redirect()->route('posts.show', ['id' => 1, 'slug' => $post->slug()]);
}
$comments = Comment::where('post_id', $id)->where('approved', 1)->get();
return view('posts.show', compact('post', 'comments', 'user'));
}
}

Yii2 custom validation rule not working

I'm trying to write some custom validation for a model in yii2, but I can't figure out why the validation always is positive, although my validation function always adds an error.
for example the rules
public function rules()
{
return [
...
[['myattribute'], 'myvalidation'],
];
}
public function myvalidation($attribute, $params)
{
$this->addError($attribute, "error");
}
the validate() function still returns true. What's the problem?
In validation rule add skipOnError => false
[
['myattribute', 'myvalidation', 'skipOnError' => false],
]
Then
$model->validate(); // should return false;
What I will recommend you is watch this lesson on custom roles and
read docs on it. It's not the best video tutorial, but this guy made it work correctly.
In your case :
1.In [['myattribute'], 'myvalidation'], remove extra array from here, make your model rules and custom valdation function look like this
public function rules()
{
return [
...
['myattribute', 'myvalidation'],
];
}
public function myvalidation($attribute, $params)
{
$this->addError($attribute, "error");
}
it's not wrong, but it's used when you have more than one attribute.
2.Then go to your form and put `` to your ActiveForm so it will look like this
<?php $form = ActiveForm::begin(['enableAjaxValidation' => true]); ?>
I mean, your need to do it in case if you want to validate it without reloading (using ajax).
3.Also add this to your controller's action that is connected to your view
if(Yii::$app->request->isAjax && $model->load($_POST)) {
Yii::$app->response->format = 'json';
return \yii\widgets\ActiveForm::validate($model);
}
This will validate your input in the form via ajax, if it's not ajax, this will not work.
['reg_date','validateDate', 'skipOnEmpty' => false, 'skipOnError' => false]
add this to your rules
public function validateDate($attribute,$params,$validator)
{
$validator->addError($this,$attribute,"Bugungi sana bo'lishi kerak!");
}
check this in your controller side like this
if($model->validate()){
echo "validate works";
}

Resources