=head1 NAME

YATT::Lite::WebMVC0::SiteApp - PSGI Handler for yatt

=head1 SYNOPSIS

  # In app.psgi

  use FindBin;
  use YATT::Lite::WebMVC0::SiteApp -as_base;
  use YATT::Lite qw/Entity *CON/;

  return do {

    my $site = MY->new(doc_root => "$FindBin::Bin/html");

    #----- You can define entities here. ----
    Entity session => sub {
      my ($this, $key) = @_;
      my $sess = $CON->get_session
        or return;
      $sess->param($key);
    };

    if (YATT::Lite::Factory->want_object) {

      # When app.psgi is loaded from yatt support scripts(eg. yatt lint),
      # return bare object, not app.

      $site;

    } else {

      # Otherwise, normal PSGI. You can use Plack::Builder and/or middleware.

      $site->to_app;
    }
  };

=head1 DESCRIPTION

C<SiteApp> is a L<Factory|YATT::Lite::Factory>
of L<DirApp|YATT::Lite::WebMVC0::DirApp>, which is a web specific
subclass of L<YATT::Lite>.

SiteApp takes a template directory tree at startup
and becomes a L<PSGI> application.

When SiteApp called for incoming request,
it first determins a sub-directory for the request.
Then SiteApp looks for DirApp from own cache, load/build it when necessary,
and finally invoke DirApp to handle do rest of work.

=head1 CONFIGS

SiteApp accepts L<YATT::Lite::Object> style configurations.

=head2 doc_root

Document root of this PSGI application. F<*.yatt> should be placed under this.
Usually, F<$FindBin::Bin/html>

=head2 app_ns

Namespace of per-directory L<YATT::Lite> class. Default is C<MyYATT>.
This will also be used as a base class of each C<YATT::Lite> instances.
This class will be loaded at startup (but can be missing).
If it exists, it must be a subclass of C<YATT::Lite>.

=head2 app_root

The application directory where F<app.psgi> lives in.
Sometime omissible, but recommended to set as C<$FindBin::Bin>.

=head2 app_base

Base DirApp for all DirApp under C<doc_root>.
A.k.a inheritance of app-directory.
Omissible. Usually, F<$FindBin::Bin/ytmpl>.

=head2 site_prefix

If your F<app.psgi> is located under subpath, specify this.
You can refer this from F<*.yatt> via C<&yatt:site_prefix();>.

=head2 header_charset

Default charset for HTTP response headers. Default is utf-8.

=head2 tmpl_encoding, output_encoding

Encoding of F<*.yatt> and HTTP response body, respectively.

XXX: should note about widechars....

=head2 no_nested_query

By default, yatt turns specific parameters into hashes/arrays
like L<PHP|http://www.php.net/manual/en/faq.html.php#faq.html.arrays>
and L<Ruby on Rails|http://guides.rubyonrails.org/action_controller_overview.html#hash-and-array-parameters>.
This feature is useful(I hope), but is experimental.
So if you don't want this feature, turn this config on.

=head2 psgi_static

Requests other than F<*.yatt>, F<*.ytmpl>, F<*.ydo> are passed to this PSGI app.
Default is:

  Plack::App::File->new(root => $self->{cf_doc_root})->to_app


=head2 backend

Room for your Model instance.
If it is given and it has C<startup> method is implemented,
C<< $backend->startup($siteapp, @all_dirapps) >>
will be called when C<prepare_app>.

=head1 METHODS

=head2 call($env)

PSGI entry function. SiteApp uses C<$env> as following:

=over 4

=item PATH_TRANSLATED, REDIRECT_STATUS

If C<< $env->{REDIRECT_STATUS} >> is C<200> and
has non empty C<< $env->{PATH_TRANSLATED} >>,
yatt tries to serve specified path.

=item PATH_INFO

Otherwise, yatt examines C<< $env->{PATH_INFO} >>
under F<doc_root> and F<app_base>, in this order.

=back

=head2 prepare_app

PSGI startup hook.

=head2 render($path_info, $args)

Aid for batch execution.

=head2 make_connection($parent_fh, @config)

Build helper for L<YATT::Lite::WebMVC0::Connection> object.
C<$parent_fh> can be undef.
If specified, C<< $con->flush >> will flush buffered contents to $parent_fh.

=head1 HOOKS

=head2 before_dirhandler($dirapp, $connection, $filename)

=head1 ENTITY FUNCTIONS

SiteApp registers following entity functions (usable in every
template as C<&yatt:NAME(ARGS);>). This section covers URL-related
ones. Most of them delegate to the same-named method of
L<$CON|YATT::Lite::WebMVC0::Connection>.

=head2 URL builders

X<GH-251> Recommended way to build app-internal links.
C<*_path> returns a path, C<*_url> returns an absolute url,
and both respect the mount point of the site. See
L<YATT::Lite::WebMVC0::Connection/URL BUILDING METHODS> for details.

  <a href="&yatt:site_path(/admin/);">admin</a>
  <a href="&yatt:site_path(/list,[page,2]);">page 2</a>

  <a href="&yatt:current_path([page,2]);">page 2 of this page</a>

  &yatt:site_url(/confirm);   (absolute; for emails etc.)
  &yatt:current_url();

=over 4

=item &yatt:site_path(PATH,QUERY);

=item &yatt:site_url(PATH,QUERY);

=item &yatt:current_path(QUERY);

=item &yatt:current_url(QUERY);

QUERY is optional and must be C<[key,value,...]> array form.

=back

=head2 Redirect

=over 4

=item &yatt:raise_redirect(URL);

=item &yatt:redirect(URL);

Same as C<< $CON->raise_redirect >>. Html made so far is discarded
and the rendering stops there.
See L<YATT::Lite::WebMVC0::Connection/REDIRECT>.

=back

=head2 Location inspection

These entities answer I<where this page is served>.
As a general rule, B<lowercase entities return yatt-normalized
values and are recommended>; UPPERCASE ones return raw PSGI env
values as-is (mainly for debugging).

Suppose the app is deployed at C</myapp> via Apache
C<Action> + C<AddHandler> (so raw C<SCRIPT_NAME> contains the
handler script path) behind a reverse proxy which sets
C<X-Forwarded-Proto: https>, and
C<https://example.com/myapp/auth/test?q=1> is served by
F<auth/test.yatt>:

  &yatt:script_name();    /myapp
  &yatt:SCRIPT_NAME();    /myapp/cgi-bin/runplack.cgi

  &yatt:script_dir();     /myapp/

  &yatt:script_uri();     https://example.com/myapp/auth/test
  &yatt:SCRIPT_URI();     http://example.com/myapp/auth/test

  &yatt:script_url();     /myapp/auth/test
  &yatt:SCRIPT_URL();     /myapp/auth/test

  &yatt:dir_location();   /myapp/auth/
  &yatt:file_location();  /myapp/auth/test
  &yatt:page_location();  /myapp/auth/test

  &yatt:absrequest();     /auth/test
  &yatt:abspath();        /auth/test.yatt

  &yatt:request_uri();    /myapp/auth/test?q=1
  &yatt:path_info();      /auth/test

=over 4

=item &yatt:script_name();

The mount point of the site, without trailing C</>
(C<< $env->{'yatt.script_name'} >> - normalized C<SCRIPT_NAME>;
handler artifacts of Apache Action mapping are trimmed).
The most basic building block for path abstraction.
Note: this usually equals to C<< &yatt:site_prefix(); >>
(explicit L</site_prefix> config wins if given).

=item &yatt:script_dir();

C<script_name> + C</>.

=item &yatt:script_uri();

Absolute url of the current page. Unlike raw C<SCRIPT_URI>,
this respects C<X-Forwarded-Proto> (GH-205).

=item &yatt:script_url();

Path-only version of C<script_uri>.

=item &yatt:dir_location(); &yatt:file_location(); &yatt:page_location();

Mount-prefix aware location of the current directory / page.
C<file_location> follows how the request spelled the file name
(with/without extension), while C<page_location> is always the
canonical (extension-less) form. Both omit the file name for
F<index.yatt> requests.
See L<YATT::Lite::WebMVC0::Connection/LOCATION INSPECTION METHODS>.

=item &yatt:abspath();

C<location> + C<file> (physical file name), without mount prefix.

=item &yatt:absrequest();

C<REQUEST_URI> minus C<script_name>, query string stripped.
Since C<REQUEST_URI> typically does not contain F<index.yatt>,
this is not suitable to get the physical file name.

=item &yatt:is_current_file(PATH); &yatt:is_current_page(PAGE);

Current page predicates, useful for navigation highlighting.

=item &yatt:path_info(); &yatt:request_uri(); &yatt:script_filename();

Raw C<PATH_INFO> / C<REQUEST_URI> / C<SCRIPT_FILENAME>.

=back

=head1 SEE ALSO

L<YATT::Lite::WebMVC0::Connection>,
L<YATT::Lite::WebMVC0::DirApp>,
L<YATT::Lite>

