diff --git a/inc/cleantalk-common.php b/inc/cleantalk-common.php index bbcdb10f7..6bf93c95d 100644 --- a/inc/cleantalk-common.php +++ b/inc/cleantalk-common.php @@ -7,6 +7,7 @@ use Cleantalk\ApbctWP\CleantalkSettingsTemplates; use Cleantalk\ApbctWP\Cron; use Cleantalk\ApbctWP\DB; +use Cleantalk\ApbctWP\DTO\GetFieldsAnyDTO; use Cleantalk\ApbctWP\Firewall\SFW; use Cleantalk\ApbctWP\GetFieldsAny; use Cleantalk\ApbctWP\Helper; @@ -1118,12 +1119,13 @@ function ct_get_fields_any($arr, $email = '', $nickname = '') } /** - * Get data from an ARRAY recursively - * - * @param array $input_array - * @param string $email - * @param string $nickname + * Get data as assoc array from an ARRAY recursively * + * @see getFieldsAnyDTO to understand the structure of the result + * @param array $input_array maybe raw POST array or other preprocessed POST data. + * @param string $email email, rewriting result of process $input_array data + * @param string $nickname nickname, rewriting result of process $input_array data + * @deprecated since 6.48, use ct_gfa_dto() instead * @return array */ function ct_gfa($input_array, $email = '', $nickname = '') @@ -1133,30 +1135,21 @@ function ct_gfa($input_array, $email = '', $nickname = '') return $gfa->getFields($email, $nickname); } -//New ct_get_fields_any_postdata -function ct_get_fields_any_postdata($arr, $message = array()) +/** + * Get data as GetFieldsAnyDTO object from an ARRAY recursively + * + * @see getFieldsAnyDTO to understand the structure of the result + * @param array $input_array maybe raw POST array or other preprocessed POST data. + * @param string $email email, rewriting result of process $input_array data + * @param string $nickname nickname, rewriting result of process $input_array data + * + * @return GetFieldsAnyDTO + */ +function ct_gfa_dto($input_array, $email = '', $nickname = '') { - $skip_params = array( - 'ipn_track_id', // PayPal IPN # - 'txn_type', // PayPal transaction type - 'payment_status', // PayPal payment status - ); - - foreach ( $arr as $key => $value ) { - if ( ! is_array($value) ) { - if ( $value == '' ) { - continue; - } - if ( ! (in_array($key, $skip_params) || preg_match("/^ct_checkjs/", $key)) && $value != '' ) { - $message[$key] = $value; - } - } else { - $temp = ct_get_fields_any_postdata($value); - $message = (count($temp) == 0 ? $message : array_merge($message, $temp)); - } - } + $gfa = new GetFieldsAny($input_array); - return $message; + return $gfa->getFieldsDTO($email, $nickname); } /** diff --git a/inc/cleantalk-public-integrations.php b/inc/cleantalk-public-integrations.php index eb641724b..0f852ad78 100644 --- a/inc/cleantalk-public-integrations.php +++ b/inc/cleantalk-public-integrations.php @@ -1,5 +1,6 @@ email; + $sender_emails_array = $gfa_dto->emails_array; + $sender_nickname = $gfa_dto->nickname; + $subject = $gfa_dto->subject; + $message = $gfa_dto->message; if ( $subject != '' ) { $message = array_merge(array('subject' => $subject), $message); } @@ -2096,7 +2097,7 @@ function apbct_form__ninjaForms__testSpam() /** * Old way to collecting NF fields data. * - * @return array + * @return GetFieldsAnyDTO */ function apbct_form__ninjaForms__collect_fields_old() { @@ -2106,7 +2107,7 @@ function apbct_form__ninjaForms__collect_fields_old() $input_array = apply_filters('apbct__filter_post', $_POST); // Choosing between POST and GET - return ct_gfa( + return ct_gfa_dto( Get::get('ninja_forms_ajax_submit') || Get::get('nf_ajax_submit') ? $_GET : $input_array ); } @@ -2114,7 +2115,7 @@ function apbct_form__ninjaForms__collect_fields_old() /** * New way to collecting NF fields data - try to get username and email. * - * @return array + * @return GetFieldsAnyDTO * @throws Exception * @psalm-suppress UndefinedClass */ @@ -2170,7 +2171,7 @@ function apbct_form__ninjaForms__collect_fields_new() } } - return ct_gfa($fields, $email, $nickname); + return ct_gfa_dto($fields, $email, $nickname); } /** diff --git a/lib/Cleantalk/ApbctWP/DTO/GetFieldsAnyDTO.php b/lib/Cleantalk/ApbctWP/DTO/GetFieldsAnyDTO.php new file mode 100644 index 000000000..a3c8e2ec5 --- /dev/null +++ b/lib/Cleantalk/ApbctWP/DTO/GetFieldsAnyDTO.php @@ -0,0 +1,90 @@ + + *
  • email(string)
  • + *
  • emails_array(string[])
  • + *
  • nickname(string)
  • + *
  • subject(string)
  • + *
  • contact(bool)
  • + *
  • message(string[])
  • + * + * + * To get assoc array of all properties use getArray() method. + * @since 6.48 + * @version 1.0.0 + * @package Cleantalk\ApbctWP\DTO + * @psalm-suppress InvalidClass + */ +class GetFieldsAnyDTO extends DTO +{ + /** + * Sender email. + * @var string + */ + public $email = ''; + /** + * Array of emails. + * @var array + */ + public $emails_array = array(); + /** + * Nickname. + * Will be concatenated from nickname_first, nickname_last and nickname_nick if not provided during processing. + * @var string + */ + public $nickname = ''; + /** + * Nickname first part. + * @var string + */ + public $nickname_first = ''; + /** + * Nickname last part. + * @var string + */ + public $nickname_last = ''; + /** + * Nickname nick part. + * @var string + */ + public $nickname_nick = ''; + /** + * Subject. + * @var string + */ + public $subject = ''; + /** + * Is contact form? + * @var bool + * @psalm-suppress PossiblyUnusedProperty + */ + public $contact = true; + /** + * Message array. + * @var array + */ + public $message = array(); + + protected $obligatory_properties = array( + 'email', + 'emails_array', + 'nickname', + 'subject', + 'contact', + 'message', + ); + + public function __construct($params) + { + parent::__construct($params); + } +} diff --git a/lib/Cleantalk/ApbctWP/GetFieldsAny.php b/lib/Cleantalk/ApbctWP/GetFieldsAny.php index d197e8fed..fa2ad7ae8 100644 --- a/lib/Cleantalk/ApbctWP/GetFieldsAny.php +++ b/lib/Cleantalk/ApbctWP/GetFieldsAny.php @@ -2,6 +2,7 @@ namespace Cleantalk\ApbctWP; +use Cleantalk\ApbctWP\DTO\GetFieldsAnyDTO; use Cleantalk\ApbctWP\Variables\Cookie; use Cleantalk\ApbctWP\Variables\Post; use Cleantalk\Common\TT; @@ -115,18 +116,6 @@ class GetFieldsAny */ private $visible_fields_arr; - /** - * Processed data array to output - * @var array - */ - private $processed_data = array( - 'email' => '', - 'nickname' => array(), - 'subject' => '', - 'contact' => true, - 'message' => array() - ); - /** * @var string */ @@ -142,6 +131,11 @@ class GetFieldsAny */ private $prev_name = ''; + /** + * @var GetFieldsAnyDTO + */ + private $dto; + /** * GetFieldsAny constructor. * @@ -149,56 +143,90 @@ class GetFieldsAny */ public function __construct(array $input_array) { + $this->setDTODefaults(); $this->input_array = $input_array; $this->isProcessForm(); $this->visible_fields_arr = $this->getVisibleFields(); } + private function setDTODefaults() + { + $dto_default_data = array( + 'email' => '', + 'emails_array' => array(), + 'nickname' => '', + 'nickname_first' => '', + 'nickname_last' => '', + 'nickname_nick' => '', + 'subject' => '', + 'contact' => true, + 'message' => array(), + ); + $this->dto = new GetFieldsAnyDTO($dto_default_data); + } + + /** + * @return GetFieldsAnyDTO + */ + public function getFieldsDTO($email = '', $nickname = '') + { + $this->prepareFields($email, $nickname); + return $this->dto; + } + /** * Public interface to process fields * * @param string $email * @param string $nickname - * * @return array */ public function getFields($email = '', $nickname = '') + { + $this->prepareFields($email, $nickname); + return $this->dto->getArray(); + } + + public function prepareFields($email, $nickname) { $this->preprocessed_email = $email; $this->preprocessed_nickname = is_string($nickname) ? $nickname : ''; + // main gathering logic, recursive if (count($this->input_array)) { - $this->process($this->input_array); + $this->processRecursive($this->input_array); } foreach ($this->skip_message_post as $v) { if (isset($_POST[$v])) { - $this->processed_data['message'] = null; + $this->dto->message = array(); break; } } if ( ! $this->contact) { - $this->processed_data['contact'] = $this->contact; + $this->dto->contact = $this->contact; } if ($this->preprocessed_email) { - $this->processed_data['email'] = $this->preprocessed_email; + $this->dto->email = $this->preprocessed_email; } if ($this->preprocessed_nickname) { - $this->processed_data['nickname'] = $this->preprocessed_nickname; + $this->dto->nickname = $this->preprocessed_nickname; } - if (isset($this->processed_data['nickname']) && is_array($this->processed_data['nickname'])) { - $nickname_str = ''; - foreach ($this->processed_data['nickname'] as $value) { - $nickname_str .= ($value ? $value . " " : ""); + if (empty($this->dto->nickname)) { + $name_chunks = array( + 'first' => $this->dto->nickname_first, + 'last' => $this->dto->nickname_last, + 'nick' => $this->dto->nickname_nick + ); + foreach ($name_chunks as $value) { + $this->dto->nickname .= ($value ? $value . " " : ""); } - $this->processed_data['nickname'] = trim($nickname_str); + $this->dto->nickname = trim($this->dto->nickname); } - - return $this->processed_data; } /** @@ -206,7 +234,7 @@ public function getFields($email = '', $nickname = '') * * @param $arr */ - private function process($arr) + private function processRecursive($arr) { foreach ($arr as $key => $value) { /* @@ -308,15 +336,14 @@ private function process($arr) if ($this->preprocessed_email) { continue; } - if (empty($this->processed_data['email'])) { + if (empty($this->dto->email)) { // if found new very first email field, set it as the processed email field. - $this->processed_data['email'] = $value_for_email; - $this->processed_data['emails_array'][$this->prev_name . $key] = $value_for_email; + $this->dto->email = $value_for_email; } else { // if processed one is already exists, set it to the message field. - $this->processed_data['message'][$this->prev_name . $key] = $value_for_email; - $this->processed_data['emails_array'][$this->prev_name . $key] = $value_for_email; + $this->dto->message[$this->prev_name . $key] = $value_for_email; } + $this->dto->emails_array[$this->prev_name . $key] = $value_for_email; // Names } elseif (false !== stripos($key, "name")) { // Bypass name collecting if it is set by attribute or it is on invisible fields. @@ -336,24 +363,20 @@ private function process($arr) preg_match("/(name.?(nick|user)|(nick|user).?name)/", $key, $match_nickname); if (count($match_forename) > 1) { - $this->processed_data['nickname']['first'] = $value; + $this->dto->nickname_first = $value; } elseif (count($match_surname) > 1) { - $this->processed_data['nickname']['last'] = $value; + $this->dto->nickname_last = $value; } elseif (count($match_nickname) > 1) { - $this->processed_data['nickname']['nick'] = $value; + $this->dto->nickname_nick = $value; } else { - $this->processed_data['message'][$this->prev_name . $key] = $value; + $this->dto->message[$this->prev_name . $key] = $value; } // Subject - } elseif ( - isset($this->processed_data['subject']) && - $this->processed_data['subject'] === '' && - false !== stripos($key, "subject") - ) { - $this->processed_data['subject'] = $value; + } elseif ($this->dto->subject === '' && false !== stripos($key, "subject")) { + $this->dto->subject = $value; // Message } else { - $this->processed_data['message'][$this->prev_name . $key] = $value; + $this->dto->message[$this->prev_name . $key] = $value; } } elseif ( ! is_object($value)) { /* @@ -366,7 +389,7 @@ private function process($arr) $prev_name_original = $this->prev_name; $this->prev_name = ($this->prev_name === '' ? $key . '_' : $this->prev_name . $key . '_'); - $this->process($value); + $this->processRecursive($value); $this->prev_name = $prev_name_original; } @@ -438,7 +461,7 @@ public static function getVisibleFieldsData() // get from Cookies:: $from_cookies = Cookie::getVisibleFields(); // get from Post:: and base64 decode the value - $from_post = @base64_decode(TT::toString(Post::get('apbct_visible_fields'))); + $from_post = @base64_decode(Post::getString('apbct_visible_fields')); $current_fields_collection = self::getFieldsDataForCurrentRequest($from_cookies, $from_post); diff --git a/lib/Cleantalk/Templates/DTO.php b/lib/Cleantalk/Templates/DTO.php new file mode 100644 index 000000000..e275cf561 --- /dev/null +++ b/lib/Cleantalk/Templates/DTO.php @@ -0,0 +1,62 @@ +isObligatoryParamsPresented($params) ) { + throw new \Exception('No go!'); + } + + foreach ( $params as $param_name => $param ) { + if ( property_exists(static::class, $param_name) ) { + $type = gettype($this->$param_name); + $this->$param_name = $param; + settype($this->$param_name, $type); + } + } + } + + /** + * @param $params + * + * @return bool + * @since 1.1.0 + * + */ + private function isObligatoryParamsPresented($params) + { + return empty($this->obligatory_properties) || + count(array_intersect($this->obligatory_properties, array_keys($params))) === count( + $this->obligatory_properties + ); + } + + /** + * Get array of all DTO properties as key-value, except obligatory_properties. + * @return array + */ + public function getArray() + { + $array = array(); + foreach (get_object_vars($this) as $key => $value) { + $array[$key] = $value; + } + unset($array['obligatory_properties']); + return $array; + } +} diff --git a/tests/ApbctWP/TestGetFieldsAny.php b/tests/ApbctWP/TestGetFieldsAny.php index 38099f74d..9d2705cc9 100644 --- a/tests/ApbctWP/TestGetFieldsAny.php +++ b/tests/ApbctWP/TestGetFieldsAny.php @@ -10,16 +10,18 @@ require_once 'inc/cleantalk-common.php'; } +use Cleantalk\ApbctWP\DTO\GetFieldsAnyDTO; use Cleantalk\ApbctWP\GetFieldsAny; +use Cleantalk\ApbctWP\State; use PHPUnit\Framework\TestCase; /** * State class placeholder */ global $apbct; -$apbct = new class { - public $settings = array('data__set_cookies' => 1); -}; +$apbct = new State('cleantalk', array('settings', 'data', 'errors', 'remote_calls', 'stats', 'fw_stats')); +$apbct->settings['data__set_cookies'] = 1; +$apbct->saveSettings(); class TestGetFieldsAny extends TestCase { @@ -47,21 +49,28 @@ public function setUp() 'your-email' => 'good@cleantalk.org', 'your-subject' => 'Subject', 'your-message' => 'Your Message', - 'ct_checkjs_cf7' => '150095430', + //'ct_checkjs_cf7' => '150095430', ); $this->gfa = new GetFieldsAny( $this->post ); - } + public function testEmptyDTO() + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No go!'); + new GetFieldsAnyDTO(array()); + } + public function testgetFields() { $result = $this->gfa->getFields(); $this->assertIsArray( $result ); - $this->arrayHasKey( 'email', $result ); - $this->arrayHasKey( 'nickname', $result ); - $this->arrayHasKey( 'subject', $result ); - $this->arrayHasKey( 'contact', $result ); - $this->arrayHasKey( 'message', $result ); + $this->assertArrayHasKey( 'email', $result ); + $this->assertArrayHasKey( 'nickname', $result ); + $this->assertArrayHasKey( 'subject', $result ); + $this->assertArrayHasKey( 'contact', $result ); + $this->assertArrayHasKey( 'message', $result ); + $this->assertArrayHasKey( 'emails_array', $result ); $this->assertEquals($result['nickname'], $this->post['your-name']); $this->assertEquals($result['email'], $this->post['your-email']); } @@ -70,13 +79,52 @@ public function testgetFieldsAnyWithArguments() { $result = $this->gfa->getFields( 'another_email@example.com', 'SuperbNickname' ); $this->assertIsArray( $result ); - $this->arrayHasKey( 'email', $result ); - $this->arrayHasKey( 'nickname', $result ); - $this->arrayHasKey( 'subject', $result ); - $this->arrayHasKey( 'contact', $result ); - $this->arrayHasKey( 'message', $result ); + $this->assertArrayHasKey( 'email', $result ); + $this->assertArrayHasKey( 'nickname', $result ); + $this->assertArrayHasKey( 'subject', $result ); + $this->assertArrayHasKey( 'contact', $result ); + $this->assertArrayHasKey( 'message', $result ); + $this->assertArrayHasKey( 'emails_array', $result ); $this->assertEquals($result['nickname'],'SuperbNickname'); $this->assertEquals($result['email'], 'another_email@example.com'); } + public function testCTGFAStandaloneAsArrayResponse() + { + $result = ct_gfa($this->post); + $this->assertIsArray( $result ); + $this->assertArrayHasKey( 'email', $result ); + $this->assertArrayHasKey( 'nickname', $result ); + $this->assertArrayHasKey( 'subject', $result ); + $this->assertArrayHasKey( 'contact', $result ); + $this->assertArrayHasKey( 'message', $result ); + $this->assertArrayHasKey( 'emails_array', $result ); + $this->assertEquals($this->post['your-name'], $result['nickname']); + $this->assertEquals($this->post['your-email'], $result['email']); + $this->assertEquals($this->post['your-message'], $result['message']['your-message']); + $this->assertEquals($this->post['your-subject'], $result['subject']); + $this->assertTrue($result['contact']); + } + + public function testCTGFAStandaloneAsDTOResponse() + { + $result = ct_gfa_dto($this->post,'', ''); + $this->assertIsObject( $result ); + $this->assertInstanceOf(GetFieldsAnyDTO::class, $result); + $this->assertEquals($this->post['your-name'], $result->nickname); + $this->assertEquals($this->post['your-email'], $result->email); + $this->assertEquals($this->post['your-subject'], $result->subject); + $this->assertEquals($this->post['your-message'], $result->message['your-message']); + } + + public function testIsNotContactForm() + { + $this->post['ct_checkjs_cf7'] = '150095430'; + $result = ct_gfa_dto($this->post,'', ''); + $this->assertIsObject( $result ); + $this->assertInstanceOf(GetFieldsAnyDTO::class, $result); + $this->assertFalse($result->contact); + } + + }