1<?php
2/**
3 * Joomla! Content Management System
4 *
5 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
6 * @license    GNU General Public License version 2 or later; see LICENSE.txt
7 */
8
9namespace Joomla\CMS\Form\Field;
10
11defined('JPATH_PLATFORM') or die;
12
13use Joomla\CMS\Captcha\Captcha;
14use Joomla\CMS\Factory;
15use Joomla\CMS\Form\FormField;
16
17/**
18 * Captcha field.
19 *
20 * @since  2.5
21 */
22class CaptchaField extends FormField
23{
24	/**
25	 * The field type.
26	 *
27	 * @var    string
28	 * @since  2.5
29	 */
30	protected $type = 'Captcha';
31
32	/**
33	 * The captcha base instance of our type.
34	 *
35	 * @var Captcha
36	 */
37	protected $_captcha;
38
39	/**
40	 * Method to get certain otherwise inaccessible properties from the form field object.
41	 *
42	 * @param   string  $name  The property name for which to get the value.
43	 *
44	 * @return  mixed  The property value or null.
45	 *
46	 * @since   3.2
47	 */
48	public function __get($name)
49	{
50		switch ($name)
51		{
52			case 'plugin':
53			case 'namespace':
54				return $this->$name;
55		}
56
57		return parent::__get($name);
58	}
59
60	/**
61	 * Method to set certain otherwise inaccessible properties of the form field object.
62	 *
63	 * @param   string  $name   The property name for which to set the value.
64	 * @param   mixed   $value  The value of the property.
65	 *
66	 * @return  void
67	 *
68	 * @since   3.2
69	 */
70	public function __set($name, $value)
71	{
72		switch ($name)
73		{
74			case 'plugin':
75			case 'namespace':
76				$this->$name = (string) $value;
77				break;
78
79			default:
80				parent::__set($name, $value);
81		}
82	}
83
84	/**
85	 * Method to attach a JForm object to the field.
86	 *
87	 * @param   \SimpleXMLElement  $element  The SimpleXMLElement object representing the `<field>` tag for the form field object.
88	 * @param   mixed              $value    The form field value to validate.
89	 * @param   string             $group    The field name group control value. This acts as an array container for the field.
90	 *                                       For example if the field has name="foo" and the group value is set to "bar" then the
91	 *                                       full field name would end up being "bar[foo]".
92	 *
93	 * @return  boolean  True on success.
94	 *
95	 * @since   2.5
96	 */
97	public function setup(\SimpleXMLElement $element, $value, $group = null)
98	{
99		$result = parent::setup($element, $value, $group);
100
101		$app = Factory::getApplication();
102
103		$default = $app->get('captcha');
104
105		if ($app->isClient('site'))
106		{
107			$default = $app->getParams()->get('captcha', $default);
108		}
109
110		$plugin = $this->element['plugin'] ?
111			(string) $this->element['plugin'] :
112			$default;
113
114		$this->plugin = $plugin;
115
116		if ($plugin === 0 || $plugin === '0' || $plugin === '' || $plugin === null)
117		{
118			$this->hidden = true;
119
120			return false;
121		}
122		else
123		{
124			// Force field to be required. There's no reason to have a captcha if it is not required.
125			// Obs: Don't put required="required" in the xml file, you just need to have validate="captcha"
126			$this->required = true;
127
128			if (strpos($this->class, 'required') === false)
129			{
130				$this->class .= ' required';
131			}
132		}
133
134		$this->namespace = $this->element['namespace'] ? (string) $this->element['namespace'] : $this->form->getName();
135
136		try
137		{
138			// Get an instance of the captcha class that we are using
139			$this->_captcha = Captcha::getInstance($this->plugin, array('namespace' => $this->namespace));
140
141			/**
142			 * Give the captcha instance a possibility to react on the setup-process,
143			 * e.g. by altering the XML structure of the field, for example hiding the label
144			 * when using invisible captchas.
145			 */
146			$this->_captcha->setupField($this, $element);
147		}
148		catch (\RuntimeException $e)
149		{
150			$this->_captcha = null;
151			\JFactory::getApplication()->enqueueMessage($e->getMessage(), 'error');
152
153			return false;
154		}
155
156		return $result;
157	}
158
159	/**
160	 * Method to get the field input.
161	 *
162	 * @return  string  The field input.
163	 *
164	 * @since   2.5
165	 */
166	protected function getInput()
167	{
168		if ($this->hidden || $this->_captcha == null)
169		{
170			return '';
171		}
172
173		try
174		{
175			return $this->_captcha->display($this->name, $this->id, $this->class);
176		}
177		catch (\RuntimeException $e)
178		{
179			\JFactory::getApplication()->enqueueMessage($e->getMessage(), 'error');
180		}
181		return '';
182	}
183}
184