Joomla fields : change dynamically the readonly property - joomla

in Joomla component forms :
is there a way to dynamically change the form field property : "readonly" ?
example :
if( _condition_ )
$this->form->getInput('Name')->readonly = true;

From what I saw in the API, you basically can change it.
I see it like this:
When you call $this->form->getInput('Name') you are inside JFormField object (actually inside an class which interits JFormField, which is abstract - inherited by JFormFieldText for example), calling the method getInput().
This method, getInput(), gets its parameters $element ( SimpleXMLElement object of the XML element that describes the form field.) from what I can see directly from the XML you defined and it returns just a string (actual HTML), so setting and non existing property obviously won't work.
But JForm has a nice method called setFieldAttribute(), see signature below:
/**
* Method to set an attribute value for a field XML element.
*
* #param string $name The name of the form field for which to set the attribute value.
* #param string $attribute The name of the attribute for which to set a value.
* #param mixed $value The value to set for the attribute.
* #param string $group The optional dot-separated form group path on which to find the field.
*
* #return boolean True on success.
*
* #since 11.1
*/
public function setFieldAttribute($name, $attribute, $value, $group = null)
So your code can look like:
if( _condition_ )
{
$this->form->setFieldAttribute('Name', 'readonly', 'true', $group = null);
echo $this->form->getInput('name');
}
Hope this helps.

Related

Use Doctrine SQLLogger in TYPO3 Backend to log all executed SQL queries

We are facing very long load times for the record list view in many pages. To understand what is causing this, we want to analyze the SQL queries executed. (Ultimately, we might want a admin panel for the backend).
Theoretically, Doctrine DBAL supports hooking SQLLogger, but we don't know where the proper Class replacement/injection for this would be.
We did find the ability to patch the file typo3/cms/typo3/sysext/core/Classes/Database/Connection.php and simply create a new method overwriting the parent:
/**
* Debug all the things
*
* If the query is parametrized, a prepared statement is used.
* If an SQLLogger is configured, the execution is logged.
*
* #param string $query The SQL query to execute.
* #param array $params The parameters to bind to the query, if any.
* #param array $types The types the previous parameters are in.
* #param \Doctrine\DBAL\Cache\QueryCacheProfile|null $qcp The query cache profile, optional.
*
* #return \Doctrine\DBAL\Driver\Statement The executed statement.
*
* #throws \Doctrine\DBAL\DBALException
*/
public function executeQuery($query, array $params = array(), $types = array(), QueryCacheProfile $qcp = null) {
$fp = fopen('/var/www/html/logs/mysql.log', 'a'); fwrite($fp, '[QUERY-DOCTRINE] ' . $query . "\n"); fclose($fp);
return parent::executeQuery($query, $params, $types, $qcp);
}
But that approach isn't really portable and requires to patch composer-generated vendor files. Also, it's lacking proper raw logging and the abilities of sophisticated SQLLoggers. So somewhere we should be able to call the Doctrine Configuration class methods?
You can modify/extend the connection class and make the database layer use yor custom class with the config option of wrapperClass that is part of the configuration for the database connection.
work in progress #medz, just created an extension.
https://packagist.org/packages/datenbetrieb/sqllog
requires some config
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['wrapperClass']= \Datenbetrieb\Sqllog\Database\Connection::class;
$GLOBALS['TYPO3_CONF_VARS']['LOG']['Datenbetrieb']['Sqllog']['Database']['Logging']['writerConfiguration'] = array(
\TYPO3\CMS\Core\Log\LogLevel::DEBUG => array(
'TYPO3\\CMS\\Core\\Log\\Writer\\FileWriter' => array(),
),
);

What is the correct way to add validation on the form level in ZF2?

There is a complex form with a lot of nested fieldsets. Some fields need to be validated depending on field(-s) in another fieldset. So I cannot define all the validation rules directly in the getInputFilterSpecification() of the Fieldset, since there I cannot access other fieldsets (only the sub-fieldsets). The only way to do this is to extend the Form validation. Right? If so, how to do this?
MyForm extends Form
{
public function isValid()
{
$isFormValid = parent::isValid();
$isFieldXyzValid = // my additional validation logic
if(! $isFieldXyzValid) {
$fieldXyz->setMessages(...);
}
return $isFormValid && $isFieldXyzValid;
}
}
Like this? Or is a cleaner way to solve this problem?
I've already developed something similar in my previous project.
For doing this i used a service which take my form and set dynamic fieldset, and obviously custom validation rules.
In your controller, get your form (via the dependancy injection formManager (polyfilled or not).
$form = $this->formManager->get('{your form}');
Call your service and give it your form.
And in your service you can do anything you want like :
get your stuff (from DB or others) to determine wich fields are mandatory
Foreach on your form
Add or remove fieldset
Add or remove validationGroup fields
Add or remove filters
Add or remove validators
I performed those via (sample) in a foreach where $stuff is an element of doctrine collection
$nameFieldset = 'my_fieldset-'.$stuff->getId();
$globalValidator = new GlobalValidator();
$globalValidator->setGlobalValue($gloablValue);
$uoValidator = new UcValidator();
$uoValidator->setOptions(array(
'idToValidate' => $stuff->getId(),
'translator' => $this->translator
));
$globalValidator->setOptions(array(
'idToValidate' => $stuff->getId(),
'translator' => $this->translator
));
$name = 'qty-'.$stuff->getId();
$form = $this->setFilters($form, $name, $nameFieldset);
$globalValidator->setData($data);
$form = $this->setValidators($form, $name, $globalValidator, $uoValidator, $nameFieldset);
Where setFilters and setValidators are custom methods wich add filters and validator to my fields (also custom)
/**
* #param myForm $form
* #param $name
* #param string $nameFieldset
* #return myForm
*/
public function setFilters($form, $name, $nameFieldset)
{
$form->getInputFilter()->get('items')->get($nameFieldset)
->get($name)
->getFilterChain()
->getFilters()
->insert(new StripTags())
->insert(new StringTrim());
return $form;
}
/**
* #param myForm $form
* #param $name
* #param $globalValidator
* #param $uoValidator
* #param $nameFieldset
* #return myForm
*/
public function setValidators($form, $name, $globalValidator, $uoValidator, $nameFieldset)
{
$optionsSpace = [
'translator' => $this->translator,
'type' => NotEmpty::SPACE
];
$optionsString = [
'translator' => $this->translator,
'type' => NotEmpty::STRING
];
$optionsDigits = [
'translator' => $this->translator,
];
$form->getInputFilter()->get('items')
->get($nameFieldset)
->get($name)
->setRequired(true)
->getValidatorChain()
->attach($uoValidator, true, 1)
->attach($globalValidator, true, 1)
// We authorize zéro but not space nor strings
->attach(new NotEmpty($optionsSpace), true, 2)
->attach(new NotEmpty($optionsString), true, 2)
->attach(new Digits($optionsDigits), true, 2);
return $form;
}

How can we change the admin form element position in magento?

How can we change the position (Sort Order) of admin form element?
TL;DR:
You can specify a caret ^ as an optional fourth argument when defining your field:
$fieldset->addField('my_element','text',array(
'name' => 'my_element',
'label' => Mage::helper('customer')->__('My Element')
),'^');
More Information
See Varien_Data_Form_Abstract::addField:
/**
* Add child element
*
* if $after parameter is false - then element adds to end of collection
* if $after parameter is null - then element adds to befin of collection
* if $after parameter is string - then element adds after of the element with some id
*
* #param string $elementId
* #param string $type
* #param array $config
* #param mixed $after
* #return Varien_Data_Form_Element_Abstract
*/
public function addField($elementId, $type, $config, $after=false)
{
if (isset($this->_types[$type])) {
$className = $this->_types[$type];
}
else {
$className = 'Varien_Data_Form_Element_'.ucfirst(strtolower($type));
}
$element = new $className($config);
$element->setId($elementId);
if ($element->getRequired()) {
$element->addClass('required-entry');
}
$this->addElement($element, $after);
return $element;
}
The comments tell you how to order your elements. So, to position your field, specify a fourth argument $after of somefield or whatever is the ID of the field you wish to place yours after.
This is useful when you are extending the customer account form within your own class. Here's an example that places a new form element above the first in the form:
class Yourcompany_Adminhtml_Block_Customer_Edit_Tab_Account extends Mage_Adminhtml_Block_Customer_Edit_Tab_Account {
...
public function initForm() {
parent::initForm();
$form=$this->getForm();
$fieldset=$form->getElement('base_fieldset');
$fieldset->addField('my_element','text',array(
'name' => 'my_element',
'label' => Mage::helper('customer')->__('My Element')
),'^');
return $this;
}
...
}
You may notice something strange. My fourth argument to the addField call is a caret ('^'). This places the element at the very top of the form, which is what you appear to be asking in your question.
But wait! Why doesn't this match up to the code documentation shown above?! Well, it looks like a disconnect in consistent coding convention during development. If you follow the code, you will find that addField makes it way to the Varien_Data_Form_Element_Collection::add method. It is in here that we see a 2nd argument, $after, which notes in the comments:
/**
* Add element to collection
*
* #todo get it straight with $after
* #param Varien_Data_Form_Element_Abstract $element
* #param boolean|'^'|string $after
* #return Varien_Data_Form_Element_Abstract
*/
public function add(Varien_Data_Form_Element_Abstract $element, $after=false)
Here we find that false appends the element to the fieldset, a ^ character prepends the element, and passing in an element ID will place the element after the one specified.
UPDATE: How to Deal With Existing Fields
What if you want to re-order an existing field? Unfortunately, ordering takes places at the time of adding the field, and cannot conveniently be changed after that. But I can offer 2 approaches to get the job done.
Method 1: Re-Order by Removing and Adding Again
$fieldset->removeField('core_element');
$fieldset->addField('core_element','text',array(
'name' => 'core_element',
'label' => Mage::helper('customer')->__('Core Element')
),'^');
This is a simple solution, but requires you to manually re-define that field. In some cases this will be easy enough. In others, not so. For those scenarios, see next.
Method 2: Re-Order by Cloning
$element=clone $form->getElement('core_element');
$fieldset->removeField('core_element');
$fieldset->addElement($element,'^');
I think this is the best solution, because it preserves the element definition as it was originally written. This is especially important in the case of attributes whose fields are generated in part by their frontend_input_renderer classes. Learn more about that here.
Check the 'attribute_id' & 'sort_order' fields in 'customer_eav_attribute' table.

how we can add rule in Yii model for input must be greater than 0

do anyone know how can I apply rule in Yii model for input must be greater than 0 value, without any custom approach ..
like :
public function rules()
{
return array(
....
....
array('SalePrice', 'required', "on"=>"sale"),
....
....
);
}
many thanks ..
Simpler way
array('SalePrice', 'numerical', 'min'=>1)
with a custom validator method
array('SalePrice', 'greaterThanZero')
public function greaterThanZero($attribute,$params)
{
if ($this->$attribute<=0)
$this->addError($attribute, 'Saleprice has to be greater than 0');
}
I see it is a price so you could use 0.01 (a penny) as a minimum value like so:
array('SalesPrice', 'numerical', 'min'=>0.01),
Note that this solution does not validate that the number entered is a price, just that it is > 0.01
I know I am too late for this . But just for future reference you can use this class also
<?php
class greaterThanZero extends CValidator
{
/**
* Validates the attribute of the object.
* If there is any error, the error message is added to the object.
* #param CModel $object the object being validated
* #param string $attribute the attribute being validated
*/
protected function validateAttribute($object,$attribute)
{
$value=$object->$attribute;
if($value <= 0)
{
$this->addError($object,$attribute,'your password is too weak!');
}
}
/**
* Returns the JavaScript needed for performing client-side validation.
* #param CModel $object the data object being validated
* #param string $attribute the name of the attribute to be validated.
* #return string the client-side validation script.
* #see CActiveForm::enableClientValidation
*/
public function clientValidateAttribute($object,$attribute)
{
$condition="value<=0";
return "
if(".$condition.") { messages.push(".CJSON::encode($object->getAttributeLabel($attribute).' should be greater than 0').");
}";
}
}
?>
Just make sure this class is imported before use.
Did nobody check the docs?
There is a built-in validator CCompareValidator:
['SalePrice', 'compare', 'operator'=>'>', 'compareValue'=>0]
you can use this one too:
array('SalePrice', 'in','range'=>range(0,90))
I handled this by regular expression, may be it will help too ..
array('SalePrice', 'match', 'not' => false, 'pattern' => '/[^a-zA-Z0]/', 'message' => 'Please enter a Leader Name', "on"=>"sale"),
many thanks #sdjuan & #Ors for your help and time ..

Magento set subscriber first & last name

When someone subscribes to the Magento newsletter I also want them to fill in their first and last name. I have added the two input fields to the form. The field names are 'firstname' and 'lastname'.
I'm going to extend Mage/Newsletter/controllers/SubscriberController.php
In newAction():
I have retrieved the post variables here:
$email = (string) $this->getRequest()->getPost('email');
$firstname = (string) $this->getRequest()->getPost('firstname');
$lastname = (string) $this->getRequest()->getPost('lastname');
I have added the following code after the success message:
$subscriber = Mage::getModel('newsletter/subscriber')->loadByEmail($email);
$subscriber->setEmail("example#email.com");
$subscriber->setFirstname("ADAM");
$subscriber->setLastname("MOSS");
$subscriber->save();
I just want to get the first and last name method working - the setEmail part works perfectly. I looked in Model/Subscriber.php and saw that there's no function for setting subscriber names.
Looking at the grid in the admin I also noticed that it says 'Customer First Name' and 'Customer Last Name' so I assume the names belong to the customer model rather than the subscriber model.
Is there a way around this? I want to be able to assign the customer name to the subscriber when they subscribe to the newsletter. I tried the observer method mentioned on this post, but I think the same issue exists: Adding a custom field to Magento's subscription module
Any help would be much appreciated.
Take a look at newsletter_subscriber table in the database. There is no firstname or lastname. You set these fields only on the newsletter model.
The subscribe() method from subscriber model associate the subscriber to customer id so the grid shows indeed the customer firstname and lastname.
If you want to have these fields also for subscribers that are not associated to cutomers you should modify the newsletter_subscriber database table by adding these two fields.
You must create a local copy of:
app/code/core/Mage/Newsletter/controllers/SubscriberController.php
app/code/core/Mage/Newsletter/Model/Subscriber.php
In app/code/core/Mage/Newsletter/controllers/SubscriberController.php add after line 44:
$firtname = (string) $this->getRequest()->getPost('firstname');
$lastname = (string) $this->getRequest()->getPost('lastname');
Then change from:
$status = Mage::getModel('newsletter/subscriber')->subscribe($email);
to:
$status = Mage::getModel('newsletter/subscriber')->subscribe($email,$firtname,$lastname);
Now in app/code/core/Mage/Newsletter/Model/Subscriber.php edit the subscribe function signature at line 307 from:
public function subscribe($email)
to:
public function subscribe($email,$firstname,$lastname)
Add this after line 338:
$this->setSubscriberFirstname($firstname);
$this->setSubscriberLastname($lastname);
And add the getters and setters for it:
/**
* Alias for getSubscriberFirstname()
*
* #return string
*/
public function getFirstname()
{
return $this->getSubscriberFirstname();
}
/**
* Alias for setSubscriberFirstName()
*
* #param string $value
*/
public function setFirstname($value)
{
return $this->setSubscriberFirstname($value);
}
/**
* Alias for getSubscriberLastname()
*
* #return string
*/
public function getLastname()
{
return $this->getSubscriberLastname();
}
/**
* Alias for setSubscriberLastname()
*
* #param string $value
*/
public function setLastname($value)
{
return $this->setSubscriberLastname($value);
}
You also need to add firstname and lastname columns to newsletter_subscriber as said in the other anwser.

Resources