Laravel Dropzonejs file validation in hasmany table - php

I have a laravel app that uploads files. I need to check in the related table if the file exist. My user model hasmany(assets) The file info lives in the assets table. I am trying to pull the name out of the table and verify it against the file being uploaded in dropzone.
Here is my dropzone script:
Dropzone.options.dropzoneUpload = {
paramName: "asset", // The name that will be used to transfer the file
maxFilesize: 2, // MB
accept: function(file, done) {
if (file.name == "{{$filename}}") {
done("Naha, you don't.");
}
else { done(); }
}
};
My function that generates my view for my upload page looks like this
public function index()
{
$filename = Auth::user()->assets->name;
return view('upload.index')->with('filename', $filename);
}
I get an error returned on the name in the filename variable
Undefined property: Illuminate\Database\Eloquent\Collection::$name
I have no idea how to access the file name from the table and verify it with the script in the view. Each user has multiple file names in the table.
Pre dropzone i was able to use this in my controller
foreach($userAssets as $asset)
{
if($asset->name == $filename)
{
return redirect('upload')->with('errornotice', 'A file with that name already exist');
}
}
but that won't work in the script.

Since you said yourself that your User hasMany Assets, what exactly is assets->name supposed to print? The name of which Asset? Since you have many of those and user->asset is returning a Collection, you could probably iterate that collection, construct a JSON array out of all Asset names and inject it into your JS. Then do a JavaScript for/each to check against all elements of the array. That's weak validation though, any user could edit the JS before submitting. If it's important to you that the filenames do not exist already, consider some kind of server-side validation.

Related

Eloquent - How to wait until after create() without Observer

The Error
Call to a member function media() on null
The Scenario
I have several related models. I have an "Event" model. Attached to this (via 1 to 1) is a Gallery model. Attached to that (via one to many) is a "Media" model. In the "created" observer for the Event, I'm trying to attach its gallery. I can create the gallery no problem, but when I then try and attach media to it I get the above error.
My code
if ($model->gallery === null) {
$this->createGallery($model);
}
// product images or banner images
$file = Storage::put("public/event_images/", $image);
$file = str_replace("public/event_images/", "", $file);
$file = "/" . $file;
$model->gallery->media()->create([
"path" => $file,
"type" => "image"
]);
// The createGallery() function
private function createGallery($model)
{
$model->gallery()->create();
}
So I know to fix this, I have to "wait" until the gallery has been created before I try to access its relationships. But I can't figure out how to do this. This code works the second time it's run, suggesting that the gallery is indeed created - just not quickly enough before the code hits media().
PHP is a synchronous programming language, so it is impossible that you have to wait for something to complete.
The problem is that you loaded the relation already and this loaded relation won't re-validate until you load it again. which can be done using the load() function.
Change your code to create the gallery like this:
if ($model->gallery === null) {
// Create the related model
$this->createGallery($model);
// Load the relation again
$model->load('gallery');
}
I think you might need to refresh the model before trying to access its relationship. Try $model->refresh() before you attempt to attach the image to the gallery. Something like
if ($model->gallery === null) {
$this->createGallery($model);
$model->refresh();
}
The model won't be aware of the newly created gallery otherwise.

PHP MVC: Best Practice and Right way for print data validation error

I have Php Login system using MVC structure. For database data validation I create LoginModel. I need to print failure error to view like: User Not Exist Now Which way is right and better:
1- Add error data validation in Login Model and get in Controller and Print to View Like This:
class LoginModel extends \App\Core\Model
{
public function login($user_name, $user_password, $set_remember_me_cookie = null)
{
$returnError = array();
// checks if user exists, if login is not blocked (due to failed logins) and if password fits the hash
$result = $this->validateAndGetUser($user_name, $user_password);
// check if that user exists.
if (!$result) {
$returnError['isMessage'] = false;
$returnError['name'] = "User Not Found";
}
return $returnError;
}
private function validateAndGetUser($user_name, $user_password){
//Check User Data Validation
}
}
2- Add Only True Or False in LoginModel and Get in Controller And Set Error Name and Print to View Like This:
class LoginModel extends \App\Core\Model
{
public function login($user_name, $user_password, $set_remember_me_cookie = null)
{
// checks if user exists, if login is not blocked (due to failed logins) and if password fits the hash
$result = $this->validateAndGetUser($user_name, $user_password);
// check if that user exists.
if (!$result) {
return false;
}
return true;
}
private function validateAndGetUser($user_name, $user_password){
//Check User Data Validation
}
}
In action my really question is: Can I add error message in Model and Get in Controller?! Which way is right and true?
There are many ways to do this.
For me the best way is the first way you have suggested, but better declare bug reports in a single file eg errors.php and make the model return you array with 2 keys, the first key is always TRUE or FALSE and then if your model returns the first key FALSE reads the error number from the second key.
Then, in the controller you can replace the error number with the corresponding key in the array you declared in errors.php
If the first key is TRUE, then the second key will be your user information.
Suggestion:
Split the login functionality into two (main) steps:
Check if the posted user already exists. If not, throw an exception.
Match the posted password against the stored one. If they don't match, throw an exception. I suggest the use of password_hash for storing passwords, and of password_verify for matching a password with the stored one.
Then - based on your current architecture, in your controller, use a try-catch block to catch the exception thrown by the login steps and proceed as you wish to display the exception message to the user.
Just as a note: In case of an ajax request, you would send a specific response header (with status code 500, for example) or a custom response header (with status code 420, for example) back to the client, e.g. browser, in order to activate the error function of the ajax request.
Notes:
The domain model is a layer. And it must have no knowledge about the outside world.
A controller should only (!) update the domain model (through services).
A view should be a class - not a template file - responsible with fetching data from the model layer (through services), preparing/formatting it for presentation, and passing it to a response object, in order for this to be returned and printed.
The controller and the view (mostly 1:1 relation) should be created separately. The controller should not have any knowledge about the view. This creation step would take place in the front-controller class or file.
As for error reporting, I would recommend to read this.

Images from Dropzone are lost after error on Validation with Laravel

So, i have this particular issue.
I have made a form with dropzone included, and the images are uploaded via AJAX, and everything is working from that point of view (selected images are stored, and can be deleted from the box).
So the problem is the following:
When i submit the form, and some validation error happens, the images i have uploaded are already on the server, but dont display on the dropzone form, i have to reupload them again, but then i just fill my storage with unwated data, and the images that were uploaded earlier before the validation cannot be accessed or deleted by any methods later on, so its basically junk data.
Is there any way to prevent this from happening? I would LOVE to show the already uploaded images after validation error (or refresh for example). If there cant be any solution for this, suggest me different approach.
Thanks.
I managed to get a working solution.
My thinking was following: If there are images posted, then using the $validator->fails() method i am deleting the images from the server.
Here is the complete code, if someone needs it:
// Validating the request
public function validate(Request $request){
$rules = []; //define your rules
$messages = []; //define your rules
// We make new validator with request data, rules and messages
$validator = Validator::make($request->all(), $rules, $messages);
// Deleting images if the validator fails
if($validator->fails()){
if(isset($request->images)){
foreach($request->images as $image){
// unlink your image here
}
}
return Redirect::back()->withInput()->withErrors($validator);
}
}
Then in the method store/edit (or custom method) just call:
public function store(Request $request){
// If it fails, return the redirect we defined.
if($this->validate($request)){
return $this->validate($request);
}
}
You can also define the validator directly in the store method, but since i use it few times in my Controller, i made a separate method just for it. We must return its value if we like to redirect back with the errors.
Cheers.

file field removed autometically on save yii model

I am trying to update a record which consist of a pdf file . record is updating successfully but the file field becomes empty on update .
my controller code is
$model2=$this->loadModel($alldata[0]->frm_id,'Forms');
$values=array();
$tagsarray=$_POST['searched_tag']; // matched tag values
$pdfval=$_POST['searched_tag_pdf']; // pdf form values
for($i=0;$i< count($pdfval);$i++)
{
$values[$pdfval[$i]]=$tagsarray[$i];
}
$model2->analyse_data=json_encode($values);
$model2->frm_status=2;
if($model2->save())
{
Yii::app()->user->setFlash('pdfupload','Form analysis done! data saved.');
$this->redirect(Yii::app()->createUrl('/formsupload'));
}else
{
Yii::app()->user->setFlash('pdfupload','Some error to save the data.');
$this->redirect(Yii::app()->createUrl('/formsupload'));
}
and model rules is
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('frm_code,frm_desc,frm_pdf', 'required'),
array('frm_code', 'unique'),
array('is_approve', 'safe'),
//array('desc', 'min'=>1, 'max'=>200)
array('frm_pdf', 'file', 'types'=>'pdf','allowEmpty'=>true),
);
}
Update
also tried this solution here
unable to catch the problem .
Handling file upload updates in yii can be a bit tricky. Try setting the file attribute to be unsafe and see if that helps. Yii seems to set the value of that attribute to null if it cannot find an uploaded file. Setting it to unsafe should prevent that.
You can check my answer at the yii forum link below to someone running into a similar problem for more info.
http://www.yiiframework.com/forum/index.php/topic/63506-how-can-i-update-records-without-adding-same-image-again/page__p__279888#entry279888

CakePHP: how to do sub-actions with sub-views

Apologies if I'm using the wrong terminology to describe what I'm trying to do...
I have a model/controller called Report which users can view like so:
example.com/reports/view/123
Each report hasAndBelongsToMany File objects. I need to make those files accessible like so:
example.com/reports/view/123/file/456
Or
example.com/reports/view/123/456
^ ^
| |
report file
I'm intentionally NOT creating a separate action for files (example.com/files/view...) because access to the file is relative to the report.
What is the correct way to do this in CakePHP?
My first guess is to add logic inside of ReportsController::view that checks for the existence of the second parameter (file) and manually render() a different view (for the file) conditionally. But I'm not sure if this is "the CakePHP way".
You are in the right path, modify your action to accept an optional parameter.
public function view($file = null) {
$somethingElse = null;
if (isset($file)) {
//your logic
$somethingElse = $this->Foo->bar();
}
$this->set(compact('somethingElse'));
}
Regarding to the view, I don't know your requirements, but I think you don't need to create a different view, you can either put a conditional in your view to show something, or (my favourite approach) create an element that will be displayed only if $somethingElse contains something. That is:
//View code
if (!empty($somethingElse)) {
echo $this->element('yourAwesomeElement', compact('somethingElse'))
}
Then in yourAwesomeElement
foreach ($somethingElse as $something) {
echo $something;
}
The good thing is that your element will be reusable for future views that could need this.

Categories