I am working on a form which accepts some user input and an image file, the submission part and the data getting entered into the database is working fine but I am stuck at how to name a file once it is uploaded, right now this is what i see as an image name in database C:\wamp2.5\tmp\phpF360.tmp which obviously is not correct.
This is what my controller looks like DefaultController.php
public function createBlogAction(Request $request)
{
$post = new Post();
$form = $this->createForm(new PostCreate(), $post);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$post->upload();
$post->setDate(date_create(date('Y-m-d H:i:s')));
$post->setAuthor('ClickTeck');
$em->persist($post);
$em->flush();
$this->get('session')->getFlashBag()->add(
'notice',
'Success'
);
}
return $this->render('BlogBundle:Default:blog-create.html.twig', array(
'form' => $form->createView()
)
);
}
This is what my upload() looks like inside Entity/Post.php which is uploading the file and moving it into the folder, the file name that I see in a folder is correct however now the one that goes into the database
public function upload()
{
if (null === $this->getImage()) {
return;
}
// I might be wrong, but I feel it is here that i need to name the file
$this->getImage()->move(
$this->getUploadRootDir(),
$this->getImage()->getClientOriginalName()
);
$this->path = $this->getUploadDir();
$this->file = null;
}
I will really appreciate if someone can push me in right direction, I just need to name the file, a name which gets assigned to the image in database and the file should get uploaded with the same name as well.
UPDATE
I managed to get it to work using the following function, not sure if this is the best practice but it did work, i would love to hear from others on this. please do not provide any links, if you can refine what has already been done that would be great.
public function upload()
{
// the file property can be empty if the field is not required
if (null === $this->getImage()) {
return;
}
$dirpath = $this->getUploadRootDir();
$image = $this->getImage()->getClientOriginalName();
$ext = $this->getImage()->guessExtension();
$name = substr($image, 0, - strlen($ext));
$i = 1;
while(file_exists($dirpath . '/' . $image)) {
$image = $name . '-' . $i .'.'. $ext;
$i++;
}
$this->getImage()->move($dirpath,$image);
$this->image = $image;
$this->path = $this->getUploadDir();
$this->file = null;
}
This topic from documentation may help you : http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html
In addition, you should not put your upload function in the controller but rather use Doctrine events (Lifecycle callbacks) to call your function automatically.
as per suggestion of #theofabry you can check symfony2 documentation How to handle File Uploads with Doctrine, Controller must be thin as much as possible and try to do upload with Doctrine Events.
If you want to continue with your logic you may try following code, I have not tested yet...so please be careful.
// set the path property to the filename where you'ved saved the file
$this->path = $this->file->getClientOriginalName();
instead of
$this->path = $this->getUploadDir();
Related
I've been using Dropzone for several days and I faced some issues. The idea is: the user selects his file, it uploads and goes in his file directory and some of the file's properties (size, name) go in the DB. I can't do it because when the user uploads the file, the page does not refresh and nothing goes in Input::file('file'). I just can't do it. Here is the code i'm using:
class UploadController extends Controller {
public function upload() {
if(Input::hasFile('file')){
$file = Input::file('file');
$user = Auth::id();
$file->move('uploads/'.$user, $file->getClientOriginalName());
}
else {
echo 'Please select a file first';
}
}
Here are the two functions in File.php model
public function getFileId(){
$fileName = Input::file('file')->getClientOriginalName();
$files = File::where('filename', $fileName)->get(); //$fileName
foreach ($files as $file) {
$fileid = $file->fileid;
echo $fileid.'<br>';
Input::file('file')->fileid = $file->fileid; // put fileid as an attribute to the object file for futher usage
}
}
public function incrementFileId(){
$files = File::orderBy('fileid', 'desc')->take(1)->get();
foreach($files as $file){
echo $file->fileid + 1 .' incremented file id<br>';
}
}
So how should my third model function look like to upload the file's properties? DropZone uses Ajax and I though that I should get the file attributes from there but could this be done?!
Use Request instead of Input:
public function upload(Request $request)
{
if ($request->hasFile('file'))
{
$file = $request->file('file');
$file->move('uploads/'.$user, $file->getClientOriginalName());
}
I'm trying to maintain a skinny controller, but I'm still getting used to what can go in my controller, since before I used to pile just about everything inside of it. In this example I'm inserting validated data into a database, which I assumed is correct. What I'm confused about is that I want to take one of the field inputs, manipulate its text formatting and then save it to another field in my database. What I have written works, but I don't know if its good to have this code in my controller, if not where should it go?
Controller
public function store()
{
$validation = new Services\Validators\Deal;
if($validation->passes())
{
$deals = Deals::create(Input::all());
// start code in question
$image = Input::get('company');
$image = strtolower($image);
$image = str_replace(" ", "-", $image);
$image .= ".png";
$deals->image = $image;
$deals->save();
// end code in question
return Redirect::to('deals/create')
->with('message', 'Deal Created');
}
return Redirect::back()
->withInput()
->withErrors($validation->errors);
}
To recap, I'm not sure if the code in question belongs in my controller, and if it doesn't, where would it be better placed? Thanks for any insights.
Any business logic should be placed in models, or repositories and your controller should look just like
<?php
class DealsController extends controller {
public function __construct(Deals $deals) //// <---- Dependency Injection
{
$this->deals = $deals;
}
public function store()
{
try
{
$this->deals->insertRow(Input::all());
}
catch (\Exceptions\ValidationException $e)
{
return Redirect::back()
->withInput()
->withErrors($this->deals->errors);
}
return Redirect::to('deals/create')
->with('message', 'Deal Created');
}
}
And in your Deals class, you do whatever you need to do with your data
class Deals extends Eloquent {
public function insertRow($input)
{
$validation = new Services\Validators\Deal;
if($validation->passes())
{
$deals = Deals::create($input);
// start code in question
$image = $input['company'];
$image = strtolower($image);
$image = str_replace(" ", "-", $image);
$image .= ".png";
$deals->image = $image;
$deals->save();
// end code in question
}
$this->errors = $validation->errors;
throw new \Exceptions\ValidationException("Error inserting Deals", $validation->errors);
}
}
This is untested and a not-really-refactored code, but I hope you can see a point in it.
You could actually remove all the code in question and use Laravel Mutator instead.
Basically, setup a function in your Deals class which will automatically process the text formatting whenever data is about to be set/save via the Model Eloquent ::create, or update.
Something like
public function setImageAttribute($value)
{
$image = strtolower($value);
$image = str_replace(" ", "-", $image);
$image .= ".png";
$this->attributes['image'] = $image;
}
Refer to http://laravel.com/docs/eloquent#accessors-and-mutators
Hi Im stucked with this for 4 days now, i have read massive amount of related articles, but seems nothing is working.
First i will explain my idea, give you some code and then i will tell what i have tried.
Idea. I have 2 separate db tables 'project' and 'pictures'. In project table i put info about projects (id, title, pubdate, template etc.) and i need to assign some pictures to that project so on pictures table i have "project_id" column which is relating those two. In my controller i have function project_picture_proccess($id) this $id is changing according to which project im clicking on and that is how all related pictures are fetched. problem is i cant pass that current project $id to upload model (this is for setting upload path for current project).
This is my controller:
class project extends Admin_Controller{
public function __construct(){
parent::__construct();
$this->load->model('project_m');
$this->load->model('project_pictures_m');
//here is index() function and some other (not related to my problem)
public function project_picture_proccess($id = NULL){
//$id variable is from current project im editing
//and changes according to project id
$this->load->model('upload_m');
if ($id) {
//search for directory in upload path with current project slug name
//and if there isnt any it will create it and add proper rights
$this->project_m->search_and_create_dir($id);
//function get_images is fetching all images that current project has
$this->data['project_images'] = $this->project_m->get_images($id);
//this function is setting upload config (setting upload path
//based on directory created in above)-its working var_dump'ed it
$this->upload_m->set_upload_config($id);
}
if($this->input->post('upload')){
//do_multi_upload works on multiple images just fine
//but i cant make it to get outcome of set_upload_config function
//so i can set upload_path very manualy and everything i upload is in mess
$this->upload_m->do_multi_upload();
//redirection function does not work because it is not getting
//any project_m data and i have lost all project_m related data in my view
//its title of project im editing and its id
redirect('admin/project/project_picture_proccess');
}
$this->data['error'] = array('error' => '');
$this->data['project'] = $this->project_m->get($id);
//function get_images is fetching all unsorted images uploaded in
//the path created above for further proccessing
$this->data['unsorted_img'] = $this->upload_m->get_unsorted();
$this->data['subview'] = 'admin/project/picture_proccess';
$this->load->view('admin/main', $this->data);
}
and here is my model:
class Upload_m extends MY_model{
protected $pic_path;
protected $_primary_filter = 'intval';
protected $_table_name = 'projects';
function Upload_m(){
parent::__construct();
$this->pic_path = realpath(APPPATH . '../img/');
function get_slug($id = NULL){
if($id !=NULL){
$filter = $this->_primary_filter;
$id = $filter($id);
$result = mysql_query('SELECT slug FROM ' . $this->_table_name . ' WHERE id=' . $id . ' limit 1');
$data = mysql_fetch_row($result);
$name = array_shift($data); //array - need to be string
return $name;
}else return;
}
function set_upload_config($id){
if($id == NULL) return;
$slug = $this->get_slug($id);
$upload_config = array(
'allowed_types' => 'jpg|gif|jpeg|png|bmp',
'upload_path' => $this->pic_path . $slug . '/',
'max_size' => 0
);
return $upload_config;
}
function do_multi_upload(){
$this->load->library('upload');
$this->upload->initialize($this->set_upload_config());
if($this->upload->do_multi_upload('userfile')){
var_dump($this->upload->get_multi_upload_data());
return;
}else echo "Error at uploading";
}
Here is what i have tried:
moving if($this->input->post...) method inside if($id) scope and
nothing is passed to view and noting is passed to model
tried like every single solution on stackoverflow: these very common tip was $this->load->model('upload_m', $id) <-
returning null when var_dump($id) tested on function
do_something($id){var_dump($id); die;}
i have made global variables and tried to fetch them by get_class_vars
i have rewrite system/core/libraries/model function to accept variable on do_multi_upload($field<-this is default,
$var=NULL<-optional)
i have tried to put those variables in __construct() function like __construct($var)
i have tried to change name of that $id to $var and put it inside if($this->input->post('upload') && $var === $id) and tried to use $var in model. didnt work this approach
I am so desperate this has taken too too much my time. My goal is to pass $id to upload function to set correct upload path and save data into database url (taken from upload_path), project_id ->taken from passed $id. Any help will be appreciated even if its a suggestion how to change my structure so i could still meet my goals.
Hi i have successfully saved to mySQL database the files uplaoded using jQuery-PHP FileUpload with the answer from this thread as guide. Now my questiion is, is it possible to only just show the images from my database according to the users who uploaded the imgs? since i also save the users along with the filename.? I dont have idea on how to do it, or whant and where to insert the codes, or is it possible.
EDITED:
I have now idea where it initialize the loading of image
protected function get_file_object($file_name) {
if ($this->is_valid_file_object($file_name)) {
$file = new stdClass();
$file->name = $file_name;
$file->size = $this->get_file_size(
$this->get_upload_path($file_name)
);
$file->url = $this->get_download_url($file->name);
foreach($this->options['image_versions'] as $version => $options) {
if (!empty($version)) {
if (is_file($this->get_upload_path($file_name, $version))) {
$file->{$version.'_url'} = $this->get_download_url(
$file->name,
$version
);
}
}
}
$this->set_file_delete_properties($file);
return $file;
}
return null;
}
Now i want to insert this mySql query which filter the images that will only show, but i don't know how.
SELECT desc FROM images WHERE userid=1
Hi there I have written a code that ietrates through whole array and copies the images to a folder and inserts data in record. Now funny thing is that $model->save()does not show error it returns true. and program never goes into else
now what happens loop continues to run and completes its ietration without breaking. I can not guess who is wrong. greater chances are me as i am most of time :)
here is code
protected function saveImage($formData,$model)
{
if ($formData === null)
return;
$idx=0;
foreach($formData['title'] as $image)
{
$model->title = $image;
$file= dirname(Yii::app()->request->scriptFile) . DIRECTORY_SEPARATOR
. DIRECTORY_SEPARATOR .'images\hotelImages'. DIRECTORY_SEPARATOR
. $model->hotel->name;
$model->image = Yii::app()->baseUrl. "/images/hotelImages/".$_FILES['HotelImages']['name'][$idx];//image path
if($model->save())
{
echo $idx.'<br /> it was sucess<br />';
If(file_exists($file))
{
copy($_FILES['HotelImages']['tmp_name'][$idx],$file."/".$_FILES['HotelImages']['name'][$idx]);
}
else
{
mkdir($file);
copy($_FILES['HotelImages']['tmp_name'][$idx],$file."/".$_FILES['HotelImages']['name'][$idx]);
}
$idx++;
}//if there was error
else
{
print_r($model->getErrors());
yii::app()->end();
return FALSE;
}
echo '<br />end reached <br />';
}
yii::app()->end();
return true;
}
var_dump for $formdata is
array
(
'title' => array
(
'0' => 'title1'
'1' => 'title2'
)
)
No mater what ever the ietration count for foreach loop database gets only single row
The save() method inserts a record into the database if it doesn't exist yet, and otherwise updates that same database record.
$model is being passed in as a method parameter, and I'm just assuming here that its title attribute is not the primary key.
In other words, you keep updating the same database record over and over, which is why you only see one record in the database.
#fivedigit's analysis is correct. My suggested fix would be to reduce the complexity of this method. Put everything inside the foreach in its own method (e.g. saveImage), then do something like:
foreach($formData['title'] as $image) {
$this->saveImage($image, new Image);
}
This method is a bit of a super-method, and you might find it easier to break it out into different methods. Perhaps use a component to handle the file copying, instead of filling up the controller.
And once again I am wrong :)
Issue was that in each foreach ietration the $model was previous and New instant of $model was not created and yii thought that hey its old one probably this Geek is updating it. so that is it.it updates in database.
just did
$model = new HotelImages;
before populating them
I thank fivedigit for Just an idea.
I have a strong believe on this
Most people says Little knowledge is dangerous...well that is true for
all except for programmers. Programmers are rare species and what it all takes is
a little idea/hint to do the thing
Yii CActiveRecord has a variable isNewRecord, its value is true when an object is created and remains true until a find or save function is not called. When a model calls save function, isNewRecord set to false.
So in your case you need to set this variable "isNewRecord" true each time before save function called or create a new model each time than call the save function.
See the changes in your code::
$model->setIsNewRecord(True); // changes code line
protected function saveImage($formData,$model)
{
if ($formData === null)
return;
$idx=0;
foreach($formData['title'] as $image)
{
$model->setIsNewRecord(True); // for each new record
$model->title = $image;
$file= dirname(Yii::app()->request->scriptFile) . DIRECTORY_SEPARATOR
. DIRECTORY_SEPARATOR .'images\hotelImages'. DIRECTORY_SEPARATOR
. $model->hotel->name;
$model->image = Yii::app()->baseUrl. "/images/hotelImages/".$_FILES['HotelImages']['name'][$idx];//image path
if($model->save())
{
echo $idx.'<br /> it was sucess<br />';
If(file_exists($file))
{
copy($_FILES['HotelImages']['tmp_name'][$idx],$file."/".$_FILES['HotelImages']['name'][$idx]);
}
else
{
mkdir($file);
copy($_FILES['HotelImages']['tmp_name'][$idx],$file."/".$_FILES['HotelImages']['name'][$idx]);
}
$idx++;
}//if there was error
else
{
print_r($model->getErrors());
yii::app()->end();
return FALSE;
}
echo '<br />end reached <br />';
}
yii::app()->end();
return true;
}