In Laravel 5.x to encapsulate the download files for the different entities, or at least in the framework of the different actions in the controller?

Good day!

There is a form _form.blade.php towed blade views: create.blade.php and update.blade.php

...
 {{ Form::file('photo') }}
 <img src="/storage/images/articles/{{ $article->photo }}" style="height:50px" alt>
...


Picture flies along with the form post. In the method, the findings, which I will respecial below:

class ArticlesController extends Controller
{
 public function update(ArticleRequest $request, Article $article)
{
 $request = $this->saveImage($request);

dump($request->all());

dump($request->photo);

$article->update($request->all());

dd($article->photo);

 $this->syncTags($article, $request->input('tag_list'));

 return redirect()->back();
}

private function saveImage(ArticleRequest $request)
{

 if ($request->hasFile('photo')) {

 $file = $request->file('photo'); // ->isValid()

 $fileNameWithExt = $file->getClientOriginalName();
 $filename = pathinfo($fileNameWithExt, PATHINFO_FILENAME);
 $extension = $file->getClientOriginalExtension();
 $fileNameToStore = $filename . '_' . time() . '.' . $extension;
 $file->storeAs('public/articles', $fileNameToStore);

 } else {
 $fileNameToStore = 'noimage.jpg';
}

 $request->photo = $fileNameToStore;

 return $request;

}

}


The output of dump and dd

1)
array:7 [▼
"_method" => "PATCH"
"_token" => "YPmvNLjhmoqKdxIt7RL2YbviiIjcfpEdqe0jw7ms"
"name" => "Sleep snow"
"content" => "
Sleep snow in winter night with bears and foxes"
"published_at" => "2017-12-14"
"tag_list" => array:1 [▶]
"photo" => UploadedFile {#238 ▶}
]

2)
"logoct_1513334576.png"

3)
UploadedFile {#238 ▼
-test: false
-originalName: "logoct.png"
-mimeType "image/png"
-size: 55490
-error: 0
#hashName: null
path: "/tmp"
filename: "phpulvqiE"
basename: "phpulvqiE"
pathname: "/tmp/phpulvqiE"
extension: ""
realPath: "/tmp/phpulvqiE"
aTime: 2017-12-15 10:42:56
mTime: 2017-12-15 10:42:56
cTime: 2017-12-15 10:42:56
inode: 21630383
size: 55490
perms: 0100600
owner: 33
group: 33
type "file"
writable: true
readable: true
executable: false
file: true
dir: false
link: false
}


The picture itself is loaded, the problem is that $article->photo is blank.

In the method saveImage I wanted to set the property photo image name, but in the end, the property $article->photo gets the UploadedFile object.

Why is it so? I return the $request method saveImagewhere overridden property photo.

Not found a single example where it would have encapsulated this logic download.

In Yii2 framework things skarmlivanii behaviors. In Laravel I suppose that may have to be involved as the middleware for such cases, if at all, to make the uploading of images and determine the name of the entity when updating and adding different entities (Also deletes the picture when an entity is deleted).

In the property $fillable element of the photo is present.

Also the rule for images is:

class ArticleRequest extends FormRequest{
...
public function rules()
{
 return [
...
'photo'=>'image|nullable|max:1999'
...
];
}
...
}
June 10th 19 at 14:57
2 answers
June 10th 19 at 14:59
Solution
I wouldn't do.
The best in my opinion solution would be to just feeding UploadedFile object in your model. But in the model to use a setter for this attribute to intercept and replay value.

Look in the model it will be something like this:
public function setPhotoAttribute($value) {
 if ($value instanceOf UploadedFile) {
 $fileNameWithExt = $value->getClientOriginalName();
 $filename = pathinfo($fileNameWithExt, PATHINFO_FILENAME);
 $extension = $value->getClientOriginalExtension();
 $fileNameToStore = $filename . '_' . time() . '.' . $extension;
 $file->storeAs('public/articles', $fileNameToStore);
 return $this->attributes['photo'] = $fileNameToStore;
}
}


The source should be checked. Distribute by hand :)
Thank you, you get the idea. This option is much better than the implementation in the controller. Interested in a moment - is it possible to make the implementation of a method outside the model, for example in any other class, so this functionality could be drawn on many models. Because of the alleged class must also be deleting pictures when you delete a model. My thoughts - the base model for models, entities which have a picture (not very good.), the trait (PTS.), a possible solution out of the box (so far none found) or some third party option. DOP. considerations - in models picture is the path like what You wrote above: 'public/articles', the rest is some sort of oraz great to feed a third-party class. - dudley_Ri commented on June 10th 19 at 15:02
It is preferable, after all, a trait in my opinion.
In trade you will write three methods to work with images and their data. Then, connecting the trait, you add functionality to the model that does not extend the bulky base class, and which is likely to grow in the future.
Path models do not understand. You have this model contains only the file name... - Gerhard commented on June 10th 19 at 15:05
Thank you, there is a view that trade must be a variable of $path, the path which should be taken from the model:

trait ImageManager()
{
 public function setPhotoAttribute($value) {
 if ($value instanceOf UploadedFile) {
 $fileNameWithExt = $value->getClientOriginalName();
 $filename = pathinfo($fileNameWithExt, PATHINFO_FILENAME);
 $extension = $value->getClientOriginalExtension();
 $fileNameToStore = $filename . '_' . time() . '.' . $extension;
// $this->path instead of an explicit 'public/articles'
 $file->storeAs( $this->path , $fileNameToStore); 
 return $this->attributes['photo'] = $fileNameToStore;
}
}
}
- dudley_Ri commented on June 10th 19 at 15:08
Interested - will it work this design in crate (containing $this->path) provided that the property is defined in the model Articles? Without prokidyvaya additional public properties in the model to the trait through $this->param , is it possible to get the class of the current model? - dudley_Ri commented on June 10th 19 at 15:11
Do not need to pass. Of the class available to all the properties and methods of the current class object ($this), where this trait was introduced. You work with the trait and with the usual class. Or in other words, if your model has a path attribute, then it can be easy to use from any method in trace and your design will work without problems. - Gerhard commented on June 10th 19 at 15:14
It sounds quite a good solution. Sad only trade that you cannot override metoday, or rather in this case - events ( Ala onCreate(), onDelete() ) in the Model. It would be very convenient if for example the event with the same name first performed in trate, and then in the main model. Laravel is a very cool framework, but I'm surprised that there are things Behavors (behavior) in Yii2 - dudley_Ri commented on June 10th 19 at 15:17
Event models can be defined in observers. Read what it is.
They can be expressed as a normal class. And then just a trait of something inside... - Gerhard commented on June 10th 19 at 15:20
June 10th 19 at 15:01
To change the $request need to use merge
$request->merge(['photo' => $fileNameToStore]);
Thank you, did not help(

All also, instead of the desired string object.

$request = $this->saveImage($request);
 dump($request->all());


array:7 [▼
"_method" => "PATCH"
"_token" => "F8OlvOLb5wmPLy7sc3EzPXZmfCdZSi666ar0db1a"
"name" => "Sleep snow"
"content" => "Sleep snow in winter night with bears and foxes"
"published_at" => "2017-12-14"
"tag_list" => array:1 [▶]
"photo" => UploadedFile {#238 ▶}
]

private function saveImage(ArticleRequest $request)
{
 if ($request->hasFile('photo')) {

 $file = $request->file('photo'); // ->isValid()

 $fileNameWithExt = $file->getClientOriginalName();
 $filename = pathinfo($fileNameWithExt, PATHINFO_FILENAME);
 $extension = $file->getClientOriginalExtension();
 $fileNameToStore = $filename . '_' . time() . '.' . $extension;
 $file->storeAs('public/images', $fileNameToStore);
 } else {
 $fileNameToStore = 'noimage.jpg';
}
 $request->merge(['photo' => $fileNameToStore]);
 return $request;
}
- dudley_Ri commented on June 10th 19 at 15:04
Better make saveImage method return the name of the photo, and in the update method already partipicate photo $request - Gerhard commented on June 10th 19 at 15:07
You can of course in the frame of one entity, but when more than 10, I want to find some nekompitentnoe end-to-end solution. Looking towards Middlewars. Is there any way to rotate. - dudley_Ri commented on June 10th 19 at 15:10
If you do that, the mass assignment will be impossible to do - dudley_Ri commented on June 10th 19 at 15:13

Find more questions by tags Laravel