Apache2-PageKit

 view release on metacpan or  search on metacpan

lib/Apache2/PageKit/View.pm  view on Meta::CPAN

  foreach my $object (@{$view->{associated_objects}}){
    foreach my $key ($object->param){
      # note that we only fill in MODEL_VARs, to avoid errors when setting
      # loops in HTML::Template
      my $type = $tmpl->query(name => $key);
      if ( $type && $type eq 'VAR' ) {
        $view->{pkit_pk}->{browser_cache} = 'no';
        # we need a separate variable for value to force scalar context
	# for multivalued params http://www.xx.yy/a?foo=12&foo=13
        my $value = $object->param($key);
	$tmpl->param($key, $value);
      }
    }
  }

  # finally, we use the $output_param_object object to fill in template
  # get params from $view object
  # note that in this case we allow for MODEL_LOOPs as well as MODEL_VARs
  my $output_param_object = $view->{output_param_object};
  foreach my $key ($output_param_object->param){
    my $value = $output_param_object->param($key);
    $view->{pkit_pk}->{browser_cache} = 'no';
    $tmpl->param($key, $value);
  }

  my $output = $tmpl->output;

  if($record->{has_form}){
    # if fillinform_objects is set, then we use that to fill in any HTML
    # forms in the template.
    my $fif;
    if(@{$view->{fillinform_objects}}){
      $view->{pkit_pk}->{browser_cache} = 'no';
      Encode::_utf8_off($output);
      $fif = HTML::FillInForm->new();
      $output = $fif->fill(scalarref => \$output,
                           fobject   => $view->{fillinform_objects},
			   ignore_fields => $view->{ignore_fillinform_fields}
			  );
      Encode::_utf8_on($output);
    }
  }
  if($view->{can_edit} eq 'yes'){
    $view->{pkit_pk}->{browser_cache} = 'no';
    Apache2::PageKit::Edit::add_edit_links($view, $record, \$output);
  }
  return \$output;
}

# gets static gzipped file, creating it if necessary
sub get_static_gzip {
  my ($view, $filename) = @_;
  my ($gzip_mtime, $gzipped_content);

  (my $relative_filename = $filename) =~ s!^$view->{view_dir}/!!;
  my $gzipped_filename = "$view->{cache_dir}/$relative_filename.gz";

  # is the cache entry valid or changed on disc?
  if(-f "$gzipped_filename"){
    open my $fh, "<$gzipped_filename" or return undef;
    binmode $fh;
    # read mtime from first line
    chomp($gzip_mtime = <$fh>);

    # read rest of gzipped content
    local $/;
    $gzipped_content = <$fh>;
    close $fh;
    if($view->{reload} ne 'no'){
      # is the cache entry valid or changed on disc?
      my $mtime = ( stat($filename) )[9];
      if($mtime != $gzip_mtime){
	$gzipped_content = $view->_create_static_zip($filename, $gzipped_filename);
      }
    }
  } else {
    $gzipped_content = $view->_create_static_zip($filename, $gzipped_filename);
  }
  return $gzipped_content;
}

# opens template, each 
sub open_view {
  my ($view, $page_id, $pkit_view, $lang) = @_;

  return if exists $view->{already_loaded}->{$page_id};

  my $record = $view->_fetch_from_file_cache($page_id, $pkit_view, $lang);
  unless($record){
    # template not cached, load now
    $view->_load_page($page_id, $pkit_view);
    $record = $view->_fetch_from_file_cache($page_id, $pkit_view, $lang);
    die "Error loading record for page_id $page_id and view $pkit_view"
      unless $record;
  }

  if($view->{reload} ne 'no'){
    # check for updated files on disk
    unless($view->_is_record_uptodate($record, $pkit_view, $page_id)){
      # one of the included files changed on disk, reload
      $view->_load_page($page_id, $pkit_view);
      $record = $view->_fetch_from_file_cache($page_id, $pkit_view, $lang);
    }
  }

  $view->{record} = $record;
  $view->{already_loaded}->{$page_id} = 1;
}

sub preparse_templates {
  my ($view) = @_;

  my $view_dir = $view->{view_dir};

  my $load_template_sub = sub {
    return unless /\.tmpl$/;
    my $template_file = "$File::Find::dir/$_";
    my ($pkit_view, $page_id) =
      ($template_file =~ m!$view_dir/([^/]*)/Page/(.*?)\.(tmpl|tt)$!);
    return unless $page_id;
    $view->open_view($page_id, $pkit_view);
  };

  File::Find::find({wanted => $load_template_sub},
#		    follow => 1},
		    $view_dir);
}

sub template_file_exists {
  my ($view, $page_id, $pkit_view) = @_;
  return 1 if $view->_find_template($pkit_view,$page_id);
}

# private methods

# creates gzipped file
sub _create_static_zip {
  my ($view, $filename, $gzipped_filename) = @_;
  local $/;
  open my $fh, "<$filename" or return undef;
  binmode $fh;
  my $content = <$fh>;
  close $fh;

  $view->_html_clean(\$content);

  my $gzipped_content = Compress::Zlib::memGzip($content);

  (my $gzipped_dir = $gzipped_filename) =~ s!(/)?[^/]*?$!!;

  File::Path::mkpath("$gzipped_dir");

  if ($gzipped_content) {
    my $mtime = (stat($filename))[9];
    if ( open my $gzip_fh, ">$gzipped_filename" ) {
      binmode $gzip_fh;
      print $gzip_fh "$mtime\n";
      print $gzip_fh $gzipped_content;
      close $gzip_fh;
    } else {
      warn "can not create gzip cache file $view->{cache_dir}/$gzipped_filename: $!";
    }
    return $gzipped_content;
  }
  return undef;
}

sub _fetch_from_file_cache {
  my ($view, $page_id, $pkit_view, $lang) = @_;

    my ($extra_param, $param_hash) = ("", "");
    
    # get a list of requested params in the *.xsl file
    if (my @xml_params = sort keys %{$Apache2::PageKit::Content::PAGE_ID_XSL_PARAMS->{$page_id}}) {
      my $param_obj = $view->{input_param_object};
      for my $xml_param (@xml_params){
        my $value = $param_obj->param($xml_param) || '';
	$extra_param .= "&$xml_param=" . $value;
      }
      $param_hash = Digest::MD5::md5_hex($extra_param);
    }

  my $cache_filename = "$view->{cache_dir}/$page_id.$pkit_view.$lang$param_hash";

  if(-f "$cache_filename"){
    # cache file exists for specified language
    return Storable::lock_retrieve($cache_filename);
  } else {
    $cache_filename = "$view->{cache_dir}/$page_id.$pkit_view.$view->{default_lang}$param_hash";
    if(-f "$cache_filename"){
      # cache file exists for default language
      return Storable::lock_retrieve($cache_filename);
    } else {
      return;
    }
  }
}

sub _find_template {
  my ($view, $pkit_view, $id) = @_;
  my $template_file = "$view->{view_dir}/$pkit_view/$id.tmpl";
  if(-f "$template_file"){
    return $template_file;
  } else {
    $template_file = "$view->{view_dir}/Default/$id.tmpl";
    if(-f "$template_file"){
      return $template_file;
    } else {
      return undef;
    }
  }
}

# clean up html, remove white spaces, etc
sub _html_clean {
  my ($view, $html_code_ref) = @_;

lib/Apache2/PageKit/View.pm  view on Meta::CPAN

    my $cid_key = join '', $component_id, sort %params;
    unless ( $view->{component_ids_hash}->{$cid_key}++ ) {
      push @{ $view->{component_ids} }, [ $component_id , \%params ];
    }
    
    # check for recursive pkit_components
    if($view->{component_ids_hash}->{$cid_key} > 100){
      die "Likely recursive PKIT_COMPONENTS for component_id $component_id and giving up.";
    }

    my $template_ref = $view->_load_component($page_id, $component_id, $pkit_view, \%params);
    return $$template_ref;
  }
}

sub _is_record_uptodate {
  my ($view, $record, $pkit_view, $page_id) = @_;

  # first check timestamps
  my $include_mtimes = $record->{include_mtimes};
  while (my ($filename, $cache_mtime) = each %$include_mtimes){
    # check if file still exists
    unless(-f "$filename"){
      return 0;
    }

    # check if file is up to date
    my $file_mtime = (stat($filename))[9];
#    print "hi $filename - $cache_mtime - $file_mtime<br>";
    if($file_mtime != $cache_mtime){
      return 0;
    }

    if($filename =~ m!^$view->{view_dir}/Default/! && $pkit_view ne 'Default'){
      # check to see if any new files have been uploaded to the $pkit_view dir
      (my $check_filename = $filename) =~ s!^$view->{view_dir}/Default/!$view->{view_dir}/$pkit_view/!;
      if (-f "$check_filename"){
	return 0;
      }
    }
  }

  # record up to date!
  return 1;
}

# here the usage of "component" also includes page
sub _load_component {
  my ($view, $page_id, $component_id, $pkit_view, $component_params) = @_;

  my $template_file = $view->_find_template($pkit_view, $component_id);
  my $template_ref;

  unless($template_file){
    # no template file exists, attempt to generate from XML and XSL files
    # currently only XML::LibXSLT is supported
    $template_ref = $view->{content}->generate_template($page_id, $component_id, $pkit_view, $view->{input_param_object}, $component_params);
  } else {
      open my $template_fh, "<$template_file" or die "can not read $template_file";
      my $default_input_charset = $view->{default_input_charset};
      binmode $template_fh, ":encoding($default_input_charset)";
      local $/;
      my $template = <$template_fh>;
      close $template_fh;

    # expand PKIT_MACRO tags
    $template =~ s!<\s*PKIT_MACRO$key_value_pattern\s*/?>!$component_params->{uc($+)} || ''!egi;

    $template_ref = \$template;

    my $mtime = (stat(_))[9];
    $view->{include_mtimes}->{$template_file} = $mtime;
  }

  if($view->{can_edit} eq 'yes'){
    Apache2::PageKit::Edit::add_component_edit_stubs($view, $page_id, $template_ref, $pkit_view);
  }

  $view->_include_components($page_id,$template_ref,$pkit_view);

  return $template_ref;
}

sub _load_page {
  my ($view, $page_id, $pkit_view) = @_;

  $Apache2::PageKit::Content::PAGE_ID_XSL_PARAMS->{$page_id} = {};

  my $content = $view->{content} ||= Apache2::PageKit::Content->new(
						     content_dir => $view->{content_dir},
						     view_dir => $view->{view_dir},
						     default_lang => $view->{default_lang},
                                                     relaxed_parser => $view->{relaxed_parser},
                                                     template_class => $view->{template_class},
                                                     );

  $view->{lang_tmpl} = $content->{lang_tmpl} = {};
  $content->{include_mtimes} = {};
  $view->{component_ids_hash} = {};

  # we add Config.xml to the hash of files to be checked for mtimes,
  # in case default_input_charset or default_output_charset changes!
  (my $config_file = $view->{view_dir}) =~ s!/View$!/Config/Config.xml!;
  my $config_mtime = ( stat($config_file) )[9];
  $view->{include_mtimes} = {$config_file => $config_mtime};

  my $template_file = $view->_find_template($pkit_view, $page_id);
  my $template_ref = $view->_load_component($page_id,$page_id,$pkit_view);

  # remove PKIT_COMMENT parts.
  my $pkit_comment_re = $re_helper{ $view->{relaxed_parser} eq 'yes' ? 'relaxed_parser' : 'std_parser' }->{pkit_comment_re};
  $$template_ref =~ s/$pkit_comment_re//sgi;

  #  my $template_file = $view->_find_template($pkit_view, $page_id);
  my $lang_tmpl = $content->process_template($page_id, $template_ref);
  
  # add used content file(s) to the mtimes hash
  while( my ( $file, $mtime ) = each( %{ $content->{include_mtimes} } ) ) {
    $view->{include_mtimes}->{$file} = $mtime;
  }



( run in 0.998 second using v1.01-cache-2.11-cpan-39bf76dae61 )