I have a model, for example SomeForm. There is a field. This field contains an array of selected options. Is it possible to write a rule for this field to check how many items were selected? I need to write a condition, that user has to check minimum 2 options and maximum 5.
I tried something like this, but it doesn't work (the form can be submitted if at least one option is selected)
public function rules()
{
return [
[['ingredients'], 'required'],
['ingredients', 'checkIsArray']
];
}
public function checkIsArray($attribute, $params)
{
if (empty($this->ingredients)) {
$this->addError($attribute, "config cannot be empty");
}
elseif (count($this->ingredients)>5) {
$this->addError($attribute, "Choose more");
}
elseif (count($params)<2) {
$this->addError($attribute, "Choose less");
}
}
Yes you can, but you have a wrong assignment of variable i.e $params in the last condition elseif (count($params)<2) you are counting $params instead of the $this->ingredients array. And you do not need to have the first check, adding the attribute to the required rule is enough to check if it is empty when submitted.
change the validation function to
public function checkIsArray( $attribute , $params ) {
if ( count ( $this->ingredients ) > 5 ) {
$this->addError ( $attribute , "Choose No more than 5" );
} elseif ( count ( $this->ingredients ) < 2 ) {
$this->addError ( $attribute , "Choose No less than 2" );
}
}
I just tested it before posting with the kartik\Select2 multiselect and it works just fine, but if it still reacts the same you need to add the controller/action code hope it helps you out.
Related
Hello I want to access an specific array item based in a condition previously checked. I leave the code here:
elsif (scalar(#{$boss->bosses}) > 1) {
foreach my $pa (#{$boss->bosses}) {
my $p = My::Model::Group->new(id => $pa->group_id);
push(#$groups, $p);
$valid_pass = 1 if ($pa->checkPassword($self->param('password')));
}
if ($valid_pass) {
my $pa_id = $pa->id;
my $pa_partner_id = $pa->group_id;
}
else {
}
}
What I want to do is, if that if in the array that comes, I check if the password is correct, so if it's correct, then I want to take the id and the group_id of the array item to use it in a function to be able to log them in.
Your for loop is doing two things at once: producing a list of My::Model::Group objects in #$groups, and finding the first boss whose password checks out.
I suggest that you split them up into two clear operations, and the List::Util modules first operator is ideal for the second task
Here's how it would look. I've extracted the result of the method call $boss->bosses into a variable $bosses to avoid repeated calls to the method
Note that you don't need to apply scalar to an array when checking its size. The > and all the other comparators impose scalar context anyway
I've taken much of my code from your question, and I'm a little concerned that you extract values for $pa_id and $pa_partner_id and then just discard them. But I imagine that you know what you really want to do here
use List::Util 'first';
my $bosses = $boss->bosses;
if ( ... ) {
...;
}
elsif ( #$bosses > 1 ) {
#$groups = map { My::Model::Group->new( id => $_->group_id ) } #$bosses;
my $password = $self->param( 'password' );
my $pa = first { $_->checkPassword( $password ) } #$bosses;
if ( $pa ) {
my $pa_id = $pa->id;
my $pa_partner_id = $pa->group_id;
}
else {
...;
}
}
Inside my User model I would like to make a isMember function.
public function isMember()
{
return(\Auth::check() && "get the status value here" == 1)
}
I got two models. User, Club.
Their pivot table: club_user
user_id
club_id
status
The 'status' column holds 0 or 1.
Now, how do i check the value for the extra column 'status'?
Update:
It's a many-to-many relationship.
Try This:
public function isMember(){
if(\Auth::check())
return (bool) $this->status;
return false;
Well, I got it to work. If somebody got some suggestions how to make it better, please fell free.
public function isMember($clubId)
{
$user = Club::find($clubId)->user()->where('club_user.user_id', \Auth::id())->first();
if (is_object($user))
{
$status = $user->pivot->status;
else
{
$status = 0;
}
return (\Auth::user() && $status == 1);
}
I am using Gravity form. I have more 400 forms. I want to add a parameter name in every form and in a particular field. I know how to add the parameter in a Gravity form field.
But i want to add parameter in each form like search replace. Is there any trick available for Gravity form. Because it is so time taking to add a parameter name in each form.
something like this should do it:
add_filter( 'gform_pre_render', function( $form ) {
foreach( $form['fields'] as &$field ) {
// if( field you want ) {
$field->allowsPrepopulate = true;
$field->inputName = 'your_parameter';
// }
}
}, 9 );
You will need to determine the best way to identify the fields you wish to apply this to. You'll see I've left the condition commented out. If they all have the same field ID you could do:
if( $field->id == 1 ) { ... }
If they'll have the same label, you could do:
if( $field->label == 'My Label' ) { ... }
I'm looking for a hook that let's me modify the database output, when editing my extension in the backend, before it's printed to the TCE fields.
I tried getSingleField_preProcess in class.t3lib_tceforms.php but that did not contain any relevant data to my extension.
getSingleField_preProcess should be the correct hook for what you want. I think the problem is that your function is called for records of every table, not just yours. You have to differentiate when to do any processing based on the table that is being rendered. The name of the table is passed to your getSingleField_preProcess() method.
Your ext_localconf.php should register your hook:
$GLOBALS ['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tceforms.php']['getSingleFieldClass'][] = 'tx_yourextension_be';
...where tx_yourextension_be is the name of your class designated for the backend processing. This class then must contain getSingleField_preProcess() method:
public function getSingleField_preProcess($table, $field, &$row, $altName, $palette, $extra, $pal, &$pObj) {
// ...processing...
}
As you see, several variables are passed to your method. $table contains the name of the table to which the processed record belongs to. $field is the name of the field that is being rendered. $row contains the whole record that you can manipulate.
Probably you want to use TCEmain hook
function processDatamap_preProcessFieldArray(array &$incomingFieldArray, $table, $id, t3lib_TCEmain &$reference) {
if ($table == 'tx_yourext_table') {
$a = $incomingFieldArray['field_a'];
$b = $incomingFieldArray['field_b'];
$incomingFieldArray['field_c'] = $a . ' ' . $b;
}
}
OR/AND
function processDatamap_afterDatabaseOperations($status, $table, $id, $fieldArray, &$reference) {
if ($table == 'tx_yourext_table') {
if ($status == 'update') {
$this->doSomethingWithRecordAfterUpdate($id);
}
}
}
Of course you need to register the hook in ext_localconf.php of your extension, for an example:
$GLOBALS ['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass']['yourext']
= 'EXT:yourext/class.tx_yourext_tcemain.php:tx_yourext_tcemain';
In Zend Form, if two elements have the same order, then Zend will totally ignores the second element (instead of displaying it under the first). Take the following code as an example. Notice that the City and Zip Code elements have the same order of 4
$address = new Zend_Form_Element_Textarea('address');
$address->setLabel('Address')
->setAttrib('cols', 20)
->setAttrib('rows', 2)
->setOrder(3)
;
$city = new Zend_Form_Element_Text('city');
$city->setLabel('City')
->setOrder(4)
;
$postal = new Zend_Form_Element_Text('postal');
$postal->setLabel('Zip Code')
->setOrder(4);
When this form renders, the Zip Code element is nowhere to be found.
If I want to set elements like a buttons dynamically, but tell it to render at the end of the form, how would I do this and not run into the problem of having two elements with the same order?
public function addSubmitButton($label = "Submit", $order = null)
{
$form_name = $this->getName();
// Convert Label to a lowercase no spaces handle
$handle = strtolower(str_replace(" ","_",$label));
$submit = new Zend_Form_Element_Submit($handle);
$submit->setLabel($label)
->setAttrib('id', $form_name . "_" . $handle)
;
///////// Set the button order to be at the end of the form /////////
$submit->setOrder(??????);
$this->addElement($submit);
}
If you really need to use the setOrder() method, I'd work with order numbers 10, 20, 30, 40, ... This way it will be easy to add elements in between already set Elements.
Furthermore, in order to avoid using order-numbers twice, you could use an array, where you store all the numbers from 1 to X. Whenever you set an order number, you set it via a method called getOrderNumberFromArray() which returns the next higher or lower order number still available in the array and unsets this array element.
Alternatively, and maybe even better, you could do getOrder() on the element you want to have before the new element, then increment this order number by X and then loop through the existing form elements and check that the order number doesn't exist yet.
Or you could just use getOrder() on the Element you want to show before and after the new element and make sure you don't use the same order numbers for the new element.
Sorry to be late to the question. What I did was extend Zend_Form and override the _sort() method as follows:
/**
* Sort items according to their order
*
* #return void
*/
protected function _sort()
{
if ($this->_orderUpdated) {
$items = array();
$index = 0;
foreach ($this->_order as $key => $order) {
if (null === $order) {
if (null === ($order = $this->{$key}->getOrder())) {
while (array_search($index, $this->_order, true)) {
++$index;
}
$items[$index][]= $key;
++$index;
} else {
$items[$order][]= $key;
}
} else {
$items[$order][]= $key;
}
}
ksort($items);
$index = 0;
foreach($items as $i=>$item){
foreach($item as $subItem){
$newItems[$index++]=$subItem;
}
}
$items = array_flip($newItems);
asort($items);
$this->_order = $items;
$this->_orderUpdated = false;
}
}
This differs from the original sort method by putting the items in an array based off of their index and then doing a depth-first traversal to flatten the array.
Try this code:
$elements = array();
$elements[] = new Zend_Form_Element_Textarea('address');
......
$elements[] = new Zend_Form_Element_Text('city');
.......
$elements[] = new Zend_Form_Element_Submit($handle);
.....
$this->addElements($elements);
All you need to do is add them in the order you want them to show
what i would do is - use a temp array for that - in that keep the element names in desired order (don't mind the keys). Then use foreach like this:
foreach(array_values($tempArray) as $order => $name) {
$form->$name->setOrder($order+1);
}
Note the array_values - it will return the values as numbered array ;) Not sure if setOrder(0) works - that's why there is +1