1 : <?php
2 :
3 : /**
4 : * Dictionaries of Old French and Latin
5 : *
6 : * PHP 5
7 : *
8 : * @category Application
9 : * @package DicFro
10 : * @author Michel Corne <mcorne@yahoo.com>
11 : * @copyright 2008-2010 Michel Corne
12 : * @license http://opensource.org/licenses/gpl-3.0.html GNU General Public License, version 3 (GPLv3)
13 : * @link http://www.micmap.org/dicfro
14 : */
15 :
16 : require_once 'Common/String.php';
17 : require_once 'Engine/Front.php';
18 : require_once 'Engine/View.php';
19 : // note: dictionary classes are included dynamically, see $dictionaries and createSearchObject()
20 :
21 : /**
22 : * Interface controller
23 : *
24 : * @category Application
25 : * @package DicFro
26 : * @author Michel Corne <mcorne@yahoo.com>
27 : * @copyright 2008-2010 Michel Corne
28 : * @license http://opensource.org/licenses/gpl-3.0.html GNU General Public License, version 3 (GPLv3)
29 : */
30 :
31 : class Controller_Interface
32 : {
33 : /**
34 : * List of actions
35 : * @var array
36 : */
37 : public $actions = array(
38 : 'about' => 'a-propos',
39 : 'help' => 'aide',
40 : 'home' => 'accueil',
41 : 'introduction' => 'introduction',
42 : 'next' => 'page-suivante',
43 : 'page' => 'aller-page',
44 : 'previous' => 'page-precedente',
45 : 'search' => 'chercher',
46 : );
47 :
48 : /**
49 : * Dictionaries information
50 : * @var array
51 : */
52 : public $dictionaries = array(
53 : // internal dictionaries
54 : 'complement-godefroy' => array(
55 : 'class' => 'Model_Search_Gdfc',
56 : 'introduction' => 'gdfc.phtml',
57 : 'internal' => true,
58 : ),
59 : 'dictionnaire-godefroy' => array(
60 : 'class' => 'Model_Search_Gdf',
61 : 'introduction' => 'gdf.phtml',
62 : 'internal' => true,
63 : ),
64 : 'gaffiot' => array(
65 : 'class' => 'Model_Search_Gaffiot',
66 : 'introduction' => 'gaffiot.phtml',
67 : 'internal' => true,
68 : ),
69 : 'glossaire-chanson-de-roland' => array(
70 : 'class' => 'Model_Search_Roland',
71 : 'introduction' => 'roland.phtml',
72 : 'internal' => true,
73 : ),
74 : 'glossaire-chretien-de-troyes' => array(
75 : 'class' => 'Model_Search_Chretien',
76 : 'introduction' => 'chretien.phtml',
77 : 'internal' => true,
78 : ),
79 : 'glossaire-couronnement-de-louis' => array(
80 : 'class' => 'Model_Search_Couronnement',
81 : 'introduction' => 'couronnement.phtml',
82 : 'internal' => true,
83 : ),
84 : 'glossaire-roman-de-la-rose' => array(
85 : 'class' => 'Model_Search_Rose',
86 : 'introduction' => 'rose.phtml',
87 : 'internal' => true,
88 : ),
89 : 'glossaire-roman-de-tristan' => array(
90 : 'class' => 'Model_Search_Tristan',
91 : 'introduction' => 'tristan.phtml',
92 : 'internal' => true,
93 : ),
94 : 'lexique-godefroy' => array(
95 : 'class' => 'Model_Search_Gdflex',
96 : 'introduction' => 'gdflex.phtml',
97 : 'internal' => true,
98 : ),
99 : 'lexique-roman' => array(
100 : 'class' => 'Model_Search_Lexromv',
101 : 'introduction' => 'roman.phtml',
102 : 'internal' => true,
103 : ),
104 : 'tableaux-de-conjugaison' => array(
105 : 'class' => 'Model_Search_Tcaf',
106 : 'introduction' => 'tcaf.phtml',
107 : 'internal' => true,
108 : ),
109 : 'vandaele' => array(
110 : 'class' => 'Model_Search_Vandaele',
111 : 'introduction' => 'vandaele.phtml',
112 : 'internal' => true,
113 : ),
114 : // external dictionaries
115 : 'cnrtl' => array(
116 : 'introduction' => 'http://www.cnrtl.fr/definition/',
117 : 'search' => 'http://www.cnrtl.fr/definition/',
118 : 'internal' => false,
119 : ),
120 : 'dmf' => array(
121 : 'introduction' => 'http://www.atilf.fr/dmf/',
122 : 'search' => 'http://atilf.atilf.fr/gsouvay/scripts/dmfX.exe?LIEN_DMF;PROJET=DicFro;LEMME=',
123 : 'internal' => false,
124 : ),
125 : 'jeanneau' => array(
126 : 'introduction' => 'http://www.prima-elementa.fr/Dico.htm',
127 : 'class' => 'Model_Search_Jeanneau',
128 : 'internal' => false,
129 : ),
130 : 'leconjugueur' => array(
131 : 'introduction' => 'http://www.leconjugueur.com/',
132 : 'search' => 'http://www.leconjugueur.com/php5/index.php?v=',
133 : 'internal' => false,
134 : ),
135 : 'littre' => array(
136 : 'introduction' => 'http://francois.gannaz.free.fr/Littre/',
137 : 'search' => 'http://francois.gannaz.free.fr/Littre/xmlittre.php?requete=',
138 : 'internal' => false,
139 : ),
140 : 'whitaker' => array(
141 : 'introduction' => 'http://lysy2.archives.nd.edu/cgi-bin/words.exe',
142 : 'search' => 'http://lysy2.archives.nd.edu/cgi-bin/words.exe?',
143 : 'internal' => false,
144 : ),
145 : );
146 :
147 : /**
148 : * Flipped list of actions
149 : * @var array
150 : */
151 : public $actionsFlipped;
152 :
153 : /**
154 : * Information on a dictionary
155 : * @var array
156 : */
157 : public $dictionaryInfo;
158 :
159 : /**
160 : * Front controller
161 : * @var object
162 : */
163 : public $front;
164 :
165 : /**
166 : * View object
167 : * @var object
168 : */
169 : public $view;
170 :
171 : /**
172 : * Constructor
173 : *
174 : * @param object $front the front controller
175 : * @return void
176 : */
177 : public function __construct(Engine_Front $front)
178 : {
179 32 : $this->front = $front;
180 32 : $this->view = $this->front->view;
181 32 : }
182 :
183 : /**
184 : * Method overload to call an action
185 : *
186 : * @param string $action the action name
187 : * @param array $arguments the list of arguments
188 : * @return void
189 : */
190 : public function __call($action, $arguments)
191 : {
192 3 : $method = $this->setActions();
193 3 : $this->$method();
194 3 : }
195 :
196 : /**
197 : * Processes the action to display the "about" page
198 : *
199 : * @return void
200 : */
201 : public function aboutAction()
202 : {
203 2 : $this->view->information = 'information/about.phtml';
204 2 : }
205 :
206 : /**
207 : * Sets the action for compatibility with 4.2, "d" and "w" still used by some external links
208 : *
209 : * Note: the name of this method must not finish with "Action"
210 : * so it is not mistaken with a proper action
211 : *
212 : * @return void
213 : */
214 : public function compatibilityActions()
215 : {
216 5 : isset($this->front->params['d']) and isset($this->front->params['w']) and
217 1 : $this->front->action = 'chercher';
218 5 : }
219 :
220 : /**
221 : * Sets the dictionary for compatibility with 4.2, "d" still used by some external links
222 : *
223 : * @return string the name of the dictionary
224 : */
225 : public function compatibilityDictionary()
226 : {
227 : $dictionaries = array(
228 5 : 'gaffiot' => 'gaffiot',
229 5 : 'gdf' => 'dictionnaire-godefroy',
230 5 : 'gdfc' => 'complement-godefroy',
231 5 : 'gdflex' => 'lexique-godefroy',
232 5 : 'vandaele' => 'vandaele',
233 5 : );
234 :
235 5 : $dictionary = isset($this->front->params['d'])?
236 1 : $this->front->params['d'] :
237 5 : null;
238 :
239 5 : return isset($dictionaries[$dictionary])?
240 1 : $dictionaries[$dictionary] :
241 5 : '';
242 : }
243 :
244 : /**
245 : * Sets the word to search for compatibility with 4.2, "w" still used by some external links
246 : *
247 : * @return string the word to search
248 : */
249 : public function compatibilityWord()
250 : {
251 5 : return isset($this->front->params['w'])?
252 1 : $this->front->params['w'] :
253 5 : '';
254 : }
255 :
256 : /**
257 : * Complete an action method name
258 : *
259 : * Note: the name of this method must not finish with "Action"
260 : * so it is not mistaken with a proper action
261 : *
262 : * @param string $action the name of the action
263 : * @return string the method name
264 : */
265 : public function completeActions($action)
266 : {
267 5 : return $action . 'Action';
268 : }
269 :
270 : /**
271 : * Creates the a dictionary search object
272 : *
273 : * @return object the dictionary search object
274 : */
275 : public function createSearchObject()
276 : {
277 7 : $class = $this->dictionaryInfo['class'];
278 7 : $file = str_replace('_', '/', $class) . '.php';
279 7 : require_once $file;
280 :
281 7 : return new $class($this->front->config['data-dir']);
282 : }
283 :
284 : /**
285 : * Sets the view data after processing an action
286 : *
287 : * @return void
288 : */
289 : public function finish()
290 : {
291 3 : $this->view->homeLink = $this->setActionLink('home');
292 3 : $this->view->introductionLink = $this->setActionLink('introduction', $this->view->dictionary);
293 3 : $this->view->helpLink = $this->setActionLink('help');
294 3 : $this->view->aboutLink = $this->setActionLink('about');
295 :
296 3 : $this->view->wordLink = $this->setActionLink('search', $this->view->dictionary, '%s');
297 :
298 3 : $action = $this->parseActions() == 'introduction'?
299 1 : 'introduction' :
300 3 : 'search';
301 3 : $this->view->dictionaryLink = $this->setActionLink($action, '%s', $this->view->word);
302 :
303 3 : $this->view->previousPageLink = $this->setActionLink('previous', $this->view->dictionary,
304 3 : $this->view->page, $this->view->volume, $this->view->word);
305 3 : $this->view->nextPageLink = $this->setActionLink('next', $this->view->dictionary,
306 3 : $this->view->page, $this->view->volume, $this->view->word);
307 :
308 3 : $needVolume = ($this->view->dictionary == 'dictionnaire-godefroy' or
309 3 : $this->view->dictionary == 'complement-godefroy')?
310 3 : '%s' :
311 3 : '';
312 3 : $this->view->goPageLink = $this->setActionLink('page', $this->view->dictionary,
313 3 : '%s', $needVolume, $this->view->word);
314 3 : }
315 :
316 : /**
317 : * Flips the dictionaries information
318 : *
319 : * Note: the name of this method must not finish with "Action"
320 : * so it is not mistaken with a proper action
321 : *
322 : * @return void
323 : */
324 : public function flipActions()
325 : {
326 6 : $string = new Common_String;
327 :
328 6 : $actions = array_map(array($string, 'dash2CamelCase'), $this->actions);
329 6 : $this->actionsFlipped = array_flip($actions);
330 6 : }
331 :
332 : /**
333 : * Processes the action to display the "help" page
334 : *
335 : * @return void
336 : */
337 : public function helpAction()
338 : {
339 1 : $this->view->information = 'information/help.phtml';
340 1 : }
341 :
342 : /**
343 : * Processes the action to display the "home" page
344 : *
345 : * @return void
346 : */
347 : public function homeAction()
348 : {
349 3 : $this->view->information = 'information/home.phtml';
350 3 : }
351 :
352 : /**
353 : * Processes the action to display a dictionary "introduction" page
354 : *
355 : * @return void
356 : */
357 : public function introductionAction()
358 : {
359 1 : if ($this->isInternalDictionary()) {
360 1 : $this->view->introduction = 'introduction/' . $this->dictionaryInfo['introduction'];
361 1 : } else {
362 1 : $this->view->externalDict = $this->dictionaryInfo['introduction'];
363 : }
364 1 : }
365 :
366 : /**
367 : * Sets data before processing an action
368 : *
369 : * @return void
370 : */
371 : public function init()
372 : {
373 3 : $this->flipActions();
374 :
375 3 : $this->setDictionary();
376 3 : $this->setWord();
377 3 : $this->setPage();
378 3 : $this->setVolume();
379 3 : $this->setNoDictChange();
380 3 : }
381 :
382 : /**
383 : * Checks if the dictionary is internal or external
384 : *
385 : * @return boolean true if internal, false if external
386 : */
387 : public function isInternalDictionary()
388 : {
389 6 : return $this->dictionaryInfo['internal'];
390 : }
391 :
392 : /**
393 : * Processes the "go to next page" action
394 : *
395 : * @return void
396 : */
397 : public function nextAction()
398 : {
399 1 : $this->pageAction('goToNextPage');
400 1 : }
401 :
402 : /**
403 : * Processes the "go to a page" action
404 : *
405 : * @return void
406 : */
407 : public function pageAction($action = 'goToPage')
408 : {
409 3 : if ($this->isInternalDictionary()) {
410 3 : $search = $this->createSearchObject();
411 3 : $result = $search->$action($this->view->volume, $this->view->page);
412 3 : $this->setViewElements($result);
413 3 : }
414 3 : }
415 :
416 : /**
417 : * Parses an action
418 : *
419 : * Note: the name of this method must not finish with "Action"
420 : * so it is not mistaken with a proper action
421 : *
422 : * @return string the action parsed
423 : */
424 : public function parseActions()
425 : {
426 6 : return str_replace('Action', '', $this->front->action);
427 : }
428 :
429 : /**
430 : * Processes the "go to previous page" action
431 : *
432 : * @return void
433 : */
434 : public function previousAction()
435 : {
436 1 : $this->pageAction('goToPreviousPage');
437 1 : }
438 :
439 : /**
440 : * Searches an external dictionary
441 : *
442 : * @return void
443 : */
444 : public function searchExternalDict()
445 : {
446 2 : $word = $this->view->word;
447 :
448 2 : switch($this->view->dictionary) {
449 2 : case 'jeanneau':
450 1 : $search = $this->createSearchObject();
451 1 : $this->view->externalDict = $search->searchWord($word);
452 1 : break;
453 :
454 2 : case 'leconjugueur':
455 2 : case 'littre':
456 2 : case 'whitaker':
457 1 : $string = new Common_String;
458 1 : $word = $string->utf8toASCII($word);
459 : // break;
460 :
461 2 : default:
462 2 : $this->view->externalDict = $this->dictionaryInfo['search'] . $word;
463 2 : }
464 2 : }
465 :
466 : /**
467 : * Searches an internal dictionary
468 : *
469 : * @return void
470 : */
471 : public function searchInternalDict()
472 : {
473 2 : $search = $this->createSearchObject();
474 2 : $result = $search->searchWord($this->view->word);
475 :
476 2 : if ($this->view->dictionary == 'tableaux-de-conjugaison') {
477 1 : list($this->view->tcaf, $this->view->composedVerbs) = $result;
478 1 : } else {
479 2 : $this->setViewElements($result);
480 : }
481 2 : }
482 :
483 : /**
484 : * Processes the "search for a word" action
485 : *
486 : * @return void
487 : */
488 : public function searchAction()
489 : {
490 1 : $this->isInternalDictionary()?
491 1 : $this->searchInternalDict() :
492 1 : $this->searchExternalDict();
493 1 : }
494 :
495 : /**
496 : * Sets an action link
497 : *
498 : * @return string the action link
499 : */
500 : public function setActionLink()
501 : {
502 4 : $arguments = func_get_args();
503 4 : $arguments = array_filter($arguments);
504 :
505 4 : $arguments[0] = $this->translateActions($arguments[0]);
506 :
507 4 : $link = implode('/', $arguments);
508 :
509 4 : $this->view->noDictChange and $link .= '?no-dict-change=1';
510 :
511 4 : return $link;
512 : }
513 :
514 : /**
515 : * Validates and sets the action
516 : *
517 : * Note: the name of this method must not finish with "Action"
518 : * so it is not mistaken with a proper action
519 : *
520 : * @return string the validated action or the "home" action if invalid
521 : */
522 : public function setActions()
523 : {
524 4 : $this->compatibilityActions();
525 4 : $action = $this->parseActions();
526 4 : $action = isset($this->actionsFlipped[$action])?
527 2 : $this->actionsFlipped[$action] :
528 4 : 'home';
529 :
530 4 : return $this->front->action = $this->completeActions($action);
531 : }
532 :
533 : /**
534 : * Validates and sets the dictionary
535 : *
536 : * @return void
537 : */
538 : public function setDictionary()
539 : {
540 10 : $dictionary = @func_get_arg(0) or // used for testing only
541 4 : $dictionary = $this->compatibilityDictionary() or
542 4 : $dictionary = array_shift($this->front->actionParams);
543 :
544 10 : $this->view->dictionary = isset($this->dictionaries[$dictionary])?
545 8 : $dictionary :
546 3 : 'dictionnaire-godefroy';
547 10 : $this->dictionaryInfo = $this->dictionaries[$this->view->dictionary];
548 10 : }
549 :
550 : /**
551 : * Freezes the dictionary if requested
552 : *
553 : * For example, when DicFro is called from MultiDic, the select box to change
554 : * dictionaries is disabled
555 : *
556 : * @return void
557 : */
558 : public function setNoDictChange()
559 : {
560 4 : $this->view->noDictChange = !empty($this->front->params['no-dict-change']);
561 4 : }
562 :
563 : /**
564 : * Validates and sets the dictionary page
565 : *
566 : * @return void
567 : */
568 : public function setPage()
569 : {
570 4 : foreach($this->front->actionParams as $idx => $param) {
571 2 : if (is_numeric($param)) {
572 2 : $this->view->page = $param;
573 2 : unset($this->front->actionParams[$idx]);
574 2 : break;
575 : }
576 4 : }
577 4 : }
578 :
579 : /**
580 : * Sets view elements
581 : *
582 : * @param array $elements the elements coming from a model
583 : * @return void
584 : */
585 : public function setViewElements($elements)
586 : {
587 : list($content,
588 6 : $this->view->errataImages,
589 6 : $this->view->errataText,
590 6 : $this->view->ghostwords,
591 6 : $this->view->identifiedWords,
592 6 : $this->view->identifiedVerbs,
593 6 : $this->view->identifiedLatinWords,
594 6 : $this->view->volume,
595 6 : $this->view->page,
596 6 : $this->view->firstWord) = $elements;
597 :
598 6 : if ($this->view->dictionary == 'lexique-roman') {
599 1 : $this->view->vocabulary = $content;
600 1 : } else {
601 6 : $this->view->definition = $content;
602 : }
603 6 : }
604 :
605 : /**
606 : * Validates and sets the dictionary volume
607 : *
608 : * @return void
609 : */
610 : public function setVolume()
611 : {
612 4 : foreach($this->front->actionParams as $idx => $param) {
613 2 : if (is_numeric($param)) {
614 2 : $this->view->volume = $param;
615 2 : unset($this->front->actionParams[$idx]);
616 2 : break;
617 : }
618 4 : }
619 4 : }
620 :
621 : /**
622 : * Validates and sets the word to search for
623 : *
624 : * @return void
625 : */
626 : public function setWord()
627 : {
628 4 : if (!($word = $this->compatibilityWord())) {
629 4 : foreach($this->front->actionParams as $idx => $param) {
630 2 : if (!is_numeric($param)) {
631 2 : $word = $param;
632 2 : unset($this->front->actionParams[$idx]);
633 2 : break;
634 : }
635 4 : }
636 4 : }
637 :
638 4 : $word = urldecode($word);
639 4 : $this->view->word = strip_tags($word);
640 4 : }
641 :
642 : /**
643 : * Translates an action into a method name
644 : *
645 : * Note: the name of this method must not finish with "Action"
646 : * so it is not mistaken with a proper action
647 : *
648 : * @param string $action the action name to translate
649 : * @return string the translated action name
650 : */
651 : public function translateActions($action)
652 : {
653 5 : isset($this->actions[$action]) and $action = $this->actions[$action];
654 :
655 5 : return $action;
656 : }
|