| Total Complexity | 40 |
| Total Lines | 331 |
| Duplicated Lines | 0 % |
| Changes | 0 | ||
Complex classes like BasePage_Controller often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use BasePage_Controller, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 271 | class BasePage_Controller extends ContentController { |
||
| 272 | |||
| 273 | private static $allowed_actions = array( |
||
| 274 | 'downloadpdf', |
||
| 275 | 'SearchForm', |
||
| 276 | 'results' |
||
| 277 | ); |
||
| 278 | |||
| 279 | /** |
||
| 280 | * How many search results should be shown per-page? |
||
| 281 | * @var int |
||
| 282 | */ |
||
| 283 | public static $results_per_page = 10; |
||
| 284 | |||
| 285 | public static $search_index_class = 'SolrSearchIndex'; |
||
| 286 | |||
| 287 | /** |
||
| 288 | * If spelling suggestions for searches are given, enable |
||
| 289 | * suggested searches to be followed immediately |
||
| 290 | * |
||
| 291 | * @config |
||
| 292 | * @var bool |
||
| 293 | */ |
||
| 294 | private static $search_follow_suggestions = true; |
||
| 295 | |||
| 296 | /** |
||
| 297 | * Which classes should be queried when searching? |
||
| 298 | * @var array |
||
| 299 | */ |
||
| 300 | public static $classes_to_search = array( |
||
| 301 | array( |
||
| 302 | 'class' => 'Page', |
||
| 303 | 'includeSubclasses' => true |
||
| 304 | ) |
||
| 305 | ); |
||
| 306 | |||
| 307 | /** |
||
| 308 | * Serve the page rendered as PDF. |
||
| 309 | */ |
||
| 310 | public function downloadpdf() { |
||
| 311 | if(!Config::inst()->get('BasePage', 'pdf_export')) return false; |
||
| 312 | |||
| 313 | // We only allow producing live pdf. There is no way to secure the draft files. |
||
| 314 | Versioned::reading_stage('Live'); |
||
| 315 | |||
| 316 | $path = $this->dataRecord->getPdfFilename(); |
||
| 317 | if(!file_exists($path)) { |
||
| 318 | $this->generatePDF(); |
||
| 319 | } |
||
| 320 | |||
| 321 | return SS_HTTPRequest::send_file(file_get_contents($path), basename($path), 'application/pdf'); |
||
| 322 | } |
||
| 323 | |||
| 324 | /* |
||
| 325 | * This will return either pdf_base_url from YML, CWP_SECURE_DOMAIN |
||
| 326 | * from _ss_environment, or blank. In that order of importance. |
||
| 327 | */ |
||
| 328 | public function getPDFBaseURL() { |
||
| 340 | } |
||
| 341 | |||
| 342 | /* |
||
| 343 | * Don't use the proxy if the pdf domain is the CWP secure domain |
||
| 344 | * Or if we aren't on a CWP server |
||
| 345 | */ |
||
| 346 | public function getPDFProxy($pdf_base_url) { |
||
| 347 | if (!defined('CWP_SECURE_DOMAIN') || $pdf_base_url == CWP_SECURE_DOMAIN.'/') { |
||
| 348 | $proxy = ''; |
||
| 349 | } else { |
||
| 350 | $proxy = ' --proxy ' . SS_OUTBOUND_PROXY . ':' . SS_OUTBOUND_PROXY_PORT; |
||
| 351 | } |
||
| 352 | return $proxy; |
||
| 353 | } |
||
| 354 | |||
| 355 | /** |
||
| 356 | * Render the page as PDF using wkhtmltopdf. |
||
| 357 | */ |
||
| 358 | public function generatePDF() { |
||
| 359 | if(!Config::inst()->get('BasePage', 'pdf_export')) return false; |
||
| 360 | |||
| 361 | $binaryPath = Config::inst()->get('BasePage', 'wkhtmltopdf_binary'); |
||
| 362 | if(!$binaryPath || !is_executable($binaryPath)) { |
||
| 363 | if(defined('WKHTMLTOPDF_BINARY') && is_executable(WKHTMLTOPDF_BINARY)) { |
||
| 364 | $binaryPath = WKHTMLTOPDF_BINARY; |
||
| 365 | } |
||
| 366 | } |
||
| 367 | |||
| 368 | if(!$binaryPath) { |
||
| 369 | user_error('Neither WKHTMLTOPDF_BINARY nor BasePage.wkhtmltopdf_binary are defined', E_USER_ERROR); |
||
| 370 | } |
||
| 371 | |||
| 372 | if(Versioned::get_reading_mode() == 'Stage.Stage') { |
||
| 373 | user_error('Generating PDFs on draft is not supported', E_USER_ERROR); |
||
| 374 | } |
||
| 375 | |||
| 376 | set_time_limit(60); |
||
| 377 | |||
| 378 | // prepare the paths |
||
| 379 | $pdfFile = $this->dataRecord->getPdfFilename(); |
||
| 380 | $bodyFile = str_replace('.pdf', '_pdf.html', $pdfFile); |
||
| 381 | $footerFile = str_replace('.pdf', '_pdffooter.html', $pdfFile); |
||
| 382 | |||
| 383 | // make sure the work directory exists |
||
| 384 | if(!file_exists(dirname($pdfFile))) Filesystem::makeFolder(dirname($pdfFile)); |
||
| 385 | |||
| 386 | //decide the domain to use in generation |
||
| 387 | $pdf_base_url = $this->getPDFBaseURL(); |
||
| 388 | |||
| 389 | // Force http protocol on CWP - fetching from localhost without using the proxy, SSL terminates on gateway. |
||
| 390 | if (defined('CWP_ENVIRONMENT')) { |
||
| 391 | Config::inst()->nest(); |
||
| 392 | Config::inst()->update('Director', 'alternate_protocol', 'http'); |
||
| 393 | //only set alternate protocol if CWP_SECURE_DOMAIN is defined OR pdf_base_url is |
||
| 394 | if($pdf_base_url){ |
||
| 395 | Config::inst()->update('Director', 'alternate_base_url', 'http://'.$pdf_base_url); |
||
| 396 | } |
||
| 397 | } |
||
| 398 | |||
| 399 | $bodyViewer = $this->getViewer('pdf'); |
||
| 400 | |||
| 401 | // write the output of this page to HTML, ready for conversion to PDF |
||
| 402 | file_put_contents($bodyFile, $bodyViewer->process($this)); |
||
| 403 | |||
| 404 | // get the viewer for the current template with _pdffooter |
||
| 405 | $footerViewer = $this->getViewer('pdffooter'); |
||
| 406 | |||
| 407 | // write the output of the footer template to HTML, ready for conversion to PDF |
||
| 408 | file_put_contents($footerFile, $footerViewer->process($this)); |
||
| 409 | |||
| 410 | if (defined('CWP_ENVIRONMENT')) { |
||
| 411 | Config::inst()->unnest(); |
||
| 412 | } |
||
| 413 | |||
| 414 | //decide what the proxy should look like |
||
| 415 | $proxy = $this->getPDFProxy($pdf_base_url); |
||
| 416 | |||
| 417 | // finally, generate the PDF |
||
| 418 | $command = $binaryPath . $proxy . ' --outline -B 40pt -L 20pt -R 20pt -T 20pt --encoding utf-8 --orientation Portrait --disable-javascript --quiet --print-media-type '; |
||
| 419 | $retVal = 0; |
||
| 420 | $output = array(); |
||
| 421 | exec($command . " --footer-html \"$footerFile\" \"$bodyFile\" \"$pdfFile\" &> /dev/stdout", $output, $return_val); |
||
| 422 | |||
| 423 | // remove temporary file |
||
| 424 | unlink($bodyFile); |
||
| 425 | unlink($footerFile); |
||
| 426 | |||
| 427 | // output any errors |
||
| 428 | if($return_val != 0) { |
||
| 429 | user_error('wkhtmltopdf failed: ' . implode("\n", $output), E_USER_ERROR); |
||
| 430 | } |
||
| 431 | |||
| 432 | // serve the generated file |
||
| 433 | return SS_HTTPRequest::send_file(file_get_contents($pdfFile), basename($pdfFile), 'application/pdf'); |
||
| 434 | } |
||
| 435 | |||
| 436 | /** |
||
| 437 | * Site search form |
||
| 438 | */ |
||
| 439 | public function SearchForm() |
||
| 440 | { |
||
| 441 | $searchText = $this->getRequest()->getVar('Search'); |
||
| 442 | |||
| 443 | $fields = new FieldList( |
||
| 444 | TextField::create('Search', false, $searchText) |
||
| 445 | ); |
||
| 446 | $actions = new FieldList( |
||
| 447 | new FormAction('results', _t('SearchForm.GO', 'Go')) |
||
| 448 | ); |
||
| 449 | |||
| 450 | $form = SearchForm::create($this, 'SearchForm', $fields, $actions); |
||
| 451 | $form->setFormAction('search/SearchForm'); |
||
| 452 | |||
| 453 | return $form; |
||
| 454 | } |
||
| 455 | |||
| 456 | /** |
||
| 457 | * Get search form with _header suffix |
||
| 458 | * |
||
| 459 | * @return SearchForm |
||
| 460 | */ |
||
| 461 | public function HeaderSearchForm() |
||
| 462 | { |
||
| 463 | return $this->SearchForm()->setTemplate('SearchForm_header'); |
||
| 464 | } |
||
| 465 | |||
| 466 | /** |
||
| 467 | * Process and render search results. |
||
| 468 | * |
||
| 469 | * @param array $data The raw request data submitted by user |
||
| 470 | * @param SearchForm $form The form instance that was submitted |
||
| 471 | * @param SS_HTTPRequest $request Request generated for this action |
||
| 472 | * @return HTMLText |
||
| 473 | */ |
||
| 474 | public function results($data, $form, $request) { |
||
| 475 | // Check parameters for terms, pagination, and if we should follow suggestions |
||
| 476 | $keywords = empty($data['Search']) ? '' : $data['Search']; |
||
| 477 | $start = isset($data['start']) ? $data['start'] : 0; |
||
| 478 | $suggestions = isset($data['suggestions']) |
||
| 479 | ? $data['suggestions'] |
||
| 480 | : $this->config()->search_follow_suggestions; |
||
| 481 | |||
| 482 | $results = CwpSearchEngine::create() |
||
| 483 | ->search( |
||
| 484 | $keywords, |
||
| 485 | $this->getClassesToSearch(), |
||
| 486 | $this->getSearchIndex(), |
||
| 487 | $this->getSearchPageSize(), |
||
| 488 | $start, |
||
| 489 | $suggestions |
||
| 490 | ); |
||
| 491 | |||
| 492 | // Customise content with these results |
||
| 493 | $properties = array( |
||
| 494 | 'MetaTitle' => _t('CWP_Search.MetaTitle', 'Search {keywords}', array('keywords' => $keywords)), |
||
| 495 | 'NoSearchResults' => _t('CWP_Search.NoResult', 'Sorry, your search query did not return any results.'), |
||
| 496 | 'EmptySearch' => _t('CWP_Search.EmptySearch', 'Search field empty, please enter your search query.'), |
||
| 497 | 'PdfLink' => '', |
||
| 498 | 'Title' => _t('SearchForm.SearchResults', 'Search Results'), |
||
| 499 | ); |
||
| 500 | $this->extend('updateSearchResults', $results, $properties); |
||
| 501 | |||
| 502 | // Customise page |
||
| 503 | $response = $this->customise($properties); |
||
| 504 | if($results) { |
||
| 505 | $response = $response |
||
| 506 | ->customise($results) |
||
| 507 | ->customise(array( 'Results' => $results->getResults() )); |
||
| 508 | } |
||
| 509 | |||
| 510 | // Render |
||
| 511 | $templates = $this->getResultsTemplate($request); |
||
| 512 | return $response->renderWith($templates); |
||
| 513 | } |
||
| 514 | |||
| 515 | /** |
||
| 516 | * Select the template to render search results with |
||
| 517 | * |
||
| 518 | * @param SS_HTTPRequest $request |
||
| 519 | * @return array |
||
| 520 | */ |
||
| 521 | protected function getResultsTemplate($request) { |
||
| 530 | } |
||
| 531 | |||
| 532 | /** |
||
| 533 | * Provide scripts as needed by the *default* theme. |
||
| 534 | * Override this function if you are using a custom theme based on the *default*. |
||
| 535 | * |
||
| 536 | * @deprecated 1.6..2.0 Use "starter" theme instead |
||
| 537 | */ |
||
| 538 | public function getBaseScripts() { |
||
| 539 | $scripts = array(); |
||
| 540 | $this->extend('updateBaseScripts', $scripts); |
||
| 541 | return $scripts; |
||
| 542 | } |
||
| 543 | |||
| 544 | /** |
||
| 545 | * Provide stylesheets, as needed by the *default* theme assumed by this recipe. |
||
| 546 | * Override this function if you are using a custom theme based on the *default*. |
||
| 547 | * |
||
| 548 | * @deprecated 1.6..2.0 Use "starter" theme instead |
||
| 549 | */ |
||
| 550 | public function getBaseStyles() { |
||
| 551 | $styles = array(); |
||
| 552 | $this->extend('updateBaseStyles', $styles); |
||
| 553 | return $styles; |
||
| 554 | } |
||
| 555 | |||
| 556 | /** |
||
| 557 | * Provide current year. |
||
| 558 | */ |
||
| 559 | public function CurrentDatetime() { |
||
| 560 | return SS_Datetime::now(); |
||
| 561 | } |
||
| 562 | |||
| 563 | public function getRSSLink() { |
||
| 564 | } |
||
| 565 | |||
| 566 | /** |
||
| 567 | * Get the search index registered for this application |
||
| 568 | * |
||
| 569 | * @return CwpSearchIndex |
||
| 570 | */ |
||
| 571 | protected function getSearchIndex() |
||
| 572 | { |
||
| 573 | // Will be a service name in 2.0 and returned via injector |
||
| 574 | /** @var CwpSearchIndex $index */ |
||
| 575 | $index = null; |
||
| 576 | if (self::$search_index_class) { |
||
| 577 | $index = Object::singleton(self::$search_index_class); |
||
| 578 | } |
||
| 579 | return $index; |
||
| 580 | } |
||
| 581 | |||
| 582 | /** |
||
| 583 | * Gets the list of configured classes to search |
||
| 584 | * |
||
| 585 | * @return array |
||
| 586 | */ |
||
| 587 | protected function getClassesToSearch() |
||
| 588 | { |
||
| 589 | // Will be private static config in 2.0 |
||
| 590 | return self::$classes_to_search; |
||
| 591 | } |
||
| 592 | |||
| 593 | /** |
||
| 594 | * Get page size for search |
||
| 595 | * |
||
| 596 | * @return int |
||
| 597 | */ |
||
| 598 | protected function getSearchPageSize() |
||
| 602 | } |
||
| 603 | } |
||
| 604 |