Get Uploaded File's Original Name - symfony

$request = $event->getRequest();
print_r($request->files);die;
gives me
Symfony\Component\HttpFoundation\FileBag Object
(
[parameters:protected] => Array
(
[files] => Array
(
[0] => Symfony\Component\HttpFoundation\File\UploadedFile Object
(
[test:Symfony\Component\HttpFoundation\File\UploadedFile:private] =>
[originalName:Symfony\Component\HttpFoundation\File\UploadedFile:private] => Chrysanthemum.jpg
[mimeType:Symfony\Component\HttpFoundation\File\UploadedFile:private] => image/jpeg
[size:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 879394
[error:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 0
[pathName:SplFileInfo:private] => /tmp/phpmUl54W
[fileName:SplFileInfo:private] => phpmUl54W
)
)
)
)
I'm trying to get at the value for 'originalname' i.e "Chrysanthemum.jpg" without resorting to a loop, but I can't seem to find the right syntax
Using the 1UP file uploader, but I dont think that's important

When you upload files you get UploadFile (API link) objects (basically the wrappers of array).
$this->getRequest()->files[0]->getClientOriginalName();
Can't try this now but you might need to do this instead:
$this->getRequest()->files['name_of_file_field_in_post']->getClientOriginalName();
where you would replace name_of_file_field_in_post with your form field's name.

2015 Update:
$request->files->get('your-file-name')->getClientOriginalName();
your-file-name for me was just file.
This will probably help too:
https://github.com/1up-lab/OneupUploaderBundle/issues/21

This wound up working for me, I guess the OneUp Class handles it a bit differently
use Oneup\UploaderBundle\Event\PostPersistEvent;
class UploadListener
{
public function onUpload(PostPersistEvent $event)
{
$request = $event->getRequest();
$original_filename = $request->files->get('blueimp')->getClientOriginalName();
}
}
Relevent Frontend
<input id="fileupload" type="file" name="blueimp" data-url="{{ oneup_uploader_endpoint('images') }}" multiple />

I'm using symfony 4,
I wanted to get the files original name. What worked for me is:
$form = $this->createForm(SomeType::class, $object);
if($form->isSubmitted() && $form->isValid()) {
$fileName = $object->getImage()->getClientOriginalName();
}
In my case getImage() is the getter for the name of the file upload field. So that would change to your relevant getter function for the file upload field.

Related

elfinder - copy hardlinks

We move alot of big files and this work flawlessly because this is done in a instance without copying the file. (just moving the pointer)
But sometimes we need acces to the same file from multiple locations in the filesystem, today we copy the file but this takes extremely long time and is storage consuming, this is expected since the file is copied to another place on disk. So we can't complain on this :)
But in our workflow we actually don't have to have multiple files, multiple pointers to the same file is enough. Therefore the hardlink model is perfect choice for us. This would be extremely usefull if it was possible to change the behavior on the copy feature in elfinder, Does anyone know if it is possible. ? :)
It is made possible by extending the elFinderVolumeLocalFileSystem class.
class elFinderVolumeMyLocalFileSystem extends elFinderVolumeLocalFileSystem
{
protected function _copy($source, $targetDir, $name) {
$target = $this->_joinPath($targetDir, $name);
if (! $ret = link($source, $target)) {
return parent::_copy($source, $targetDir, $name);
}
return $ret;
}
}
$opts = array(
'locale' => '',
'roots' => array(
array(
'driver' => 'MyLocalFileSystem',
'path' => '/path/to/files/',
'URL' => 'http://localhost/to/files/'
)
)
);
// run elFinder
$connector = new elFinderConnector(new elFinder($opts));
$connector->run();

Find YAML by key and change the value

I want to parse the contents of any .yml file and modify any key.
Let's take the security.yml file, get its contents and use Yaml::parse, which will return an array of arrays with its structure.
$yml='/config/security.yml';
$path = $this->get('kernel')->getRootDir().$yml;
$contents= Yaml::parse(file_get_contents($file));
This outputs
array(1) {
["security"]=>
array(5) {
["encoders"]=>
string(8) "Array(1)"
["role_hierarchy"]=>
string(8) "Array(3)"
["providers"]=>
string(8) "Array(2)"
["firewalls"]=>
string(8) "Array(2)"
["access_control"]=>
string(9) "Array(14)"
}
}
So far so good. Now let's say I want to change the value of security.firewalls.main.pattern. I need to change the array value $contents['security']['firewalls']['main']['pattern'] and then file_put_contents the yaml dump.
My question is how to get and set a parameter value, dynamically, by any key and not hard-code it like above. The Yaml parser doesn't have any way to get a value by its key. I need a way to transform security.firewalls.main.pattern into array keys, somehow. I will delete the cache afterwards, obviously.
I made something in the meanwhile:
$array = Yaml::parse(file_get_contents($file));
$keys=array("security","firewalls","main");
$val = $this->parseYmlArray($array, $keys);
public function parseYmlArray($array, $keys)
{
$newArr = $array;
foreach ($keys as $key) {
$newArr = $newArr[$key];
}
return $newArr;
}
This will return whatever node, but it needs an array in the exact order of the keys depth.
I was thinking initially if I could make a ParameterBag just like the one in the Container. The problem is that I can't seem to find where it is created from an associative array in depth to one like key->value(security.firewalls.main.pattern and its value, for instance). If I try to create a ParameterBag out of an array, it doesn't modify that array, the bag contains the exact same array. I'm trying to find where the array is being parsed and transformed into the one in the container.
Actually, I don't see any alternative to update your configuration values directly.
But, you can achieve this by defining parameters.
For example, you can change your security.firewalls.main.pattern like follows:
parameters:
firewall_main_pattern: ^/yourpattern
# ...
firewalls:
# ...
main:
pattern: %firewall_main_pattern%
# ...
Then, update the parameter as needed:
$this->container->setParameter('firewall_main_pattern', '^/yournewpattern');
Hope this solves to your problem.
Update
In the same kind of your parseYmlArray, you can use the following to change a value :
function assignConfigurationValueByPath(&$array, $path, $value) {
$keys = explode('.', $path);
while ($key = array_shift($keys)) {
$arr = &$arr[$key];
}
$arr = $value;
}
$array = Yaml::parse(file_get_contents($file));
assignConfigurationValueByPath($array, 'security.firewalls.main.pattern, 'new_value');
Now $array is changed to:
array(
'security' => array(
// ...
'firewalls' => array(
// ...
'main' => array(
// ...
'pattern' => 'new_value'
),
),
),
):

Filter ModelAdmin by many_many relation

I'm managing the DataObject class 'trainer' with ModelAdmin. A trainer has a many_many relation to my other class 'language'.
On my 'trainer' class I'm manipulating the 'searchableFields' function to display a ListboxField in the filters area.
public function searchableFields() {
$languagesField = ListboxField::create(
'Languages',
'Sprachen',
Language::get()->map()->toArray()
)->setMultiple(true);
return array (
'Languages' => array (
'filter' => 'ExactMatchFilter',
'title' => 'Sprachen',
'field' => $languagesField
)
);
}
That works like expected and shows me the wanted ListboxField. The Problem is, after selecting 1 or 2 or whatever languages and submitting the form, I'm receiving
[Warning] trim() expects parameter 1 to be string, array given
Is it possible here to filter with an many_many relation? And if so, how? Would be great if someone could point me in the right direction.
Update:
Full Error Message: http://www.sspaste.com/paste/show/56589337eea35
Trainer Class: http://www.sspaste.com/paste/show/56589441428d0
You need to define that logic within a $searchable_fields parameter instead of the searchableFields() which actually constructs the searchable fields and logic.
PHP would be likely to throw an error if you go doing fancy form stuff within the array itself, so farm that form field off to a separate method in the same DataObject and simply call upon it.
See my example, I hope it helps.
/* Define this DataObjects searchable Fields */
private static $searchable_fields = array(
'Languages' => array (
'filter' => 'ExactMatchFilter',
'title' => 'Sprachen',
'field' => self::languagesField()
)
);
/* Return the searchable field for Languages */
public function languagesField() {
return ListboxField::create(
'Languages',
'Sprachen',
Language::get()->map()->toArray()
)->setMultiple(true);
}
Yes, it's possible. You just need to override two methods - one in Trainer data object and one in TrainerModelAdmin. First one will make a field, second one will do filtering.
Trainer Data Object:
public function scaffoldSearchFields($_params = null)
{
$fields = parent::scaffoldSearchFields($_params);
// get values from query, if set
$query = Controller::curr()->request->getVar('q');
$value = !empty($query['Languages']) && !empty($query['Languages']) ? $query['Languages'] : array();
// create a field with options and values
$lang = ListboxField::create("Languages", "Sprachen", Language::get()->map()->toArray(), $value, null, true);
// push it to field list
$fields->push($lang);
return $fields;
}
Trainer Model Admin
public function getList()
{
$list = parent::getList();
// check if managed model is right and is query set
$query = $this->request->getVar('q');
if ($this->modelClass === "Trainer" && !empty($query['Languages']) && !empty($query['Languages']))
{
// cast all values to integer, just to be sure
$ids = array();
foreach ($query['Languages'] as $lang)
{
$ids[] = (int)$lang;
}
// make a condition for query
$langs = join(",", $ids);
// run the query and take only trainer IDs
$trainers = DB::query("SELECT * FROM Trainer_Languages WHERE LanguageID IN ({$langs})")->column("TrainerID");
// filter query on those IDs and return it
return $list->filter("ID", $trainers);
}
return $list;
}

Illegal offset type in isset or empty in EntityChoiceList.php line 273

Within my Symfony2 project I've attempted to dynamically generate the entities used within my form type, by-passing the use of query builder etc.
To he entity choices property I am supplying an array of entities to be used. On page load everything seems fine and the correct content is displayed. However on form submission I get
Illegal offset type in isset or empty in EntityChoiceList.php line 273
at ErrorHandler ->handle ('2', 'Illegal offset type in isset or empty',
'..../Symfony/Bridge/Doctrine/Form/ChoiceList/EntityChoiceList.php', '273', array('key' => object(myEntity))) in ..../Symfony/Bridge/Doctrine/Form/ChoiceList/EntityChoiceList.php at line 273
.....
return isset($entities[$key]) ? $entities[$key] : null;
.....
What has me stumped is if I add var_dump(isset($this->entities[$key]));exit; above this line I am returned 'bool(true)' which to me means the key does exist.
As background I have attempted to extend the EntityType, for ease within my project and added:
public function getDefaultOptions(array $options)
{
$defaultOptions = array(
'em' => null,
'class' => 'Acme\TestBundle\Entity\myEntity',
'property' => null,
'query_builder' => null,
'choices' => $this->myEntityArray,
);
$options = array_replace($defaultOptions, $options);
$defaults = parent::getDefaultOptions($options);
return $defaults;
}
Has any one any ideas why I getting this error, or am I going about my issue all wrong anyway, with trying to pass an array of entities to choices?
If you're getting this while trying to remove an element from an ArrayCollection it's probably because you've typed:
$list->remove($item) instead of $list->removeElement($item)
I'm guessing you already solved this some other way, and this isn't a real answer either.
But I'm guessing either $entities isn't an array on that point, or $key isn't a scalar value.
For debugging you should use:
<?php
if (!is_array($entities) || !is_scalar($key)) {
var_dump($key, $entities));exit;
}
How you now tested this, it would stop on the first pass in that function. Symfony Forms use quit a lot of recursion, so an exit in any function usually doesn't help you.

Symfony2 Functional test: Passing form data directly

I am using phpunit to run functional tests but I am having a problem with a few of the forms. The problem is that phpunit is not aware of JS, and I have a form with a dynamically populated select box that needs jQuery.
So I need to pass the form data directly. The 'book' gives the following example:
// Directly submit a form (but using the Crawler is easier!)
$client->request('POST', '/submit', array('name' => 'Fabien'));
When I used this example the controller didn't receive any of the form data. Intially I saw that passing the array key 'name' wasn't correct in my situation as I needed the form name which was 'timesheet' in my code. So I tried something like:
$client->request('POST', '/timesheet/create', array('timesheet[project]' => '100'));
But this still didn't work. In the controller I tried to understand what was happening and what if anything was being received:
$postData = $request->request->get('timesheet');
$project = $postData['project'];
This didn't work and $project remained empty. However if I used the following code I got the value:
$project = $request->request->get('timesheet[project]');
But clearly that's not what I want. Atleast though I can see that there is some POST data. My last attempt was to try the following in the test method:
$this->crawler = $this->client->request('POST', '/timesheet/create/', array('timesheet' => array(project => '100'));
So I am trying to pass a 'timesheet' array as the first element of the request parameter array. But with this I get the error:
Symfony\Component\Form\Exception\UnexpectedTypeException: Expected argument of type "array", "string" given (uncaught exception) at /mnt/hgfs/pmt/src/vendor/symfony/src/Symfony/Component/Form/Form.php line 489
I would be very happy if someone can expand on what's in the 'book' about how I am supposed to get this working.
Form bind in controller:
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
$postData = $request->request->get('timesheet');
$project = $postData['project'];
$timesheetmanager = $this->get('wlp_pmt.timesheet_db_access');
$timesheetmanager->editTimesheet($timesheet);
return $this->redirect($this->generateUrl('timesheet_list'));
}
}
If you are wanting to know how to inject arrays of POST data using the test client...
In your test method, do something like
$crawler = $client->request('POST', '/foo', array(
'animal_sounds' => array(
'cow' => 'moo',
'duck' => 'quack'
)
); // This would encode to '/foo?animal_sounds%5Bcow%5D=moo&animal_sounds%5Bduck%5D=quack'
$this->assertTrue( ... );
In the controller, you would access your params like this:
$data = $request->request->get('animal_sounds');
$cowNoise = $data['cow'];
$duckNoise = $data['duck'];
Or you could just use the forms API if the test method was injecting valid form data...
do you have a $request parameter in your action?
that was the reason why my request->get() was empty:
//WRONG
public function projectAction()
{
$request = Request::createFromGlobals();
$project = $request->request->get('timesheet[project]');
//$project will be empty
}
//CORRECT
public function projectAction(Request $request)
{
$project = $request->request->get('timesheet[project]');
//$project is not empty
}
see
How do I create a functional test which includes a POST to a page with parameters?
Try to use $form->bind($clientData) instead of $form->bindRequest($request).

Resources