olegkrivtsov / using-zf3-book-samples

Samples for the Using Zend Framework 3 book
142 stars 100 forks source link

Save user choices in session #40

Closed Mecanik closed 6 years ago

Mecanik commented 6 years ago

In the RegistrationController.php:

// Save user choices in session.
$this->sessionContainer->userChoices["step$step"] = $data;

I suggest changing this, because the array keys will have strings instead of integers. ( currently step1, step2, step3 )

Result:

Array ( 
[step1] => Array () 
[step2] => Array () 
[step3] => Array ()
)

This is a headache for newbies to access, for example if they want to store the data.

I recently found myself in the same boat.

I think just having:

$this->sessionContainer->userChoices[$step] = $data;

Should do, because then you would have it as:

Array ( 
[1] => Array () 
[2] => Array () 
[3] => Array ()
)

Other suggestions:

I would really suggest changing these to make life easier for the not so wise.

olegkrivtsov commented 6 years ago

Hi @Mecanik good suggestions. Can you suggest a better phone number pattern? I'm not very familiar with UK phone numbers. Also, an example of a postcode with a non-number would be useful.

Mecanik commented 6 years ago

Yep, will do today because I haven’t fixed my one yet! LoL

Mecanik commented 6 years ago

I`m back!

I put comments inside so you can understand what I am talking about.

Here is my fix suggestions:

UK phone numbers examples: https://en.wikipedia.org/wiki/Telephone_numbers_in_the_United_Kingdom

PhoneValidator.php:

/**
     * Validates a phone number.
     * @param string $value User-entered phone number.
     * @return boolean true if the number is valid; otherwise false.
     */
    public function isValid($value) 
    {
        if(!is_scalar($value)) {
            $this->error(self::NOT_SCALAR);
            return $false; // Phone number must be a scalar.
        }

        // Convert the value to string.
        $value = (string)$value;

        /** Remove spaces, so our pregmatch will work **/
        $phone_value = str_replace(' ', '', $value);

        $format = $this->options['format'];

        /** We stricly specify that the format is PHONE_FORMAT_INTL in RegistrationForm.php so the below code will only validate international numbers
         * Unless we can dinamically determine the format and use the according regex, the if statement below is pretty much useless.
         */

        // Determine the correct length and pattern of the phone number,
        // depending on the format.        
        if($format == self::PHONE_FORMAT_INTL) {
            //$correctLength = 16;
            //$pattern = '/^\d \(\d{3}\) \d{3}-\d{4}$/';

            /** This will allow mobile, landline, and special service numbers (999, 123, etc.) -- assumes that spaces have been stripped **/
            $pattern = '/^(?>(?>\+44|0)(?>(?!7624)(?>[12389]\d|5[56]|7[06])\d{8}|(?>(?>[58]00|1\d{2})\d{6})|(?>8001111|845464\d)|7(?>[45789]\d{8}|624\d{6}))|999|112|100|101|111|116|123|155|118\d{3}|(?>\+44|0)(?>800111|8454647))$/D';

        } else { // self::PHONE_FORMAT_LOCAL

            //$correctLength = 8;
            $pattern = '/^\d{3}-\d{4}$/'; /** Untested **/
        }

        /** In RegistrationForm.php we have max lenght 32 so the below code is incorrect. **/

        // First check phone number length
        /*$isValid = false;

        if(strlen($value)==$correctLength) {            
            // Check if the value matches the pattern
            if(preg_match($pattern, $value))                    
                $isValid = true;
        } else 
        {
            echo "strlen is: " . strlen($value) .PHP_EOL;
        }*/

        $isValid = false;

        if(preg_match($pattern, $phone_value)) 
        {
            $isValid = true;
        }

        // If there were an error, set error message.
        if(!$isValid) 
        {
            if($format==self::PHONE_FORMAT_INTL) 
            {
                $this->error(self::INVALID_FORMAT_INTL);
            }
            else
            {
                $this->error(self::INVALID_FORMAT_LOCAL);
            }
        }

        // Return validation result.
        return $isValid;
    }

For the postcode, this is tricky. I saw there is a PostCode validator available from Zend but never tried it.

Plus, without knowing the country code this is again - tricky.

I just created for now PostCodeValidator.php:

<?php
namespace User\Validator;

use Zend\Validator\AbstractValidator;

/**
 * This validator class is designed for checking a post code for conformance to a country.
 */
class PostCodeValidator extends AbstractValidator 
{
    const POSTCODE_FORMAT_INTL  = 'intl';  // International

    /**
     * Available validator options.
     * @var array
     */
    protected $options = [
        'format'        => self::POSTCODE_FORMAT_INTL
    ];

    // Validation failure message IDs.
    const NOT_SCALAR  = 'notScalar';
    const INVALID_FORMAT_POSTCODE  = 'invalidFormatIntl';

    /**
     * Validation failure messages.
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_SCALAR  => "The post code must be a scalar value",
        self::INVALID_FORMAT_POSTCODE  => "The post code you have entered seems to be invalid.",
    ];

    /**
     * Constructor.
     * @param string One of POSTCODE_FORMAT_-prefixed constants.
     */
    public function __construct($options = null) 
    {
        // Set filter options (if provided).
        if(is_array($options)) {

            if(isset($options['format']))
                $this->setFormat($options['format']);
        }

        // Call the parent class constructor
        parent::__construct($options);
    }

    /**
     * Sets post code format.
     * @param string One of POSTCODE_FORMAT_-prefixed constants.
     */
    public function setFormat($format) 
    {
        // Check input argument.
        if($format!=self::POSTCODE_FORMAT_INTL) {            
            throw new \Exception('Invalid format argument passed.');
        }

        $this->options['format'] = $format;
    }

    /**
     * Validate a postal code.
     *
     * @param $value
     * @param $country
     * @return
     *   TRUE or FALSE if it validates.
     */
    public function isValid($value)
    {
        if(!is_scalar($value)) {
            $this->error(self::NOT_SCALAR);
            return $false;
        }

        $country = 'uk';

        $country_regex = array(
            'uk' => '/\\A\\b[A-Z]{1,2}[0-9][A-Z0-9]? [0-9][ABD-HJLNP-UW-Z]{2}\\b\\z/i',
            'ca' => '/\\A\\b[ABCEGHJKLMNPRSTVXY][0-9][A-Z][ ]?[0-9][A-Z][0-9]\\b\\z/i',
            'it' => '/^[0-9]{5}$/i',
            'de' => '/^[0-9]{5}$/i',
            'be' => '/^[1-9]{1}[0-9]{3}$/i',
            'us' => '/\\A\\b[0-9]{5}(?:-[0-9]{4})?\\b\\z/i',
            'default' => '/\\A\\b[0-9]{5}(?:-[0-9]{4})?\\b\\z/i' // Same as US.
        );

        if ( isset($country_regex[$country]) ) {
            return preg_match($country_regex[$country], $value);
        }

        return preg_match($country_regex['default'], $value);
    }

}

RegistrationForm.php:

// Add input for "post_code" field
            $inputFilter->add([
                    'name'     => 'post_code',
                    'required' => true,
                    'filters'  => [                                        
                    ],
                    'validators' => [
                        [
                            'name'    => 'StringLength',
                            'options' => [
                                'min' => 3,
                                /** 
                                 * The lowest ZIP Code is 00501, a unique ZIP Code for the Internal Revenue Service in Holtsville, NY. The highest ZIP Code is 99950 in Ketchikan, AK. The easiest ZIP Code to remember is 12345, a unique ZIP Code for General Electric in Schenectady, NY. The longest rural delivery route is in Mangum, OK.
                                 */
                                'max' => 99950
                            ],
                        ],
                        [
                            'name' => PostCodeValidator::class,
                            'options' => [
                                'format' => PostCodeValidator::POSTCODE_FORMAT_INTL
                            ]
                        ],
                    ],
                ]);

If you have a better solution for this, it would be great. I tested this with UK postcode (https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom) and it validates accordingly, however it is very poor code.

Mecanik commented 6 years ago

Another contribution from me:

RegistrationForm.php -> Step 2:

// Add "country" field
            $this->add([            
                'type'  => 'select',
                'name' => 'country',
                'attributes' => [
                    'id' => 'country',                                
                ],                                    
                'options' => [                                
                    'label' => 'Country',
                    'empty_option' => '-- Please select --',
                    'value_options' => [
                        'AD'=> 'ANDORRA',
                        'AE'=> 'UNITED ARAB EMIRATES',
                        'AF'=> 'AFGHANISTAN',
                        'AG'=> 'ANTIGUA AND BARBUDA',
                        'AI'=> 'ANGUILLA',
                        'AL'=> 'ALBANIA',
                        'AM'=> 'ARMENIA',
                        'AN'=> 'NETHERLANDS ANTILLES',
                        'AO'=> 'ANGOLA',
                        'AQ'=> 'ANTARCTICA',
                        'AR'=> 'ARGENTINA',
                        'AS'=> 'AMERICAN SAMOA',
                        'AT'=> 'AUSTRIA',
                        'AU'=> 'AUSTRALIA',
                        'AW'=> 'ARUBA',
                        'AZ'=> 'AZERBAIJAN',
                        'BA'=> 'BOSNIA AND HERZEGOVINA',
                        'BB'=> 'BARBADOS',
                        'BD'=> 'BANGLADESH',
                        'BE'=> 'BELGIUM',
                        'BF'=> 'BURKINA FASO',
                        'BG'=> 'BULGARIA',
                        'BH'=> 'BAHRAIN',
                        'BI'=> 'BURUNDI',
                        'BJ'=> 'BENIN',
                        'BL'=> 'SAINT BARTHELEMY',
                        'BM'=> 'BERMUDA',
                        'BN'=> 'BRUNEI DARUSSALAM',
                        'BO'=> 'BOLIVIA',
                        'BR'=> 'BRAZIL',
                        'BS'=> 'BAHAMAS',
                        'BT'=> 'BHUTAN',
                        'BW'=> 'BOTSWANA',
                        'BY'=> 'BELARUS',
                        'BZ'=> 'BELIZE',
                        'CA'=> 'CANADA',
                        'CC'=> 'COCOS (KEELING) ISLANDS',
                        'CD'=> 'CONGO, THE DEMOCRATIC REPUBLIC OF THE',
                        'CF'=> 'CENTRAL AFRICAN REPUBLIC',
                        'CG'=> 'CONGO',
                        'CH'=> 'SWITZERLAND',
                        'CI'=> 'COTE D IVOIRE',
                        'CK'=> 'COOK ISLANDS',
                        'CL'=> 'CHILE',
                        'CM'=> 'CAMEROON',
                        'CN'=> 'CHINA',
                        'CO'=> 'COLOMBIA',
                        'CR'=> 'COSTA RICA',
                        'CU'=> 'CUBA',
                        'CV'=> 'CAPE VERDE',
                        'CX'=> 'CHRISTMAS ISLAND',
                        'CY'=> 'CYPRUS',
                        'CZ'=> 'CZECH REPUBLIC',
                        'DE'=> 'GERMANY',
                        'DJ'=> 'DJIBOUTI',
                        'DK'=> 'DENMARK',
                        'DM'=> 'DOMINICA',
                        'DO'=> 'DOMINICAN REPUBLIC',
                        'DZ'=> 'ALGERIA',
                        'EC'=> 'ECUADOR',
                        'EE'=> 'ESTONIA',
                        'EG'=> 'EGYPT',
                        'ER'=> 'ERITREA',
                        'ES'=> 'SPAIN',
                        'ET'=> 'ETHIOPIA',
                        'FI'=> 'FINLAND',
                        'FJ'=> 'FIJI',
                        'FK'=> 'FALKLAND ISLANDS (MALVINAS)',
                        'FM'=> 'MICRONESIA, FEDERATED STATES OF',
                        'FO'=> 'FAROE ISLANDS',
                        'FR'=> 'FRANCE',
                        'GA'=> 'GABON',
                        'GB'=> 'UNITED KINGDOM',
                        'GD'=> 'GRENADA',
                        'GE'=> 'GEORGIA',
                        'GH'=> 'GHANA',
                        'GI'=> 'GIBRALTAR',
                        'GL'=> 'GREENLAND',
                        'GM'=> 'GAMBIA',
                        'GN'=> 'GUINEA',
                        'GQ'=> 'EQUATORIAL GUINEA',
                        'GR'=> 'GREECE',
                        'GT'=> 'GUATEMALA',
                        'GU'=> 'GUAM',
                        'GW'=> 'GUINEA-BISSAU',
                        'GY'=> 'GUYANA',
                        'HK'=> 'HONG KONG',
                        'HN'=> 'HONDURAS',
                        'HR'=> 'CROATIA',
                        'HT'=> 'HAITI',
                        'HU'=> 'HUNGARY',
                        'ID'=> 'INDONESIA',
                        'IE'=> 'IRELAND',
                        'IL'=> 'ISRAEL',
                        'IM'=> 'ISLE OF MAN',
                        'IN'=> 'INDIA',
                        'IQ'=> 'IRAQ',
                        'IR'=> 'IRAN, ISLAMIC REPUBLIC OF',
                        'IS'=> 'ICELAND',
                        'IT'=> 'ITALY',
                        'JM'=> 'JAMAICA',
                        'JO'=> 'JORDAN',
                        'JP'=> 'JAPAN',
                        'KE'=> 'KENYA',
                        'KG'=> 'KYRGYZSTAN',
                        'KH'=> 'CAMBODIA',
                        'KI'=> 'KIRIBATI',
                        'KM'=> 'COMOROS',
                        'KN'=> 'SAINT KITTS AND NEVIS',
                        'KP'=> 'KOREA DEMOCRATIC PEOPLES REPUBLIC OF',
                        'KR'=> 'KOREA REPUBLIC OF',
                        'KW'=> 'KUWAIT',
                        'KY'=> 'CAYMAN ISLANDS',
                        'KZ'=> 'KAZAKSTAN',
                        'LA'=> 'LAO PEOPLES DEMOCRATIC REPUBLIC',
                        'LB'=> 'LEBANON',
                        'LC'=> 'SAINT LUCIA',
                        'LI'=> 'LIECHTENSTEIN',
                        'LK'=> 'SRI LANKA',
                        'LR'=> 'LIBERIA',
                        'LS'=> 'LESOTHO',
                        'LT'=> 'LITHUANIA',
                        'LU'=> 'LUXEMBOURG',
                        'LV'=> 'LATVIA',
                        'LY'=> 'LIBYAN ARAB JAMAHIRIYA',
                        'MA'=> 'MOROCCO',
                        'MC'=> 'MONACO',
                        'MD'=> 'MOLDOVA, REPUBLIC OF',
                        'ME'=> 'MONTENEGRO',
                        'MF'=> 'SAINT MARTIN',
                        'MG'=> 'MADAGASCAR',
                        'MH'=> 'MARSHALL ISLANDS',
                        'MK'=> 'MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF',
                        'ML'=> 'MALI',
                        'MM'=> 'MYANMAR',
                        'MN'=> 'MONGOLIA',
                        'MO'=> 'MACAU',
                        'MP'=> 'NORTHERN MARIANA ISLANDS',
                        'MR'=> 'MAURITANIA',
                        'MS'=> 'MONTSERRAT',
                        'MT'=> 'MALTA',
                        'MU'=> 'MAURITIUS',
                        'MV'=> 'MALDIVES',
                        'MW'=> 'MALAWI',
                        'MX'=> 'MEXICO',
                        'MY'=> 'MALAYSIA',
                        'MZ'=> 'MOZAMBIQUE',
                        'NA'=> 'NAMIBIA',
                        'NC'=> 'NEW CALEDONIA',
                        'NE'=> 'NIGER',
                        'NG'=> 'NIGERIA',
                        'NI'=> 'NICARAGUA',
                        'NL'=> 'NETHERLANDS',
                        'NO'=> 'NORWAY',
                        'NP'=> 'NEPAL',
                        'NR'=> 'NAURU',
                        'NU'=> 'NIUE',
                        'NZ'=> 'NEW ZEALAND',
                        'OM'=> 'OMAN',
                        'PA'=> 'PANAMA',
                        'PE'=> 'PERU',
                        'PF'=> 'FRENCH POLYNESIA',
                        'PG'=> 'PAPUA NEW GUINEA',
                        'PH'=> 'PHILIPPINES',
                        'PK'=> 'PAKISTAN',
                        'PL'=> 'POLAND',
                        'PM'=> 'SAINT PIERRE AND MIQUELON',
                        'PN'=> 'PITCAIRN',
                        'PR'=> 'PUERTO RICO',
                        'PT'=> 'PORTUGAL',
                        'PW'=> 'PALAU',
                        'PY'=> 'PARAGUAY',
                        'QA'=> 'QATAR',
                        'RO'=> 'ROMANIA',
                        'RS'=> 'SERBIA',
                        'RU'=> 'RUSSIAN FEDERATION',
                        'RW'=> 'RWANDA',
                        'SA'=> 'SAUDI ARABIA',
                        'SB'=> 'SOLOMON ISLANDS',
                        'SC'=> 'SEYCHELLES',
                        'SD'=> 'SUDAN',
                        'SE'=> 'SWEDEN',
                        'SG'=> 'SINGAPORE',
                        'SH'=> 'SAINT HELENA',
                        'SI'=> 'SLOVENIA',
                        'SK'=> 'SLOVAKIA',
                        'SL'=> 'SIERRA LEONE',
                        'SM'=> 'SAN MARINO',
                        'SN'=> 'SENEGAL',
                        'SO'=> 'SOMALIA',
                        'SR'=> 'SURINAME',
                        'ST'=> 'SAO TOME AND PRINCIPE',
                        'SV'=> 'EL SALVADOR',
                        'SY'=> 'SYRIAN ARAB REPUBLIC',
                        'SZ'=> 'SWAZILAND',
                        'TC'=> 'TURKS AND CAICOS ISLANDS',
                        'TD'=> 'CHAD',
                        'TG'=> 'TOGO',
                        'TH'=> 'THAILAND',
                        'TJ'=> 'TAJIKISTAN',
                        'TK'=> 'TOKELAU',
                        'TL'=> 'TIMOR-LESTE',
                        'TM'=> 'TURKMENISTAN',
                        'TN'=> 'TUNISIA',
                        'TO'=> 'TONGA',
                        'TR'=> 'TURKEY',
                        'TT'=> 'TRINIDAD AND TOBAGO',
                        'TV'=> 'TUVALU',
                        'TW'=> 'TAIWAN, PROVINCE OF CHINA',
                        'TZ'=> 'TANZANIA, UNITED REPUBLIC OF',
                        'UA'=> 'UKRAINE',
                        'UG'=> 'UGANDA',
                        'US'=> 'UNITED STATES',
                        'UY'=> 'URUGUAY',
                        'UZ'=> 'UZBEKISTAN',
                        'VA'=> 'HOLY SEE (VATICAN CITY STATE)',
                        'VC'=> 'SAINT VINCENT AND THE GRENADINES',
                        'VE'=> 'VENEZUELA',
                        'VG'=> 'VIRGIN ISLANDS, BRITISH',
                        'VI'=> 'VIRGIN ISLANDS, U.S.',
                        'VN'=> 'VIET NAM',
                        'VU'=> 'VANUATU',
                        'WF'=> 'WALLIS AND FUTUNA',
                        'WS'=> 'SAMOA',
                        'XK'=> 'KOSOVO',
                        'YE'=> 'YEMEN',
                        'YT'=> 'MAYOTTE',
                        'ZA'=> 'SOUTH AFRICA',
                        'ZM'=> 'ZAMBIA',
                        'ZW'=> 'ZIMBABWE'
                    ],                
                ],
            ]);
olegkrivtsov commented 6 years ago

Thanks @Mecanik for now I see this code is much more complex than mine. It may work better than mine but it also may be more difficult to understand, unfortunatelly. I'll better add something like below to the current text of the book:

The PhoneValidator is only for demonstration of how to write custom validators in ZF3. Implementing a validator that will work correctly against all possible phone numbers in the world is beyond the scope of this book. If you'd like to use this validator in real life app, you will definitely need to improve it. For example, take a look at libphonenumber PHP library from Google.

olegkrivtsov commented 6 years ago

Hi @Mecanik I've added that note here: https://olegkrivtsov.github.io/using-zend-framework-3-book/html/en/Checking_Input_Data_with_Validators/Writing_Own_Validator.html

Plan to close this.