I am using code igniter form_validation class to perform a number of validations, since codeigniter validates all the fields and then shows a list of all the errors, I need to restrict this to show only the first error that occurred.
Eg.
If I have 2 (email, message) fields with the required validation in place, and if I were to leave both fields blank. I need codeigniter to show only the error The Email Field is required.
To my knowledge CI doesn't come with this out of the box, but it's easy enough to implement:
Firstly, (if you don't have this file already) create the file MY_Form_validation.php in application/libraries/ with the following:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation {
public function __construct($rules = array())
{
parent::__construct($rules);
}
}
Then add the following method to that class:
/**
* First Error
*
* Returns the first error messages as a string, wrapped in the error delimiters
*
* #access public
* #param string
* #param string
* #return str
*/
public function first_error($prefix = '', $suffix = '')
{
// No errrors, validation passes!
if (count($this->_error_array) === 0)
{
return '';
}
if ($prefix == '')
{
$prefix = $this->_error_prefix;
}
if ($suffix == '')
{
$suffix = $this->_error_suffix;
}
// Generate the error string
$str = '';
foreach ($this->_error_array as $val)
{
if ($val != '')
{
return $prefix.$val.$suffix."\n";
}
}
return $str;
}
This way you'll be able to access this with $this->form_validation->first_error()
Alternatively, you can create a helper function similar to validation_errors() by (if the file doesn't exist) creating a file called MY_form_helper.php in application/helpers/
and then adding the following code:
/**
* First Validation Error String
*
* Returns the first error associated with a form submission. This is a helper
* function for the form validation class.
*
* #access public
* #param string
* #param string
* #return string
*/
if ( ! function_exists('first_validation_error'))
{
function first_validation_error($prefix = '', $suffix = '')
{
if (FALSE === ($OBJ =& _get_validation_object()))
{
return '';
}
return $OBJ->first_error($prefix, $suffix);
}
}
Hope this helps!
Related
Normally TYPO3 assigns a variable in FrontEnd with the name validationResults and it looks like that.
Then we have to iterate through the Error objects and get a list with all the errors and their messages. But there is no way to take each one individually and assign it on the corresponding field where the error appears.
So the question is, how do i do it?
Best regards,
After some programming and a help from larry-pete (typo3.slack.com) i found a solution.
I created my own ViewHelper and it looks like this:
ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['fluid']['namespaces']['mytag'][] = 'Vendor\\ExtensionName\\ViewHelpers';
Classes/ViewHelpers/Form/ErrorViewHelper.php
namespace Vendor\ExtensionName\ViewHelpers\Form;
use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFieldViewHelper;
class ErrorViewHelper extends AbstractFormFieldViewHelper
{
use CompileWithRenderStatic;
/**
* As this ViewHelper renders HTML, the output must not be escaped.
*
* #var bool
*/
protected $escapeOutput = false;
public function initializeArguments()
{
$this->registerArgument('for', 'string', 'The name of the error name (e.g. argument name or property name). This can also be a property path (like blog.title), and will then only display the validation errors of that property.', false, '');
$this->registerArgument('as', 'string', '', false, 'flattenedErrors');
}
/**
* #param array $arguments
* #param \Closure $renderChildrenClosure
* #param RenderingContextInterface $renderingContext
* #return mixed
*/
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
{
$as = $arguments['as'];
$for = $arguments['for'];
$templateVariableContainer = $renderingContext->getVariableProvider();
$controllerContext = $renderingContext->getcontrollerContext();
$validationResults = $controllerContext->getRequest()->getOriginalRequestMappingResults();
if ($validationResults !== null){
$validationResults = $validationResults->forProperty($for);
}
$flattenedErrors = $validationResults->getErrors();
$output = $renderChildrenClosure();
$withKeys = [];
if (empty($output)) {
if ($flattenedErrors) {
foreach ($flattenedErrors as $error) {
$withKeys[$error->getTitle()] = $error;
}
}
}
$templateVariableContainer->add($as, $withKeys);
return $output;
}
}
Form.html
<mytag:form.error as="error" for="error"/>
And this returns:
So now, you can do something like that:
<f:if condition="{offer.firstName}"><span style="display: block">{offer.firstName.message}</span></f:if>
Best regards
I changed your Viewhelper a bit because it didn't worked in my version (typo3 9)
<?php
namespace Vendor\Extension\ViewHelpers;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
class ErrorViewHelper extends AbstractViewHelper
{
use CompileWithRenderStatic;
/**
* As this ViewHelper renders HTML, the output must not be escaped.
*
* #var bool
*/
protected $escapeOutput = false;
public function initializeArguments()
{
$this->registerArgument('for', 'string', 'The name of the error name (e.g. argument name or property name). This can also be a property path (like blog.title), and will then only display the validation errors of that property.', false, '');
}
/**
* #param array $arguments
* #param \Closure $renderChildrenClosure
* #param RenderingContextInterface $renderingContext
* #return mixed
*/
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
$for = $arguments['for'];
$controllerContext = $renderingContext->getControllerContext();
$validationResults = $controllerContext->getRequest()->getOriginalRequestMappingResults();
if ($validationResults !== null) {
$validationResults = $validationResults->forProperty($for);
}
$flattenedErrors = $validationResults->getFlattenedErrors();
return $flattenedErrors;
}
}
you can do:
{myExt:error() -> f:variable(name: 'errors')}}
or
{ff:error( for:"user" ) -> f:variable(name: 'errors')}}
Auto-generate BOOLEAN getters and setters - different output
Symfony3.2.0: php bin/console vs PhpStorm 2016.3
There seems to be a difference in generated code if I use the command line doctrine:generate:entities or use the PhpStorm function Generate - Getters and Setters on a BOOLEAN value within an Entity class.
Example: I have set this private variable, below are 3 examples to generate Getters/Setters, which all give a slightly different output.
/**
* #var boolean
* #ORM\Column(name="active", type="boolean")
*/
private $active;
# Generated 'getter' from command line = getActive()
# Generated 'getter' from PhpStorm = isActive()
Console command: php bin/console doctrine:generate:entities MyBundle:MyEntity (note: getActive, return boolean)
/**
* Set active
*
* #param boolean $active
*
* #return MyEntity
*/
public function setActive($active)
{
$this->active = $active;
return $this;
}
/**
* Get active
*
* #return boolean
*/
public function getActive()
{
return $this->active;
}
Within PhpStorm - Code > Generate (Alt+Insert) > Getters and Setters (with checkbox 'Fluent setters' enabled) (note: isActive, return bool)
/**
* #return bool
*/
public function isActive()
{
return $this->active;
}
/**
* #param bool $active
* #return MyEntity
*/
public function setActive($active)
{
$this->active = $active;
return $this;
}
and another one: PhpStorm - Code > Generate (Alt+Insert) > Getters and Setters (with checkbox 'Fluent setters' disabled) (note: isActive, return bool, and setActive does not return $this)
/**
* #return bool
*/
public function isActive()
{
return $this->active;
}
/**
* #param bool $active
*/
public function setActive($active)
{
$this->active = $active;
}
My Questions:
Can the commandline tool doctrine:generate:entities be configured somehow to generate getters for boolean values automatically as is... in stead of 'get...' ? (so that it always generates boolean getter methods as: isActive(), isEnabled(), etc)
I saw some examples/tutorials where the method setActive() did not return $this, so no chaining could be used. Is it best practice to return $this? What would be the preferred way? (Is there a disadvantage when you DO return $this, performance maybe?)
Does the minor difference of the return type within the comment section has any effect on the app (database migrations with the command line or something)? Or are the types bool and boolean handled the same way everywhere in Symfony?
(3. Example)
#return bool (Generated by command line)
vs
#return boolean (Generated by PhpStorm)
I've played with the code a bit and unfortunately there is no way to generate it differently with the existent setup. All classes are hardcoded and there is no way to override it with command or Symfony settings.
So I've extended generator classes a bit and created extended command that accepts generator as a parameter. I've also created sample generator that created 'is...' methods for setting booleans.
Unfortunately there are some copy-paste from existent classes because it is not possible to extend it.
Answering 2nd question I think that it is more personal preference using fluent interface. I'm old school developer and I'm not used to fluent interface in PHP. I do not see any major performance impact with it.
For the 3rd question. The difference between bool and boolean is that bool is a scalar type declaration while the boolean is a variable type. See the 'Warning' in the documentation. It explains a lot.
<?php
// src/AppBundle/Command/GenerateDoctrineEntityExtendedCommand.php
namespace AppBundle\Command;
use Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineEntityCommand;
use Sensio\Bundle\GeneratorBundle\Generator\Generator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class GenerateDoctrineEntityExtendedCommand extends GenerateDoctrineEntityCommand
{
/** #var Generator */
private $generator;
protected function configure()
{
parent::configure();
$this->setName('doctrine:generate:entity:extended');
$this->setDescription($this->getDescription() . " Allows specifying generator class.");
$this->addOption('generator', null, InputOption::VALUE_REQUIRED, "The generator class to create entity.", 'Sensio\Bundle\GeneratorBundle\Generator\DoctrineEntityGenerator');
}
protected function initialize(InputInterface $input, OutputInterface $output)
{
parent::initialize($input, $output);
if ($class = $input->getOption('generator')) {
if (!class_exists($class)) {
throw new \Exception('Class ' . $class . 'does not exist.');
}
$this->generator = new $class($this->getContainer()->get('filesystem'), $this->getContainer()->get('doctrine'));
}
}
protected function createGenerator()
{
return $this->generator;
}
}
DoctrineEntityGenerator replacement:
<?php
// src/AppBundle/Generator/IsDoctrineEntityGenerator.php
namespace AppBundle\Generator;
use Sensio\Bundle\GeneratorBundle\Generator\DoctrineEntityGenerator;
class IsDoctrineEntityGenerator extends DoctrineEntityGenerator
{
protected function getEntityGenerator()
{
// This is the place where customized entity generator is instantiated instead of default
$entityGenerator = new IsEntityGenerator();
$entityGenerator->setGenerateAnnotations(false);
$entityGenerator->setGenerateStubMethods(true);
$entityGenerator->setRegenerateEntityIfExists(false);
$entityGenerator->setUpdateEntityIfExists(true);
$entityGenerator->setNumSpaces(4);
$entityGenerator->setAnnotationPrefix('ORM\\');
return $entityGenerator;
}
}
EntityGenerator replacement:
<?php
// src/AppBundle/Generator/IsEntityGenerator.php
namespace AppBundle\Generator;
use Doctrine\Common\Inflector\Inflector;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Tools\EntityGenerator;
use Doctrine\DBAL\Types\Type;
class IsEntityGenerator extends EntityGenerator
{
protected function generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null, $defaultValue = null)
{
//
// This is the only line I've added compared to the original method
//
$methodPrefix = ($type == 'get' && $typeHint == 'boolean') ? 'is' : $type;
$methodName = $methodPrefix . Inflector::classify($fieldName);
$variableName = Inflector::camelize($fieldName);
if (in_array($type, array("add", "remove"))) {
$methodName = Inflector::singularize($methodName);
$variableName = Inflector::singularize($variableName);
}
if ($this->hasMethod($methodName, $metadata)) {
return '';
}
$this->staticReflection[$metadata->name]['methods'][] = strtolower($methodName);
$var = sprintf('%sMethodTemplate', $type);
$template = static::$$var;
$methodTypeHint = null;
$types = Type::getTypesMap();
$variableType = $typeHint ? $this->getType($typeHint) : null;
if ($typeHint && !isset($types[$typeHint])) {
$variableType = '\\' . ltrim($variableType, '\\');
$methodTypeHint = '\\' . $typeHint . ' ';
}
$replacements = array(
'<description>' => ucfirst($type) . ' ' . $variableName,
'<methodTypeHint>' => $methodTypeHint,
'<variableType>' => $variableType,
'<variableName>' => $variableName,
'<methodName>' => $methodName,
'<fieldName>' => $fieldName,
'<variableDefault>' => ($defaultValue !== null) ? (' = ' . $defaultValue) : '',
'<entity>' => $this->getClassName($metadata)
);
$method = str_replace(
array_keys($replacements),
array_values($replacements),
$template
);
return $this->prefixCodeWithSpaces($method);
}
}
So that's I'm afraid the only option for what you want so far.
Stepashka correctly answered.
But I think there is a better, simplified and more conventional way to help you to use PhpStorm auto generate Getters and Setters methods with Symfony.
You can customize PhpStorm Getters and Setters generation methods!
You just have to go to :
Preferences/Editor/File and Code Templates/Code
Then for Getter, to modify isActive to getActive you have to change "PHP Getter Method" to :
/*
* #return ${TYPE_HINT}
*/
public ${STATIC} function get${NAME}()#if(${RETURN_TYPE}): ${RETURN_TYPE}#else#end
{
#if (${STATIC} == "static")
return self::$${FIELD_NAME};
#else
return $this->${FIELD_NAME};
#end
}
for Setter, to add "return $this" you have to change "PHP Setter Method" to:
/*
* #param ${TYPE_HINT} $${PARAM_NAME}
* #return ${CLASS_NAME}
*/
public ${STATIC} function set${NAME}(#if (${SCALAR_TYPE_HINT})(${SCALAR_TYPE_HINT} #else#end$${PARAM_NAME})
{
#if (${STATIC} == "static")
self::$${FIELD_NAME} = $${PARAM_NAME};
#else
$this->${FIELD_NAME} = $${PARAM_NAME};
#end
return $this;
}
Finally, don't forget to Apply changes.
I want to create user role and permission based on controller method. For this i needed a list of controllers with its method.
i want it to dynamically if i add a method into any class than it will list in this listing
For that i tried this into my method But the problem is that its only showing the current controller and its method.:
<?php
$controller = $this->router->fetch_class();
$method = $this->router->fetch_method();
?>
Please help.
Thanks in advance
Use this library to get all Codeigniter class with yours methods. On application/config/autoload.php, you need load Controllerlist.
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/***
* File: (Codeigniterapp)/libraries/Controllerlist.php
*
* A simple library to list all your controllers with their methods.
* This library will return an array with controllers and methods
*
* The library will scan the "controller" directory and (in case of) one (1) subdirectory level deep
* for controllers
*
* Usage in one of your controllers:
*
* $this->load->library('controllerlist');
* print_r($this->controllerlist->getControllers());
*
* #author Peter Prins
*/
class ControllerList {
/**
* Codeigniter reference
*/
private $CI;
private $EXT;
/**
* Array that will hold the controller names and methods
*/
private $aControllers;
// Construct
function __construct() {
// Get Codeigniter instance
$this->CI = get_instance();
$this->CI->EXT = ".php";
// Get all controllers
$this->setControllers();
}
/**
* Return all controllers and their methods
* #return array
*/
public function getControllers() {
return $this->aControllers;
}
/**
* Set the array holding the controller name and methods
*/
public function setControllerMethods($p_sControllerName, $p_aControllerMethods) {
$this->aControllers[$p_sControllerName] = $p_aControllerMethods;
}
/**
* Search and set controller and methods.
*/
private function setControllers() {
// Loop through the controller directory
foreach(glob(APPPATH . 'controllers/*') as $controller) {
// if the value in the loop is a directory loop through that directory
if(is_dir($controller)) {
// Get name of directory
$dirname = basename($controller, $this->CI->EXT);
// Loop through the subdirectory
foreach(glob(APPPATH . 'controllers/'.$dirname.'/*') as $subdircontroller) {
// Get the name of the subdir
$subdircontrollername = basename($subdircontroller, $this->CI->EXT);
// Load the controller file in memory if it's not load already
if(!class_exists($subdircontrollername)) {
$this->CI->load->file($subdircontroller);
}
// Add the controllername to the array with its methods
$aMethods = get_class_methods($subdircontrollername);
$aUserMethods = array();
foreach($aMethods as $method) {
if($method != '__construct' && $method != 'get_instance' && $method != $subdircontrollername) {
$aUserMethods[] = $method;
}
}
$this->setControllerMethods($subdircontrollername, $aUserMethods);
}
}
else if(pathinfo($controller, PATHINFO_EXTENSION) == "php"){
// value is no directory get controller name
$controllername = basename($controller, $this->CI->EXT);
// Load the class in memory (if it's not loaded already)
if(!class_exists($controllername)) {
$this->CI->load->file($controller);
}
// Add controller and methods to the array
$aMethods = get_class_methods($controllername);
$aUserMethods = array();
if(is_array($aMethods)){
foreach($aMethods as $method) {
if($method != '__construct' && $method != 'get_instance' && $method != $controllername) {
$aUserMethods[] = $method;
}
}
}
$this->setControllerMethods($controllername, $aUserMethods);
}
}
}
}
// EOF
I am using magento version 1.9.0.1.
For switching to magento purposes I need to create a login function for customers outside the magento framework.
I have looked up the method magento uses to hash and validate passwords, but the method doesn't seem to work anymore.
Below the code I use to validate a user login outside magento. This code is just to try proof of concept and is not being used in a live environment for obvious reasons :).
function checkPassword($entity,$passwordInput){
$query = mysql_query("SELECT value FROM customer_entity_varchar WHERE entity_id = '$entity' AND attribute_id = '12' LIMIT 1");
$fetch = mysql_fetch_object($query);
$fetch_data = explode(':',$fetch->value);
$hashed_password = $fetch_data['0'];
$salt = $fetch_data['1'];
$hashInput = md5($passwordInput . $salt);
if($hashInput == $hashed_password){
return 'Success';
}
else{
return 'Failure';
}
}
$entity is the entity_id passed after email validation,
$passwordInput is the password entered in the login form.
It returns Failure. Which I'm not surprised about because when I return $hashInput and compare it with $hashed_password it's not the same.
Has the way Magento hashes passwords been changed? Or is there a mistake in my code?
If you check in \app\code\core\Mage\Customer\Model\Customer.php you can find something like this (near line 430) :
/**
* Encrypt password
*
* #param string $password
* #return string
*/
public function encryptPassword($password)
{
return Mage::helper('core')->encrypt($password);
}
The helper('core') is \app\code\core\Mage\Core\Helper\Data.php
In \app\code\core\Mage\Core\Helper\Data.php, you find :
/**
* Encrypt data using application key
*
* #param string $data
* #return string
*/
public function encrypt($data)
{
if (!Mage::isInstalled()) {
return $data;
}
return $this->getEncryptor()->encrypt($data);
}
and getEncryptor() function is :
/**
* #return Mage_Core_Model_Encryption
*/
public function getEncryptor()
{
if ($this->_encryptor === null) {
$encryptionModel = (string)Mage::getConfig()->getNode(self::XML_PATH_ENCRYPTION_MODEL);
if ($encryptionModel) {
$this->_encryptor = new $encryptionModel;
} else {
$this->_encryptor = Mage::getModel('core/encryption');
}
$this->_encryptor->setHelper($this);
}
return $this->_encryptor;
}
$this->_encryptor is in \app\code\core\Mage\Core\Model\Encryption.php and in this file you can find :
/**
* Encrypt a string
*
* #param string $data
* #return string
*/
public function encrypt($data)
{
return base64_encode($this->_getCrypt()->encrypt((string)$data));
}
and
/**
* Instantiate crypt model
*
* #param string $key
* #return Varien_Crypt_Mcrypt
*/
protected function _getCrypt($key = null)
{
if (!$this->_crypt) {
if (null === $key) {
$key = (string)Mage::getConfig()->getNode('global/crypt/key');
}
$this->_crypt = Varien_Crypt::factory()->init($key);
}
return $this->_crypt;
}
(string)Mage::getConfig()->getNode('global/crypt/key'); is in /app/etc/local.xml file.
Your variable $hashed_password pass by this last method.
Your variable $hashInput also pass there ?
So, you can change in your checkPassword() function :
$hashInput = md5($passwordInput . $salt);
to
$hashInput = encryptPassword($passwordInput);
Thereby, $hashInput and $hashed_password will follow the same way.
I want to ensure that a certain text field does not contain a specific value. Is there any way for me to do this using CI's Form Validation class or do I have to write my own extension for it?
I would extend the form validation class:
http://codeigniter.com/user_guide/general/creating_libraries.html
Something like
<?
class MY_Form_validation extends CI_Form_validation {
function __constuct() {
parent::__constuct();
}
function isnt($str,$field){
$this->CI->form_validation->set_message('isnt', "%s contains an invalid response");
return $str!==$field;
}
}
?>
Your validation rule would be something like
trim|alpha_numeric|isnt[invalid value]
Or, you can create a callback function instead of extending the class. The form validation section of the CI user guide has a relevant example:
http://codeigniter.com/user_guide/libraries/form_validation.html#callbacks
I agree with Billiam that you should extend the Form_validation class
I find it is more likely that one would want to validate a white-list of possible string values rather than a black-list. For example, you know your 'shirt_size' field should only return the string values: 'xl','l','m','s'. My solution is to handle both cases.
I use these methods in MY_From_validation:
/**
* ENUM
* The submitted string must match one of the values given
*
* usage:
* enum[value_1, value_2, value_n]
*
* example (any value beside exactly 'ASC' or 'DESC' are invalid):
* $rule['order_by'] = "required|enum[ASC,DESC]";
*
* example of case-insenstive enum using strtolower as validation rule
* $rule['favorite_corey'] = "required|strtolower|enum[feldman]";
*
* #access public
* #param string $str the input to validate
* #param string $val a comma separated lists of values
* #return bool
*/
function enum($str, $val='')
{
if (empty($val))
{
return FALSE;
}
$arr = explode(',', $val);
$array = array();
foreach($arr as $value)
{
$array[] = trim($value);
}
return (in_array(trim($str), $array)) ? TRUE : FALSE;
}
// --------------------------------------------------------------------
/**
* NOT ENUM
* The submitted string must NOT match one of the values given
*
* usage:
* enum[value_1, value_2, value_n]
*
* example (any input beside exactly 'feldman' or 'haim' are valid):
* $rule['favorite_corey'] = "required|not_enum['feldman','haim']";
*
* #access public
* #param string $str the input to validate
* #param string $val a comma separated lists of values
* #return bool
*/
function not_enum($str, $val='')
{
return ($this->enum($str,$val) === TRUE)? FALSE : TRUE;
}
Using Billiam's example, the validation rule not allow string 'invalid value' would be something like:
trim|alpha_numeric|not_enum[invalid value]
Actually, there's a fairly simple example given for this very question in the User Guide - for V2 or V3
Look for the section "Callbacks: Your own Validation Functions". In the example it uses a check for the word "test" in the username field, and returns the custom error if the value is found.
In your controller, change the "username" rule to this:
$this->form_validation->set_rules('username', 'Username', 'callback_username_check');
Then add a new function called username_check to your controller:
function username_check($str)
{
if ($str == 'test')
{
$this->form_validation->set_message('username_check', 'The %s field can not be the word "test"');
return FALSE;
}
else
{
return TRUE;
}
}
And Bob's your uncle...
CodeIgniter's form validation class can call almost any declared PHP function in your rule set. So I would simply declare a function like so:
class yourController {
function someFunction() {
$this->form_validation->set_rules('the_field_you_want_to_check', 'The Field Name', 'trim|myvalfunc[not this value]|xss');
}
}
function myvalfunc($formvalue, $notallowed) {
$this->CI->form_validation->set_message('myvalfunc', "%s is not allowed");
return $formvalue !== $nowallowed;
}