1: <?php
2:
3: App::uses('FormHelper', 'View/Helper');
4: App::uses('ExtendedFieldsParser', 'ExtendedScaffold.Lib');
5: App::uses('ArrayUtil', 'Base.Lib');
6: App::uses('Basics', 'Base.Lib');
7: App::uses('DateTimeInput', 'ExtendedScaffold.View/Helper/ExtendedForm');
8: App::uses('ExtendedFieldSet', 'ExtendedScaffold.View/Helper/ExtendedForm');
9: App::uses('InputSearchable', 'ExtendedScaffold.View/Helper/ExtendedForm');
10: App::uses('InputsOnSubmit', 'ExtendedScaffold.View/Helper/ExtendedForm');
11: App::uses('ListFieldSet', 'ExtendedScaffold.View/Helper/ExtendedForm');
12: App::uses('InputMasked', 'ExtendedScaffold.View/Helper/ExtendedForm');
13:
14: class ExtendedFormHelper extends FormHelper {
15:
16: const FIXED_PREFIX = '_fixed';
17: const MASKED_SUFFIX = '_masked';
18:
19: public $helpers = array(
20: 'AccessControl.AccessControl',
21: 'Html',
22: 'ExtendedScaffold.FieldSetLayout',
23: 'ExtendedScaffold.Lists',
24: 'Base.CakeLayers',
25: 'ExtendedScaffold.ScaffoldUtil',
26: );
27: public $inputsOnSubmit;
28: private $formId;
29:
30: public function __construct(View $View, $settings = array()) {
31: parent::__construct($View, $settings);
32: $this->inputsOnSubmit = new InputsOnSubmit($this);
33: }
34:
35: public function beforeLayout($layoutFile) {
36: parent::beforeLayout($layoutFile);
37: $this->ScaffoldUtil->addJavascriptLink('ExtendedScaffold.DomHelper.js');
38: $this->ScaffoldUtil->addJavascriptLink('ExtendedScaffold.Lang.js');
39: $this->ScaffoldUtil->addJavascriptLink('ExtendedScaffold.Collections.js');
40: $this->ScaffoldUtil->addJavascriptLink('ExtendedScaffold.ExtendedFormHelper.js');
41: $this->ScaffoldUtil->addJavascriptLink('ExtendedScaffold.ExtendedFormHelper/InputMasked.js');
42: $this->ScaffoldUtil->addJavascriptLink('ExtendedScaffold.ExtendedFormHelper/InputSearchable.js');
43: $this->ScaffoldUtil->addJavascriptLink('ExtendedScaffold.ExtendedFormHelper/ListFieldSet.js');
44: $this->ScaffoldUtil->addJavascriptLink('ExtendedScaffold.ExtendedFormHelper/DateTimeInput.js');
45: $this->ScaffoldUtil->addJavascriptLink('ExtendedScaffold.jquery-1.8.3.min.js');
46: $this->ScaffoldUtil->addJavascriptLink('ExtendedScaffold.jquery-ui-1.10.4.custom.min.js');
47: $this->ScaffoldUtil->addJavascriptLink('ExtendedScaffold.jquery.textchange.min.js');
48: $this->ScaffoldUtil->addJavascriptLink('ExtendedScaffold.jquery.inputmask/jquery.inputmask.js');
49: $this->ScaffoldUtil->addJavascriptLink('ExtendedScaffold.moment.min.js');
50: $this->ScaffoldUtil->addCssLink('ExtendedScaffold.jquery-ui-1.10.4.custom.min.css');
51: }
52:
53: public function defaultForm($fields = null) {
54: $blacklist = array('created', 'modified', 'updated', 'canceled');
55: if (ExtendedFieldsParser::isExtendedFieldsDefinition($fields)) {
56: return $this->extendedCreate() .
57: $this->extendedInputs(
58: $fields, $blacklist
59: ) . $this->extendedEnd(__d('extended_scaffold','Submit', true));
60: } else {
61: return $this->create(null, array('url' => $this->_currentUrl())) .
62: $this->inputs($fields, $blacklist) .
63: $this->end(__d('extended_scaffold','Submit', true));
64: }
65: }
66:
67: public function extendedCreate($model = null, $options = array()) {
68: if (empty($options['class'])) {
69: $options['class'] = 'extendedForm';
70: }
71:
72: if (empty($options['url']) && empty($options['action'])) {
73: $options['url'] = $this->_currentUrl();
74: }
75:
76: $options['enctype'] = 'multipart/form-data';
77:
78: return $this->create($model, $options);
79: }
80:
81: public function extendedInputs($data, $blacklist = array(), $defaultModel = null) {
82: $b = "\n<div class='scaffoldInputsLine'>\n";
83: foreach (ExtendedFieldsAccessControl::parseFieldsets($data, false, $defaultModel) as $fieldset) {
84:
85: $fieldsetOut = $this->_extendedInputsFieldset(
86: $fieldset, $blacklist
87: );
88:
89: if (!empty($fieldsetOut)) {
90: $b .= $fieldsetOut;
91: }
92: }
93: $b .= "\n</div>\n";
94:
95: return $b;
96: }
97:
98: public function extendedEnd($options = null) {
99: return $this->end($options);
100: }
101:
102: public function getFieldInfo($field) {
103: if (empty($this->fieldset[$this->model()]['fields'][$field])) {
104: return false;
105: } else {
106: return $this->fieldset[$this->model()]['fields'][$field];
107: }
108: }
109:
110: private function _extendedInputsFieldset(\FieldSetDefinition $fieldset, $blacklist) {
111: $currentModel = $this->model();
112: if ($fieldset->getListAssociation()) {
113: $f = new ListFieldSet($this, $fieldset, $blacklist);
114: } else {
115: $f = new ExtendedFieldSet($this, $fieldset, $blacklist);
116: }
117: $output = $f->output();
118: $this->setEntity($currentModel);
119: return $output;
120: }
121:
122: public function input($fieldName, $options = array()) {
123: $fields = array();
124: $this->setEntity($fieldName);
125: $view = ClassRegistry::getObject('view');
126:
127: if (strpos($fieldName, '.') === false) {
128: $fieldName = $this->model() . '.' . $fieldName;
129: }
130:
131: if ($this->isFixed($fieldName)) {
132: ArrayUtil::setByArray($this->request->data[self::FIXED_PREFIX], Basics::fieldNameToArray($fieldName), true);
133: $options['readonly'] = true;
134:
135: if ($this->isListable($fieldName)) {
136: $options['options'] = $this->getReadonlyListOptions($fieldName);
137: }
138: $fields[self::FIXED_PREFIX . '.' . $fieldName] = array('type' => 'hidden');
139: }
140:
141: if (!empty($options['mask']) || !empty($options['search'])) {
142: $options['type'] = 'text';
143: }
144:
145: $fields[$fieldName] = $options;
146:
147: return $this->_inputSubinputs($fields);
148: }
149:
150: private function _inputSubinputs($fields) {
151: $b = '';
152: foreach ($fields as $fieldName => $options) {
153: $b .= parent::input($fieldName, $options) . "\n";
154: }
155: return $b;
156: }
157:
158: public function isListable($fieldName) {
159: return $this->_View->getVar($this->getListVariableDefaultName($fieldName)) !== null;
160: }
161:
162: public function getListVariableDefaultName($fieldName) {
163: $fieldNameParts = explode('.', $fieldName);
164:
165: return Inflector::variable(
166: Inflector::pluralize(
167: preg_replace('/(?:_id)$/', '', $fieldNameParts[count($fieldNameParts) - 1])
168: ));
169: }
170:
171: public function getReadonlyListOptions($fieldName) {
172: $view = ClassRegistry::getObject('view');
173: $fieldValue = ArrayUtil::arrayIndex($view->data, explode('.', $fieldName));
174: return array(
175: $fieldValue => $view->viewVars[$this->getListVariableDefaultName($fieldName)][$fieldValue]
176: );
177: }
178:
179: public function inputHiddenAllData() {
180: $buffer = "";
181: foreach (array_keys(ArrayUtil::array2NamedParams($this->data)) as $field) {
182: $buffer .= $this->input($field, array('type' => 'hidden'));
183: }
184: return $buffer;
185: }
186:
187: public function isFixed($fieldName) {
188: return ArrayUtil::arrayIndex(
189: $this->data, array_merge(
190: array(self::FIXED_PREFIX), explode('.', $fieldName)
191: )
192: ) || $this->isVirtualField($fieldName);
193: }
194:
195: public function isVirtualField($fieldName) {
196: $this->setEntity($fieldName);
197: $parts = explode('.', $fieldName);
198: $lastPart = $parts[count($parts) - 1];
199: if (App::import('Model', $this->model())) {
200: $model = ClassRegistry::init($this->model());
201: return !empty($model->virtualFields[$lastPart]);
202: } else {
203: return false;
204: }
205: }
206:
207: public function dateTime($fieldName, $dateFormat = 'DMY', $timeFormat = '12', $selected = null, $attributes = array()) {
208: return DateTimeInput::dateTime($this, $fieldName, $dateFormat, $timeFormat, $selected, $attributes);
209: }
210:
211: public function fieldDefinition($fieldName, $property = false) {
212: $fieldPath = $this->_fieldDefinitionPath($fieldName);
213: $fieldDef = $this->_introspectModel($fieldPath[0], 'fields', $fieldPath[1]);
214: if ($property) {
215: return $fieldDef[$property];
216: } else {
217: return $fieldDef;
218: }
219: }
220:
221: private function _fieldDefinitionPath($fieldName) {
222: $parts = Basics::fieldPath($fieldName, $this->model());
223: $path = array();
224: foreach ($parts as $part) {
225: if (!preg_match('/^[0-9]$/', $part) && !preg_match('/^\%.+\%$/', $part)) {
226: $path[] = $part;
227: }
228: }
229: return $path;
230: }
231:
232: public function text($fieldName, $options = array()) {
233: if (!empty($options['mask'])) {
234: return InputMasked::maskedText($this, $fieldName, $options);
235: } else if (!empty($options['search'])) {
236: $input = new InputSearchable($this,$fieldName,$options);
237: return $input->output();
238: } else {
239: return parent::text($fieldName, $options);
240: }
241: }
242:
243: public function create($model = null, $options = array()) {
244: $this->formId = empty($options['id']) ?
245: $this->createNewDomId() :
246: $options['id'];
247: $options['id'] = $this->formId;
248: $options['onsubmit'] = 'return ExtendedFormHelper.onSubmit(this)';
249: $buffer = parent::create($model, $options);
250: $buffer .= $this->_refererInput();
251: return $buffer;
252: }
253:
254: private function _refererInput() {
255: return $this->hidden('_ScaffoldUtil.referer');
256: }
257:
258: public function end($options = null) {
259: return parent::end($options) . $this->_onReadyEvent();
260: }
261:
262: private function _onReadyEvent() {
263: $b = <<<EOT
264: $(document).ready(function(){
265: ExtendedFormHelper.initInputs($('#{$this->formId}'));
266: });
267: EOT;
268: return $this->javascriptTag($b);
269: }
270:
271: public function javascriptTag($content) {
272: return "\n<script type='text/javascript'>\n$content\n</script>\n";
273: }
274:
275: public function createNewDomId() {
276: $maxDigits = 8;
277: $n = rand(0, pow(10, 8) - 1);
278: return "id_" . str_pad($n, $maxDigits, '0', STR_PAD_LEFT);
279: }
280:
281: 282: 283: 284:
285: public function getInputsOnSubmit() {
286: return $this->inputsOnSubmit;
287: }
288:
289: private function _currentUrl() {
290: $pattern = '/^' . str_replace('/', '\/', $this->base) . '/';
291: return preg_replace($pattern, '', $this->here);
292: }
293:
294: }
295:
296: ?>
297: