Symfony2 - Functional Testing File uploads with dynamically created fields - forms

I'm fighting with functional testing of files uploading.
I will try to simplify my situation. Let's say I have
a company entity, which has 3 fields.
Company {
protected name;
protected tags;
protected images;
}
Images is array of CompanyImage entities, which serve for
storing image files and tags contains array of Tag entities,
which can be m:n connected with companies.
In the form I use jquery, for adding tags and images dynamically.
(you can create images and add them to the company similar to the
collection type symfony tutorial)
Because images and tag arrays are created with jquery, I cannot
simply use something like the turorial line below in the functional test of the company form.
$form['images'][0]->upload('/path/to/image.jpg');
For the setting
of the form values I use simple a little trick described by sstok here
(https://github.com/symfony/symfony/issues/4124)
public function testCompanyCreation() {
...
//option1
$image = new UploadedFile(
'/path/to/image.jpg',
'image.jpg',
'image/jpeg',
123
);
//or option2
//$image = array('tmp_name' => '/path/to/image.jpg', 'name' => 'image.jpg', 'type' => 'image/jpeg', 'size' => 300, 'error' => UPLOAD_ERR_OK);
$companyFormNode = $companyCrawler->selectButton('Create');
$companyForm = $companyFormNode->form();
$values = array(
'company' => array(
'_token' => $companyForm['company[_token]']->getValue(),
'name' => 'test company',
'tags' => array('1'),
'images' => array('0' => (array('file' =>$image))),
),
);
$companySubmitCrawler = $client->request($companyForm->getMethod(), $companyForm->getUri(), $values, $companyForm->getPhpFiles());
}
this works perfectly until I try to upload the image file.
With the option1 I get following exception
Exception: Serialization of 'Symfony\Component\HttpFoundation\File\UploadedFile' is not allowed
when I use option2 I get this
Argument 1 passed to Acme\myBundle\Entity\CompanyImage::setFile() must be an instance of Symfony\Component\HttpFoundation\File\UploadedFile, array given, called in ...\PropertyAccess\PropertyAccessor.php on line 347 and defined (500 Internal Server Error)
I would also like to point out, that the whole form and uploading of the files works without any problems in the browser. I also tried to make the entities serializable, and it didn't help. Do I have a bug somewhere?

I have figured it out (took couple of hours). Files have to be uploaded in a separate array.
$companyForm = $companyFormNode->form();
$values = array(
'company' => array(
'_token' => $companyForm['company[_token]']->getValue(),
'name' => 'test company',
'tags' => array('1')
),
);
$files = array(
'company' => array('images' => array('0' => (array('file' => $image))))
);
$companySubmitCrawler = $client->request(
$companyForm->getMethod(),
$companyForm->getUri(),
$values,
$files
);

Related

TYPO3 TCA make the 'default' value dynamic

The title is rather self explanatory, but what i would like to have is a dynamic default value.
The idea behind it is to get the biggest number from a column in the database and then add one to the result. This result should be saved as the default value.
Lets take for example this code:
$GLOBALS['TCA'][$modelName]['columns']['autojobnumber'] = array(
'exclude' => true,
'label' => 'LLL:EXT:path/To/The/LLL:tx_extension_domain_model_job_autojobnumber',
'config' => [
'type' => 'input',
'size' => 10,
'eval' => 'trim,int',
'readOnly' =>1,
'default' => $result,
]
);
The SQL looks like this:
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_extension_domain_model_job');
$getBiggestNumber = $queryBuilder
->select('autojobnumber')
->from('tx_extension_domain_model_job')
->groupBy('autojobnumber')
->orderBy('autojobnumber', 'DESC')
->setMaxResults(1)
->execute()
->fetchColumn(0);
$result = $getBiggestNumber + 1;
So how can i do that "clean"?
I thought about processCmdmap_preProcess but i dont know how to pass the value to the coorisponding TCA field. Plus i do not get any results on my backend when i use the DebuggerUtility like i get them when i use processDatamap_afterAllOperations after saving the Object.
Can someone point me to the right direction?
I don't think it is supported to create a dynamic default value, see default property of input field.
What you can do however, is to create your own type (use this instead of type="input"). You can use the "user" type. (It might also be possible to create your own renderType for type="input", I never did this, but created custom renderTypes for type= "select").
You can look at the code of InputTextElement, extend that or create your own from scratch.
core code: InputTextElement
documentation for user type
more examples in FormEngine documentation
Example
(slightly modified, from documentation)
ext_localconf.php:
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][<current timestamp>] = [
'nodeName' => 'customInputField',
'priority' => 40,
'class' => \T3docs\Examples\Form\Element\CustomInputElement::class,
];
CustomInputElement
<?php
declare(strict_types = 1);
namespace Myvendor\MyExtension\Backend\FormEngine\Element\CustomInputElement;
use TYPO3\CMS\Backend\Form\Element\AbstractFormElement;
// extend from AbstractFormElement
// alternatively, extend from existing Type and extend it.
class CustomInputElement extends AbstractFormElement
{
public function render():array
{
$resultArray = $this->initializeResultArray();
// add some HTML
$resultArray['html'] = 'something ...';
// ... see docs + core for more info what you can set here!
return $resultArray;
}
}

Can someone provide a php sample using nusoap/sugarcrm api to create an acct/lead in sugarcrn?

Can someone provide a sample code chunk of php using the sugarcrm API/nusoap for adding creating an acct. and then linking a lead to the acct?
I've got a sample function that adds a lead, and I can see how to create an acct, but I can't see how to tie a lead to the acct, to simulate the subpanel process in the sugarcrm acct/subpanel process.
thanks
// Create a new Lead, return the SOAP result
function createLead($data)
{
// Parse the data and store it into a name/value list
// which will then pe passed on to Sugar via SOAP
$name_value_list = array();
foreach($data as $key => $value)
array_push($name_value_list, array('name' => $key, 'value' => $value));
// Fire the set_entry call to the Leads module
$result = $this->soap->call('set_entry', array(
'session' => $this->session,
'module_name' => 'Leads',
'name_value_list' => $name_value_list
));
return $result;
}
$result = $sugar->createLead(array(
'lead_source' => 'Web Site',
'lead_source_description' => 'Inquiry form on the website',
'lead_status' => 'New',
'first_name' => $_POST['first_name'],
'last_name' => $_POST['last_name'],
'email1' => $_POST['email'],
'description' => $_POST['message']
));
You need to find the ID for the account and assign that ID to whatever the account_id field name is in the Lead Module. I have run into a couple things like this before and I have found it easier to go straight to the Sugar database. So, write a statement that will return the account is, for example: SELECT id WHERE something_in_the_account_table = something else;
Then you can assign that id in your $result array. I hope it helps. I didn't have any code or documentation in front of me or I would have helped more.

Example of Zend Form with Collection Element using Forms not Fieldsets in Zend Framework2

I need a straight forward working example how I can include a collection element in Zend Form, I have seen some examples from Zend Framework 2 site and from previous posts in StackOverflow where most of them pointed to this link. But right now I am not using Fieldsets and staying with Forms, so in case if someone can direct me in the right way, how I can include a simple collection element when the user gets a page where the user can choose multiple choices from the shown collection form. Much better would be populating the collection form from database.
I have searched in the internet for quite a sometime now and thought I would post here, so that Zend profis can give their suggestions.
Just For Information:
Normally one can include a static dropdownbox in Zend Form in this fashion
$this->add(
array(
'name' => "countr",
'type' => 'Zend\Form\Element\Select',
'options' => array(
'label' => "Countries",
'options' => array(
'country1' => 'Brazil',
'country2' => 'USA',
'country3' => 'Mexico',
'country4' => 'France',
)
)
)
);
So I am expecting a simple example which could give me a basic idea how this can be done.
To be honest, I don't see your problem here. Since form collections extend Fieldset which extends Element, you can just add it to the form as a regular element. The view helpers will take care of the rendering recursively.
Step 1: Create a form collection (create an instance of Zend\Form\Element\Collection). If the elements have to be added dynamically in some way, I'd create a factory class for this purpose.
Step 2: Add it to the form. (For example using $form->add($myCollectionInstance).)
Step 3: Render it. Zend\Form\View\Helper\Collection is a pretty good view helper to render the whole form without any pain.
You can also create a new class extending Zend\Form\Element\Collection and use the constructor to add the fields you need. Thus, you can add it to the form using the array you've pasted in your question. Also, you could directly use it in annotations.
Hope this helps.
If you just want to fill in a select list with option values you can add the array to the select list in a controller:
$form = new MyForm();
$form->get('countr')->setOptions(array('value_options'=>array(
'country1' => 'Brazil',
'country2' => 'USA',
'country3' => 'Mexico',
'country4' => 'France',
));
the array can be fetched from db.
this is a different example for using form collections in the simplest way.
In this example it creates input text elements in a collection and fills them in. The number of elements depends on the array:
class MyForm extends \Zend\Form\Form
{
$this->add(array(
'type' => '\Zend\Form\Element\Collection',
'name' => 'myCollection',
'options' => array(
'label' => 'My collection',
'allow_add' => true,
)
));
}
class IndexController extends AbstractActionController
{
public function indexAction
{
$form = new MyForm();
$this->addElementsFromArray($form, array(
'country1' => 'Brazil',
'country2' => 'USA',
'country3' => 'Mexico',
'country4' => 'France',
));
//the above line can be replaced if fetching the array from a db table:
//$arrayFromDb = getArrayFromDb();
//$this->addElementsFromArray($form, $arrayFromDb);
return array(
'form' => $form
);
}
private function addElementsFromArray($form, $array)
{
foreach ($array as $key=>$value)
{
$form->get('myCollection')->add(array(
//'type' => '\Zend\Form\Element\SomeElement',
'name' => $key,
'options' => array(
'label' => $key,
),
'attributes' => array(
'value' => $value,
)
));
}
}
}
index.phtml:
$form->setAttribute('action', $this->url('home'))
->prepare();
echo $this->form()->openTag($form);
echo $this->formCollection($form->get('myCollection'));
echo $this->form()->closeTag();

Form with managed files weird behaviour on form error

I have created a content type with an associated image field.
Each user is able to see a list of all the nodes of this content type and should be able to upload a new image in the appropriate field.
I've tried many solutions, but in the end I'm trying with a form and managed files.
In the page with the list of all the nodes I'm creating a lightbox with a form for each node.
Each form is created like this:
function coverupload_form($form, &$form_state, $uid, $relid) {
$form['#attributes']['id'] = 'coverup-'.$relid;
$form_state['storage']['rid'] = $relid;
$cliente = cataloghi_user_edit_get_cliente($uid);
$release = node_load($relid);
$form['cover'] = array(
'#title' => 'Carica la cover per la release '.$release->title,
'#description' => 'I file caricati devono avere estensione \'.jpeg\', risoluzione di 1440x1440 e dimensione massima di 5MB',
'#type' => 'managed_file',
'#upload_location' => 'public://clienti/'.$cliente->title.'/cover',
'#upload_validators' => array(
'file_validate_extensions' => array('jpeg, jpg'),
// Pass the maximum file size in bytes
'file_validate_size' => array(5*1024*1024),
'file_validate_image_resolution' =>array('1440x1440', '1440x1440'),
),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('CARICA'),
);
return $form;
}
function coverupload_form_submit($form, &$form_state) {
$file = file_load($form_state['values']['cover']);
// Change status to permanent.
$file->status = FILE_STATUS_PERMANENT;
// Save.
file_save($file);
$nodo = node_load($form_state['storage']['rid']);
$nodo->field_release_copertina['und'][0] = (array)$file;
if($nodo = node_submit($nodo)) { // Prepare node for saving
node_save($nodo);
}
}
All the forms have display: none, and when the user click on the cover upload button only the corresponding form is showed in the lightbox.
Well, everything works fine when the image is validated.
The problems start when the image is not validated (like if it's below 1440x1440px).
If I check the lightbox with the inspector, the correct number of forms is generated but they all refer to the same node (so they all have id 'coverup-17' for example).
I have checked everything, and it seems like I pass the correct values to the form everytime, so I'm starting to think that it may be a problem connected with my poor understanding of forms.
Would it be better to try a different type of approach?
Thanks and sorry for if this is a bit messy...
I managed to solve the problem.
It depended on the fact that I had multiple instances of the same form on the same page.
I implemented hook_forms().
function mymodule_forms($form_id, $args) {
$forms = array();
if(strpos($form_id, 'coverupload_form_') === 0) {
$forms[$form_id] = array(
'callback' => 'coverupload_form',
'callback arguments' => array($args[0], $args[1]),
);
}
return $forms;
}
and then I changed my form call to
drupal_render(drupal_get_form('coverupload_form_'.$relid, $arg1, $arg2));

Zend_Validate_Db_RecordExists against 2 fields

I usualy use Zend_Validate_Db_RecordExists to update or insert a record. This works fine with one field to check against. How to do it if you have two fields to check?
$validator = new Zend_Validate_Db_RecordExists(
array(
'table' => $this->_name,
'field' => 'id_sector,day_of_week'
)
);
if ($validator->isValid($fields_values['id_sector'],$fields_values['day_of_week'])){
//true
}
I tried it with an array and comma separated list, nothing works... Any help is welcome.
Regards
Andrea
To do this you would have to extend the Zend_Validate_Db_RecordExists class.
It doesn't currently know how to check for the existence of more than one field.
You could just use two different validator instances to check the two fields separately. This is the only work around that I can see right now besides extending it.
If you choose to extend it then you'll have to find some way of passing in all the fields to the constructor ( array seems like a good choice ), and then you'll have to dig into the method that creates the sql query. In this method you'll have to loop over the array of fields that were passed in to the constructor.
You should look into using the exclude parameter. Something like this should do what you want:
$validator = new Zend_Validate_Db_RecordExists(
array(
'table' => $this->_name,
'field' => 'id_sector',
'exclude' => array(
'field' => 'day_of_week',
'value' => $fields_values['day_of_week']
)
);
The exclude field will effectively add to the automatically generated WHERE part to create something equivalent to this:
WHERE `id_sector` = $fields_values['id_sector'] AND `day_of_week` = $fields_values['day_of_week']
Its kind of a hack in that we're using it for the opposite of what it was intended, but its working for me similar to this (I'm using it with Db_NoRecordExists).
Source: Zend_Validate_Db_NoRecordExists example
Sorry for the late reply.
The best option that worked for me is this:
// create an instance of the Zend_Validate_Db_RecordExists class
// pass in the database table name and the first field (as usual)...
$validator = new Zend_Validate_Db_RecordExists(array(
'table' => 'tablename',
'field' => 'first_field'
));
// reset the where clause used by Zend_Validate_Db_RecordExists
$validator->getSelect()->reset('where');
// set again the first field and the second field.
// :value is a named parameter that will be substituted
// by the value passed to the isValid method
$validator->getSelect()->where('first_field = ?', $first_field);
$validator->getSelect()->where('second_field = :value', $second_field);
// add your new record exist based on 2 fields validator to your element.
$element = new Zend_Form_Element_Text('element');
$element->addValidator($validator);
// add the validated element to the form.
$form->addElement($element);
I hope that will help someone :)
Although, I would strongly recommend a neater solution which would be to extend the Zend_Validate_Db_RecordExists class with the above code.
Enjoy!!
Rosario
$dbAdapter = Zend_Db_Table::getDefaultAdapter();
'validators' => array('EmailAddress', $obj= new Zend_Validate_Db_NoRecordExists(array('adapter'=>$dbAdapter,
'field'=>'email',
'table'=>'user',
'exclude'=>array('field'=>'email','value'=>$this->_options['email'], 'field'=>'is_deleted', 'value'=>'1')
))),
For those using Zend 2, If you want to check if user with given id and email exists in table users, It is possible this way.
First, you create the select object that will be use as parameter for the Zend\Validator\Db\RecordExists object
$select = new Zend\Db\Sql\Select();
$select->from('users')
->where->equalTo('id', $user_id)
->where->equalTo('email', $email);
Now, create RecordExists object and check the existence this way
$validator = new Zend\Validator\Db\RecordExists($select);
$validator->setAdapter($dbAdapter);
if ($validator->isValid($username)) {
echo 'This user is valid';
} else {
//get and display errors
$messages = $validator->getMessages();
foreach ($messages as $message) {
echo "$message\n";
}
}
This sample is from ZF2 official doc
You can use the 'exclude' in this parameter pass the second clause that you want to filter through.
$clause = 'table.field2 = value';
$validator = new Zend_Validate_Db_RecordExists(
array(
'table' => 'table',
'field' => 'field1',
'exclude' => $clause
)
);
if ($validator->isValid('value') {
true;
}
I am using zend framework v.3 and validation via InputFilter(), it uses same validation rules as zend framework 2.
In my case I need to check, if location exists in db (by 'id' field) and has needed company's id ('company_id' field).
I implemented it in next way:
$clause = new Operator('company_id', Operator::OP_EQ, $companyId);
$inputFilter->add([
'name' => 'location_id',
'required' => false,
'filters' => [
['name' => 'StringTrim'],
['name' => 'ToInt'],
],
'validators' => [
[
'name' => 'Int',
],
[
'name' => 'dbRecordExists',
'options' => [
'adapter' => $dbAdapterCore,
'table' => 'locations',
'field' => 'id',
'exclude' => $clause,
'messages' => [
'noRecordFound' => "Location does not exist.",
],
]
],
],
]);
In this case validation will pass, only if 'locations' table has item with columns id == $value and company_id == $companyId, like next:
select * from location where id = ? AND company_id = ?