Page 1 of 1

Second Street Address Line

Posted: Wed Jan 04, 2023 7:55 pm
by tessthepup
Good evening everyone & a Happy New Year

I have copied/changed the includes/modules/customer_data/cd_street_address.php to make a new input for a second address line. Also created the new field in the database.

The module installs and displays fine on all pages but the data for the new address line is not saving to the database.

Is there another file somewhere that I need to add the extra line to???

Thanks

Re: Second Street Address Line

Posted: Wed Jan 04, 2023 9:16 pm
by Kofod95
Maybe a hook like one of the steps here: viewtopic.php?p=3636#p3636

Edit: link updated!

//Daniel

Re: Second Street Address Line

Posted: Wed Jan 04, 2023 9:58 pm
by tessthepup
Kofod95 wrote: Wed Jan 04, 2023 9:16 pm Maybe a hook like one of the steps here: memberlist.php?mode=viewprofile&u=154

//Daniel
Cheers Daniel. I will have a go tomorrow and report back

Re: Second Street Address Line

Posted: Thu Jan 05, 2023 11:53 am
by ecartz
tessthepup wrote: Wed Jan 04, 2023 7:55 pm The module installs and displays fine on all pages but the data for the new address line is not saving to the database.
You made the new field on what table?

What's the code in the module? When does it save? Where does it save?

How do you know that it is not saving to the database? Have you looked at a row in the database that you edited since you added the module? (Best.) Or you looked in the interface and it is not appearing? Or it's not appearing in the address when you look at ...

Note that Daniel's solution fixes the field appearing correctly in the customers or address_book table but not in the orders table. It's not the right solution if the field is not saving anywhere.

Re: Second Street Address Line

Posted: Thu Jan 05, 2023 6:33 pm
by tessthepup
ecartz wrote: Thu Jan 05, 2023 11:53 am
tessthepup wrote: Wed Jan 04, 2023 7:55 pm The module installs and displays fine on all pages but the data for the new address line is not saving to the database.
@ecartz

Hi, thanks for the reply
You made the new field on what table?
I added the new field to the address_book table
What's the code in the module? When does it save? Where does it save?
It does not save anywhere. I did find 2 lines I had not changed to reflect the second address line but now it's totally broken the page.

Code: Select all

<?php
/*
  $Id$

  CE Phoenix, E-Commerce made Easy
  https://phoenixcart.org

  Copyright (c) 2021 Phoenix Cart

  Released under the GNU General Public License
*/

  class cd_second_street_address extends abstract_customer_data_module {

    const CONFIG_KEY_BASE = 'MODULE_CUSTOMER_DATA_SECOND_STREET_ADDRESS_';

    const PROVIDES = [ 'Address Line 2' ];
    const REQUIRES = [  ];

    protected function get_parameters() {
      return [
        static::CONFIG_KEY_BASE . 'STATUS' => [
          'title' => 'Enable Additional Street Address module',
          'value' => 'True',
          'desc' => 'Do you want to add the module to your shop?',
          'set_func' => "Config::select_one(['True', 'False'], ",
        ],
        static::CONFIG_KEY_BASE . 'GROUP' => [
          'title' => 'Customer data group',
          'value' => '2',
          'desc' => 'In what group should this appear?',
          'use_func' => 'customer_data_group::fetch_name',
          'set_func' => 'Config::select_customer_data_group(',
        ],
        static::CONFIG_KEY_BASE . 'REQUIRED' => [
          'title' => 'Require Street Address module (if enabled)',
          'value' => 'True',
          'desc' => 'Do you want the street address to be required in customer registration?',
          'set_func' => "Config::select_one(['True', 'False'], ",
        ],
        static::CONFIG_KEY_BASE . 'MIN_LENGTH' => [
          'title' => 'Minimum Length',
          'value' => '3',
          'desc' => 'Minimum length of street address',
        ],
        static::CONFIG_KEY_BASE . 'PAGES' => [
          'title' => 'Pages',
          'value' => 'address_book;checkout_new_address;create_account;customers',
          'desc' => 'On what pages should this appear?',
          'set_func' => 'Customers::select_pages(',
          'use_func' => 'abstract_module::list_exploded',
        ],
        static::CONFIG_KEY_BASE . 'SORT_ORDER' => [
          'title' => 'Sort Order',
          'value' => '4200',
          'desc' => 'Sort order of display. Lowest is displayed first.',
        ],
        static::CONFIG_KEY_BASE . 'TEMPLATE' => [
          'title' => 'Template',
          'value' => 'includes/modules/customer_data/cd_whole_row_input.php',
          'desc' => 'What template should be used to surround this input?',
        ],
      ];
    }

    public function get($field, &$customer_details) {
      switch ($field) {
        case 'second_street_address':
          if (!isset($customer_details[$field])) {
            $customer_details[$field] = $customer_details['second_street_address']
              ?? $customer_details['entry_second_street_address'] ?? null;
          }
          return $customer_details[$field];
      }
    }

    public function display_input($customer_details = null) {
      $label_text = ENTRY_SECOND_STREET_ADDRESS;
      $input_id = 'inputSecondStreetAddress';

      $input = new Input('second_street_address', [
        'id' => $input_id,
        'autocomplete' => 'address-line2',
        'placeholder' => ENTRY_SECOND_STREET_ADDRESS_TEXT,
      ]);

      if ($customer_details && is_array($customer_details)) {
        $input->set('value', $this->get('second_street_address', $customer_details));
      }

      if ($this->is_required()) {
        $input->require();
        $input .= FORM_REQUIRED_INPUT;
      }

      include Guarantor::ensure_global('Template')->map($this->base_constant('TEMPLATE'));
    }

    public function process(&$customer_details) {
      $customer_details['second_street_address'] = Text::input($_POST['second_street_address']);

      if ((strlen($customer_details['second_street_address']) < $this->base_constant('MIN_LENGTH'))
        && $this->is_required()
        )
      {
        $GLOBALS['messageStack']->add_classed(
          $GLOBALS['message_stack_area'] ?? 'customer_data',
          sprintf(ENTRY_STREET_ADDRESS_ERROR, $this->base_constant('MIN_LENGTH')));

        return false;
      }

      return true;
    }

    public function build_db_values(&$db_tables, $customer_details, $table = 'both') {
      Guarantor::guarantee_subarray($db_tables, 'address_book');
      $db_tables['address_book']['entry_second_street_address'] = $customer_details['second_street_address'];
    }

    public function build_db_aliases(&$db_tables, $table = 'both') {
      Guarantor::guarantee_subarray($db_tables, 'address_book');
      $db_tables['address_book']['entry_second_street_address'] = 'second_street_address';
    }

  }
How do you know that it is not saving to the database? Have you looked at a row in the database that you edited since you added the module? (Best.) Or you looked in the interface and it is not appearing? Or it's not appearing in the address when you look at ...
Check the database and nothing got saved to the field. Also before I broke the code I manually entered a value into the database and it showed in the field on the address_book etc.

Note that Daniel's solution fixes the field appearing correctly in the customers or address_book table but not in the orders table. It's not the right solution if the field is not saving anywhere.
one problem at a time ;)

Thanks

Mark

Re: Second Street Address Line

Posted: Fri Jan 06, 2023 11:14 am
by ecartz
Try changing

Code: Select all

    const PROVIDES = [ 'Address Line 2' ];
to

Code: Select all

    const PROVIDES = [ 'second_street_address' ];
I'm not sure that it handles spaces (although it might), and I am sure that there is at least one place where what is given must match that.

Re: Second Street Address Line

Posted: Fri Jan 06, 2023 4:46 pm
by burt
This works in 1.0.8.17 for the following (you'll need to add entry_street_address_l2 to the address_book table);

1. allow admin to add street address (l2) to the relevant forms as per the usual way
2. saves the inputted data from customer
3. shows the inputted data to customer when editing an address [not sure if I tested if it saves changed data]

The issue now is how to get the "l2" inputted data to show where-ever a customers address shows. You'll need this "l2" to show in places so the customer can see their full address (eg in the checkout area, on the gdpr page) and in the admin area for the shopowner (especailly on orders page [I haven't tested that], and in the customer editing screen [I haven't tested that]).

My suggestion would be to look at address_format and try to get the $streets to pick up the relevant data. I didn't have time to look into it. Maybe Matt has a good/easy way of doing this.

Re: Second Street Address Line

Posted: Fri Jan 06, 2023 8:18 pm
by tessthepup
@ecartz @burt

Thanks Guys

I changed the line as suggested by ecartz and that worked great and the second address line saved to the database.

Gary, your file was very helpful and also the suggestion of changing the $streets. I added $cr$second_streets after $streets in each field in the address_format table.

I also had to add the second address line to includes/modules/customer_data/cd_traditional_address.php

Code: Select all

<?php
/*
  $Id$

  CE Phoenix, E-Commerce made Easy
  https://phoenixcart.org

  Copyright (c) 2021 Phoenix Cart

  Released under the GNU General Public License
*/

  class cd_traditional_address extends abstract_module {

    const CONFIG_KEY_BASE = 'MODULE_CUSTOMER_DATA_TRADITIONAL_ADDRESS_';

    const PROVIDES = [ 'address' ];
    const REQUIRES = [ 'name', 'street_address', 'second_street_address', 'postcode', 'city', 'country' ];
    const FIELDS = [ 'name', 'street_address', 'second_street_address', 'postcode', 'city', 'country_id', 'company', 'suburb', 'state' ];

    private $active_fields;

    protected function get_parameters() {
      return [
        static::CONFIG_KEY_BASE . 'STATUS' => [
          'title' => 'Enable Traditional Address module',
          'value' => 'True',
          'desc' => 'Do you want to add the module to your shop?',
          'set_func' => "Config::select_one(['True', 'False'], ",
        ],
      ];
    }

    public function get($field, &$customer_details) {
      switch ($field) {
        case 'address':
          if (!isset($customer_details[$field])) {
            $customer_details[$field] = array_combine(
              $this->get_fields(),
              array_map(
                function ($v) use (&$customer_details) {
                  return $GLOBALS['customer_data']->get($v, $customer_details);
                },
                $this->get_fields()
              )
            );
          }

          return $customer_details[$field];
      }
    }

    public function process(&$customer_details) {
      $results = $GLOBALS['customer_data']->process($this->get_fields());
      $customer_details = array_merge($customer_details, $results);

      return !empty($results);
    }

    public function get_fields() {
      if (is_null($this->active_fields)) {
        global $customer_data;

        $customer_data->has(self::FIELDS);
        $this->active_fields = array_diff(self::FIELDS, $customer_data->get_last_missing_abilities());
      }

      return $this->active_fields;
    }

    public function get_purveyors() {
      return array_map([$GLOBALS['customer_data'], 'get_module'], $this->get_fields());
    }

    public function build_db_values(&$db_tables, $customer_details, $table = 'both') {
      foreach ($this->get_purveyors() as $purveyor) {
        $purveyor->build_db_values($db_tables, $customer_details, $table);
      }
    }

    public function build_db_aliases(&$db_tables, $table = 'both') {
      foreach ($this->get_purveyors() as $purveyor) {
        $purveyor->build_db_aliases($db_tables, $table);
      }
    }

    function format($address, $html, $boln, $eoln) {
      $address_format_id = $address['format_id'] ?? $address['address_format_id'] ?? $this->get_address_format_id($address['country_id'] ?? $address['country']['id'] ?? null);
      $address_format = $GLOBALS['db']->query("SELECT address_format AS format FROM address_format WHERE address_format_id = " . (int)$address_format_id)->fetch_assoc();

      $company = htmlspecialchars($address['company'] ?? '');
      $name = htmlspecialchars($GLOBALS['customer_data']->get('name', $address) ?? '');

      $street = htmlspecialchars($address['street_address']);
      $second_street = htmlspecialchars($address['second_street_address']);
      $suburb = htmlspecialchars($address['suburb'] ?? '');
      $city = htmlspecialchars($address['city']);
      $state = htmlspecialchars($address['state'] ?? '');
      if (!empty($address['country_id'])) {
        $country = Country::fetch_name($address['country_id']);

        if (!empty($address['zone_id'])) {
          $state = Zone::fetch_code($address['zone_id'], $address['country_id'], $state);
        }
      } elseif (!empty($address['country']) && is_array($address['country'])) {
        $country = htmlspecialchars($address['country']['title']);
      } else {
        $country = '';
      }
      $postcode = htmlspecialchars($address['postcode']);
      $zip = $postcode;

      if ($html) {
        // HTML Mode
        $HR = '<hr />';
        $hr = '<hr />';
        if ( ($boln == '') && ($eoln == "\n") ) { // Values not specified, use rational defaults
          $CR = '<br>';
          $cr = '<br>';
          $eoln = $cr;
        } else { // Use values supplied
          $CR = $eoln . $boln;
          $cr = $CR;
        }
      } else {
        // Text Mode
        $CR = $eoln;
        $cr = $CR;
        $HR = '----------------------------------------';
        $hr = '----------------------------------------';
      }

      $statecomma = '';
      $streets = $street;
      $second_streets = $second_street;
      if ('' != $suburb) {
        $streets .= $cr . $suburb;
      }
      if ('' != $state) {
        $statecomma = $state . ', ';
      }

      $fmt = $address_format['format'];
      eval("\$address = \"$fmt\";");

      if (!empty($company)) {
        $address = $company . $cr . $address;
      }

      return $address;
    }

    function get_address_format_id($country_id) {
      $address_format = $GLOBALS['db']->query("SELECT address_format_id AS format_id FROM countries WHERE countries_id = " . (int)$country_id)->fetch_assoc();

      return $address_format['format_id'] ?? '1';
    }

  }
I have check in most areas on the store front and all seems ok.

I then unfortunately had to modify catalog/includes/system/segments/checkout/insert_order.php

and add

Code: Select all

'customers_second_street_address' => $GLOBALS['customer_data']->get('second_street_address', $order->customer),
'delivery_second_street_address' => $GLOBALS['customer_data']->get('second_street_address', $order->delivery),
'billing_second_street_address' => $GLOBALS['customer_data']->get('second_street_address', $order->billing),
I then added 3 new fields to correspond to the above changes to the orders table

Re: Second Street Address Line

Posted: Sat Jan 07, 2023 5:41 pm
by ecartz
tessthepup wrote: Fri Jan 06, 2023 8:18 pm I then unfortunately had to modify catalog/includes/system/segments/checkout/insert_order.php
This is the point where you should read Daniel's link about using a hook to do that. Or actually, you should have read it before making the core changes. But since we're past that, you should read it now. You can do that entirely via hook and revert the core changes.
tessthepup wrote: Fri Jan 06, 2023 8:18 pm I also had to add the second address line to includes/modules/customer_data/cd_traditional_address.php
The suggested method here is to duplicate cd_traditional_address.php with a new name. Then uninstall the original and install your duplicate version. Then you won't get stomped by later core changes.