Compare commits

...

4 commits

Author SHA1 Message Date
799554951b Code cleaning in example app 2023-02-13 02:43:31 +01:00
5691494f12 I18n: fix extracting messages from all PHP, JS and templates files 2023-02-13 02:36:40 +01:00
317cb30cb3 Tpl: Add stuff to have multiple templates directories with priority 2023-02-13 00:42:37 +01:00
4f47dc056d Tpl: Add stuff to handle static files
* Move example application in example sub-directory
* Widely use App::get() instead of Config::get()
2023-02-12 00:30:36 +01:00
1156 changed files with 2609 additions and 4690 deletions

1
.gitignore vendored
View file

@ -3,6 +3,7 @@
.*.swp
# Exclude composer installed libs
/vendor
/composer.lock
# Common UNIX user home directory files
/.bash*
/.vim*

View file

@ -21,12 +21,12 @@
"brenard/php-unidecode": "dev-master",
"smarty/smarty": "3.1.34",
"smarty-gettext/smarty-gettext": "^1.6",
"smarty-gettext/tsmarty2c": "^0.2.1",
"sepia/po-parser": "^6.0",
"sentry/sdk": "^3.3",
"ext-pdo": "^7.3",
"ext-json": "^7.3",
"ext-yaml": "^2.0"
"ext-yaml": "^2.0",
"league/mime-type-detection": "^1.11"
},
"require-dev": {
"phpstan/phpstan": "^1.9"

2866
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -13,12 +13,6 @@ upload_tmp_directory: ${tmp_root_directory}/uploading"
# Main pagetitle
main_pagetitle: "Eesyphp"
# Theme CSS file
included_css_files:
#- css/custom.css
included_js_files:
#- js/custom.js
# Debug Ajax request/response
debug_ajax: false
@ -81,12 +75,17 @@ sentry:
traces_sample_rate: 0.2
#
# Smarty template configuration
# Smarty templates configuration
#
template:
templates:
# Smarty directories
directory: "${root_directory_path}/templates"
cache_directory: "${tmp_root_directory}/templates_c"
# Theme CSS file
included_css_files:
#- css/custom.css
included_js_files:
#- js/custom.js
#
# Translations

View file

@ -1,7 +1,6 @@
<?php
use EesyPHP\App;
use EesyPHP\Config;
use EesyPHP\I18n;
use EesyPHP\SentrySpan;
@ -34,6 +33,11 @@ App::init(
'overwrite_config_files' => array(
"$root_dir_path/includes/config.local.yml",
),
'templates' => array(
'static_directories' => array(
"$root_dir_path/static"
),
),
),
$root_dir_path
);

View file

@ -1,6 +1,6 @@
<?php
use EesyPHP\Config;
use EesyPHP\App;
use EesyPHP\Db;
use EesyPHP\Hook;
use EesyPHP\Log;
@ -8,12 +8,12 @@ use EesyPHP\Log;
use Unidecode\Unidecode;
$db = new Db(
Config::get('db.dsn', null, 'string'),
Config::get('db.user', null, 'string'),
Config::get('db.password', null, 'string'),
Config::get('db.options', array(), 'array'),
Config::get('db.date_format', null, 'string'),
Config::get('db.datetime_format', null, 'string'),
App::get('db.dsn', null, 'string'),
App::get('db.user', null, 'string'),
App::get('db.password', null, 'string'),
App::get('db.options', array(), 'array'),
App::get('db.date_format', null, 'string'),
App::get('db.datetime_format', null, 'string'),
);
/*
@ -154,7 +154,7 @@ function search_items($params) {
global $db;
// Detect PgSQL backend
$is_pgsql = (strpos(Config::get('db.dsn', '', 'string'), "pgsql:") === 0);
$is_pgsql = (strpos(App::get('db.dsn', '', 'string'), "pgsql:") === 0);
$where = array();
if (isset($params['status']) && $params['status'] && $params['status'] != 'all')

View file

@ -1,6 +1,6 @@
<?php
use EesyPHP\Config;
use EesyPHP\App;
use EesyPHP\Date;
use EesyPHP\Hook;
use EesyPHP\Log;
@ -22,15 +22,6 @@ Tpl :: enable_security_mode(
array('range', 'implode', 'stripslashes')
);
// Defined some global template variables
Tpl :: assign('public_root_url', Config::get('public_root_url', '/', 'string'));
Tpl :: assign('main_pagetitle', Config::get('main_pagetitle', null, 'string'));
Tpl :: assign('session_key', $_SESSION['session_key']);
// Handle CSS & JS files included
Tpl :: add_css_file(Config::get('included_css_files', array(), 'array'));
Tpl :: add_js_file(Config::get('included_js_files', array(), 'array'));
function define_common_template_variables($event) {
global $status_list, $admin;
Tpl :: assign(
@ -41,7 +32,7 @@ function define_common_template_variables($event) {
Tpl :: assign('admin', isset($admin) && $admin);
Tpl :: assign(
'webstats_js_code',
Config::get('webstats_js_code', null, 'string'));
App::get('webstats_js_code', null, 'string'));
}
Hook :: register('before_displaying_template', 'define_common_template_variables');

View file

@ -10,11 +10,11 @@ use function EesyPHP\vardump;
if (php_sapi_name() == "cli")
return true;
function handle_homepage($request) {
Tpl :: display("homepage.tpl", _("Hello world !"));
}
Url :: add_url_handler('#^$#', 'handle_homepage');
/**
* Search page handler
* @param EesyPHP\UrlRequest $request
* @return void
*/
function handle_search($request) {
global $status_list;
@ -102,20 +102,21 @@ function handle_search($request) {
Tpl :: assign('nbs_by_page', $nbs_by_page);
Tpl :: assign('status_list', $status_list);
Tpl :: add_js_file(array(
Tpl :: add_js_file(
'lib/bootstrap4dialog/dist/js/bootstrap4dialog.min.js',
'js/myconfirm.js',
'js/search.js'
));
);
Tpl :: display("search.tpl", _("Search"));
}
Url :: add_url_handler('|^item/?$|', 'handle_search');
/*
* One item pages
/**
* Show one item page handler
* @param EesyPHP\UrlRequest $request
* @return void
*/
function handle_show($request) {
$item = get_item_from_url($request -> id);
if (!$item)
@ -124,10 +125,10 @@ function handle_show($request) {
Tpl :: assign('item', $item);
// Dialog
Tpl :: add_js_file(array(
Tpl :: add_js_file(
'lib/bootstrap4dialog/dist/js/bootstrap4dialog.min.js',
'js/myconfirm.js',
));
);
Tpl :: display(
"show.tpl", _("Element %s"),
@ -136,6 +137,11 @@ function handle_show($request) {
}
Url :: add_url_handler('|^item/(?P<id>[0-9]+)$|', 'handle_show');
/**
* Create one item page handler
* @param EesyPHP\UrlRequest $request
* @return void
*/
function handle_create($request) {
global $status_list;
@ -219,6 +225,11 @@ function handle_modify($request) {
}
Url :: add_url_handler('|^item/(?P<id>[0-9]+)/modify$|', 'handle_modify');
/**
* Archive one item page handler
* @param EesyPHP\UrlRequest $request
* @return void
*/
function handle_archive($request) {
$item = get_item_from_url($request -> id);
if(!is_array($item)) {
@ -241,6 +252,11 @@ function handle_archive($request) {
}
Url :: add_url_handler('|^item/(?P<id>[0-9]+)/archive$|', 'handle_archive');
/**
* Delete one item page handler
* @param EesyPHP\UrlRequest $request
* @return void
*/
function handle_delete($request) {
$item = get_item_from_url($request -> id);
if(!is_array($item)) {

View file

@ -0,0 +1,318 @@
#: Cli.php:34
#, php-format
msgid "The CLI command '%s' already exists."
msgstr ""
#: Cli.php:39
#, php-format
msgid "The CLI command '%s' handler is not callable !"
msgstr ""
#: Cli.php:71
#, php-format
msgid "Usage: %s [-h] [-qd] command\n"
msgstr ""
#: Cli.php:72
msgid " -h Show this message\n"
msgstr ""
#: Cli.php:73
msgid " -q / -d Quiet/Debug mode\n"
msgstr ""
#: Cli.php:74
msgid " --trace Trace mode (the most verbose)\n"
msgstr ""
#: Cli.php:75
msgid " command Command to run\n"
msgstr ""
#: Cli.php:77
msgid "Available commands:\n"
msgstr ""
#: Cli.php:125
msgid "Only one command could be executed !"
msgstr ""
#: Cli.php:153
#, php-format
msgid ""
"Invalid parameter \"%s\".\n"
"Note: Command's parameter/argument must be place after the command."
msgstr ""
#: Cli.php:178
#, php-format
msgid "An exception occured running command %s"
msgstr ""
#: Db.php:74
msgid "Unable to connect to the database."
msgstr ""
#: Email.php:141
#, php-format
msgid "</hr><p><small>Mail initialy intended for %s.</small></p>"
msgstr ""
#: Email.php:142
#, php-format
msgid ""
"\n"
"\n"
"\n"
"Mail initialy intended for %s."
msgstr ""
#: Email.php:178
#, php-format
msgid "<p><small>%s: %s</small></p>"
msgstr ""
#: Email.php:179
#, php-format
msgid ""
"\n"
"%s: %s"
msgstr ""
#: Tpl.php:339
msgid "No template specified."
msgstr ""
#: Tpl.php:370
msgid "An error occurred while displaying this page."
msgstr ""
#: Url.php:141
msgid "Bad request"
msgstr ""
#: Url.php:142
msgid "Invalid request."
msgstr ""
#: Url.php:145
msgid "Authentication required"
msgstr ""
#: Url.php:146
msgid "You have to be authenticated to access to this page."
msgstr ""
#: Url.php:149
msgid "Access denied"
msgstr ""
#: Url.php:150
msgid ""
"You do not have access to this application. If you think this is an error, "
"please contact support."
msgstr ""
#: Url.php:153
msgid "Whoops ! Page not found"
msgstr ""
#: Url.php:154
msgid "The requested page can not be found."
msgstr ""
#: Url.php:162
msgid "Error"
msgstr ""
#: Url.php:163
msgid "An unknown error occurred. If problem persist, please contact support."
msgstr ""
#: Url.php:226
msgid ""
"Unable to determine the requested page. If the problem persists, please "
"contact support."
msgstr ""
#: Url.php:376
msgid ""
"Unable to determine the requested page (loop detected). If the problem "
"persists, please contact support."
msgstr ""
#: Url.php:407
msgid "This request cannot be processed."
msgstr ""
#: Url.php:420
msgid ""
"Authentication required but force_authentication function is not defined."
msgstr ""
#: Url.php:429
msgid "This request could not be processed correctly."
msgstr ""
#: I18n.php:114 App.php:120
msgid "Hello world !"
msgstr ""
#: I18n.php:130
msgid "Extract messages that need to be translated"
msgstr ""
#: I18n.php:132
msgid "This command could be used to generate/update lang/messages.pot file."
msgstr ""
#: I18n.php:138
msgid "Update messages in translation PO lang files"
msgstr ""
#: I18n.php:140
msgid ""
"This command could be used to init/update PO files in lang/*/LC_MESSAGES "
"directories."
msgstr ""
#: I18n.php:147
msgid ""
"Compile messages from existing translation PO lang files to corresponding MO "
"files and JSON catalogs"
msgstr ""
#: I18n.php:152
msgid ""
"This command could be used to compile PO files in lang/*/LC_MESSAGES "
"directories to MO files and as JSON catalogs in public_html/translations."
msgstr ""
#: I18n.php:277
msgid "Fail to list EesyPHP PHP files."
msgstr ""
#: I18n.php:297
msgid "Fail to extract messages from EesyPHP PHP files using xgettext."
msgstr ""
#: I18n.php:309
msgid "Fail to list application PHP files."
msgstr ""
#: I18n.php:329
msgid "Fail to extract messages from PHP files using xgettext."
msgstr ""
#: I18n.php:342
#, php-format
msgid "Fail to list JS files in the directory of static files '%s'."
msgstr ""
#: I18n.php:364
#, php-format
msgid ""
"Fail to extract messages from JS files in the directory of static files '%s' "
"using xgettext."
msgstr ""
#: I18n.php:384
#, php-format
msgid ""
"Fail to extract messages from templates directory '%s' using tsmarty2c.php "
"script."
msgstr ""
#: I18n.php:420
msgid "Fail to merge messages using msgcat."
msgstr ""
#: I18n.php:434
#, php-format
msgid "Compendium file %s not found."
msgstr ""
#: I18n.php:441
#, php-format
msgid "POT file not found (%s). Please run extract_messages first."
msgstr ""
#: I18n.php:453 I18n.php:561
#, php-format
msgid "Lang directory '%s' found"
msgstr ""
#: I18n.php:459 I18n.php:567
#, php-format
msgid "LC_MESSAGES directory not found in lang '%s' directory, ignore it."
msgstr ""
#: I18n.php:474
#, php-format
msgid "Fail to init messages in %s PO file using msginit (%s)."
msgstr ""
#: I18n.php:492
#, php-format
msgid "Fail to update messages in %s PO file using msgmerge (%s)."
msgstr ""
#: I18n.php:498 I18n.php:575
#, php-format
msgid "PO file not found in lang '%s' directory, ignore it."
msgstr ""
#: I18n.php:505 I18n.php:615
#, php-format
msgid "Fail to open root lang directory (%s)."
msgstr ""
#: I18n.php:531
#, php-format
msgid "Lang alias symlink found: %s -> %s"
msgstr ""
#: I18n.php:538
#, php-format
msgid "JSON catalog symlink for %s -> %s created (%s)"
msgstr ""
#: I18n.php:542
#, php-format
msgid "Fail to create JSON catalog symlink for %s -> %s (%s)"
msgstr ""
#: I18n.php:548
#, php-format
msgid "JSON catalog symlink for %s -> %s already exist (%s)"
msgstr ""
#: I18n.php:553
#, php-format
msgid ""
"JSON catalog file for %s already exist, but it's not a symlink to %s (%s)"
msgstr ""
#: I18n.php:588
#, php-format
msgid "Fail to compile messages from %s PO file as MO file using msgfmt (%s)."
msgstr ""
#: I18n.php:598
#, php-format
msgid "Fail to open %s JSON catalog file in write mode (%s)."
msgstr ""
#: I18n.php:603
#, php-format
msgid "Fail to write %s JSON catalog in file (%s)."
msgstr ""
#: I18n.php:608
#, php-format
msgid "%s JSON catalog writed (%s)."
msgstr ""
#: App.php:122
msgid "Hello world!"
msgstr ""

Binary file not shown.

View file

@ -0,0 +1,7 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2023-02-13 02:32+0100\n"
"PO-Revision-Date: 2023-02-13 02:32+0100\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"

View file

@ -0,0 +1,44 @@
#: static/js/myconfirm.js:4 static/js/myconfirm.js:171
#: static/js/myconfirm.js:200
msgid "Confirmation"
msgstr ""
#: static/js/myconfirm.js:5
msgid "Do you confirm?"
msgstr ""
#: static/js/myconfirm.js:11 static/js/myconfirm.js:108
msgid "Cancel"
msgstr ""
#: static/js/myconfirm.js:17 static/js/myconfirm.js:114
msgid "Validate"
msgstr ""
#: static/js/myconfirm.js:44
msgid "Error"
msgstr ""
#: static/js/myconfirm.js:52
msgid "OK"
msgstr ""
#: static/js/myconfirm.js:91
msgid "Question"
msgstr ""
#: static/js/myconfirm.js:92
msgid "Please enter your answer below:"
msgstr ""
#: static/js/myconfirm.js:143
msgid "Please wait"
msgstr ""
#: static/js/myconfirm.js:144
msgid "Please wait while your request is being processed."
msgstr ""
#: static/js/myconfirm.js:172 static/js/myconfirm.js:201
msgid "Are you sure?"
msgstr ""

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,259 @@
#: includes/cli.php:23
#, php-format
msgid "Item #%s:\n"
msgstr ""
#: includes/cli.php:24
#, php-format
msgid "ID: %s"
msgstr ""
#: includes/cli.php:25
#, php-format
msgid "Name: '%s'"
msgstr ""
#: includes/cli.php:26
#, php-format
msgid "Date: %s"
msgstr ""
#: includes/cli.php:28
#, php-format
msgid "Description: %s"
msgstr ""
#: includes/cli.php:29
msgid "Not set"
msgstr ""
#: includes/cli.php:31
#, php-format
msgid "Status: %s"
msgstr ""
#: includes/cli.php:84
msgid "No item.\n"
msgstr ""
#: includes/cli.php:110
#, php-format
msgid "%d item(s)"
msgstr ""
#: includes/cli.php:116
msgid "List/search items"
msgstr ""
#: includes/cli.php:117
msgid "[patterns]"
msgstr ""
#: includes/cli.php:119
msgid "-o|--orderby Ordering list criterion. Possible values:"
msgstr ""
#: includes/cli.php:121
msgid "-r|--reverse Reverse order"
msgstr ""
#: includes/cli.php:122
msgid "-s|--status Filter on status. Possible values:"
msgstr ""
#: includes/cli.php:129
msgid "You must provide a valid ID."
msgstr ""
#: includes/cli.php:135 includes/cli.php:159
#, php-format
msgid "Item #%s not found."
msgstr ""
#: includes/cli.php:143
msgid "Show item"
msgstr ""
#: includes/cli.php:144
msgid "[ID]"
msgstr ""
#: includes/cli.php:149
msgid "You must provide item ID."
msgstr ""
#: includes/cli.php:153
msgid "Invalid item ID"
msgstr ""
#: includes/cli.php:164
msgid "Are you sure you want to delete this item? Type 'yes' to continue: "
msgstr ""
#: includes/cli.php:168
msgid "User cancel"
msgstr ""
#: includes/cli.php:174
#, php-format
msgid "An error occured deleting item #%d."
msgstr ""
#: includes/cli.php:181
msgid "Delete item"
msgstr ""
#: includes/cli.php:182
msgid "[item ID]"
msgstr ""
#: includes/cli.php:194
msgid "Export items (as CSV)"
msgstr ""
#: includes/cli.php:195
msgid "[output file path]"
msgstr ""
#: includes/cli.php:210
msgid "Restore items (from CSV)"
msgstr ""
#: includes/cli.php:211
msgid "[input file path]"
msgstr ""
#: includes/cli.php:278
msgid "Cron to handle item expiration"
msgstr ""
#: includes/cli.php:281
msgid "-j/--just-try Just-try mode : do not really removed expired item(s)"
msgstr ""
#: includes/cli.php:282
msgid "-m/--max-age Item expiration limit (in days, optional)"
msgstr ""
#: includes/url-helpers.php:9
msgid "Invalid element identifier."
msgstr ""
#: includes/url-helpers.php:13 includes/url-public.php:220
#: includes/url-public.php:242
#, php-format
msgid "Item #% s not found."
msgstr ""
#: includes/core.php:51
msgid "Pending"
msgstr ""
#: includes/core.php:52
msgid "Validated"
msgstr ""
#: includes/core.php:53
msgid "Refused"
msgstr ""
#: includes/core.php:54
msgid "Archived"
msgstr ""
#: includes/url-public.php:33
msgid "Any"
msgstr ""
#: includes/url-public.php:91
msgid ""
"An error occurred while listing the items. If the problem persists, please "
"contact support."
msgstr ""
#: includes/url-public.php:106
msgid "Search"
msgstr ""
#: includes/url-public.php:128
#, php-format
msgid "Element %s"
msgstr ""
#: includes/url-public.php:142
#, php-format
msgid "The element '% s' has been created."
msgstr ""
#: includes/url-public.php:146
msgid "An error occurred while saving this item."
msgstr ""
#: includes/url-public.php:153
msgid ""
"There are errors preventing this item from being saved. Please correct them "
"before attempting to add this item."
msgstr ""
#: includes/url-public.php:160
msgid "New"
msgstr ""
#: includes/url-public.php:170
msgid "You cannot edit this item."
msgstr ""
#: includes/url-public.php:183
#, php-format
msgid "You have not made any changes to element '% s'."
msgstr ""
#: includes/url-public.php:187
#, php-format
msgid "The element '% s' has been updated successfully."
msgstr ""
#: includes/url-public.php:191
msgid "An error occurred while updating this item."
msgstr ""
#: includes/url-public.php:199
msgid ""
"There are errors preventing this item from being saved. Please correct them "
"before attempting to save your changes."
msgstr ""
#: includes/url-public.php:211
#, php-format
msgid "Element %s: Modification"
msgstr ""
#: includes/url-public.php:224
msgid "This item is already archived."
msgstr ""
#: includes/url-public.php:227
msgid "You cannot archive this item."
msgstr ""
#: includes/url-public.php:230
#, php-format
msgid "The element '% s' has been archived successfully."
msgstr ""
#: includes/url-public.php:233
msgid "An error occurred while archiving this item."
msgstr ""
#: includes/url-public.php:245
msgid "You cannot delete this item."
msgstr ""
#: includes/url-public.php:248
#, php-format
msgid "The element '% s' has been deleted successfully."
msgstr ""
#: includes/url-public.php:251
msgid "An error occurred while deleting this item."
msgstr ""

View file

@ -0,0 +1,110 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8\n"
#: templates/show.tpl:5 templates/search.tpl:36 templates/form.tpl:7
msgid "Name"
msgstr ""
#: templates/show.tpl:14
msgid "Creation date"
msgstr ""
#: templates/show.tpl:23 templates/search.tpl:11 templates/form.tpl:15
msgid "Status"
msgstr ""
#: templates/show.tpl:32 templates/form.tpl:25
msgid "Description"
msgstr ""
#: templates/show.tpl:35
msgid "Unspecified."
msgstr ""
#: templates/show.tpl:42 templates/form.tpl:33
msgid "Back"
msgstr ""
#: templates/show.tpl:43 templates/search.tpl:51
msgid "Modify"
msgstr ""
#: templates/show.tpl:44 templates/search.tpl:52
msgid "Are you sure you want to archive this item?"
msgstr ""
#: templates/show.tpl:44 templates/search.tpl:52
msgid "Archive"
msgstr ""
#: templates/show.tpl:45 templates/search.tpl:53
msgid "Are you sure you want to delete this item?"
msgstr ""
#: templates/show.tpl:45 templates/search.tpl:53
msgid "Delete"
msgstr ""
#: templates/search.tpl:8
msgid "Pattern"
msgstr ""
#: templates/search.tpl:16
msgid "Nb by page"
msgstr ""
#: templates/search.tpl:22
msgid "Search"
msgstr ""
#: templates/search.tpl:23
msgid "Reset"
msgstr ""
#: templates/search.tpl:28 templates/form.tpl:38
msgid "Add"
msgstr ""
#: templates/search.tpl:35
msgid "Date"
msgstr ""
#: templates/search.tpl:37
msgid "Actions"
msgstr ""
#: templates/search.tpl:47 templates/search.tpl:50
msgid "View"
msgstr ""
#: templates/search.tpl:59
msgid "No item found."
msgstr ""
#: templates/search.tpl:68
msgid "%3 element"
msgid_plural "Elements %1 to %2 on %3"
msgstr[0] ""
msgstr[1] ""
#: templates/homepage.tpl:5
msgid "Hello, world!"
msgstr ""
#: templates/homepage.tpl:6
msgid ""
"This is a simple app to show the different possibilities and basic "
"functionality."
msgstr ""
#: templates/homepage.tpl:8
msgid "This app contains some demo pages:"
msgstr ""
#: templates/homepage.tpl:9
msgid "Search page"
msgstr ""
#: templates/form.tpl:36
msgid "Save"
msgstr ""

View file

@ -0,0 +1,28 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8\n"
#: templates/fatal_error.tpl:5
msgid ""
"A fatal error has occurred and it is preventing this application from "
"working properly. Please try again later or contact support."
msgstr ""
#: templates/fatal_error.tpl:7
msgid "Error: %1"
msgstr ""
#: templates/fatal_error.tpl:9
msgid "Back"
msgstr ""
#: templates/homepage.tpl:5
msgid "Hello, world!"
msgstr ""
#: templates/homepage.tpl:6
msgid ""
"This is the default page of a new app using EesyPHP framework. Register your "
"own templates directory and create a <em>homepage.tpl</em> file to overwrite "
"it. You could also overwrite the URL handler for the root of the web "
"application."
msgstr ""

View file

@ -5,7 +5,6 @@ include 'url-public.php';
use EesyPHP\Url;
$default_url='';
Url :: handle_request();
Url :: handle_request('');
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab

View file

@ -1,4 +1,4 @@
{extends file='empty.tpl'}
{extends file='Tpl:empty.tpl'}
{block name="content"}
<form enctype="multipart/form-data" method="post" class="container" id="item-form">
<input type='hidden' name='session_key' value='{$session_key|escape:'quotes'}' />

View file

@ -0,0 +1,11 @@
{extends file='Tpl:empty.tpl'}
{block name="pagetitle"}{/block}
{block name="content"}
<div class="jumbotron">
<h1 class="display-4">{t}Hello, world!{/t}</h1>
<p class="lead">{t}This is a simple app to show the different possibilities and basic functionality.{/t}</p>
<hr class="my-4">
<p>{t}This app contains some demo pages:{/t}</p>
<a class="btn btn-primary btn-lg" href="item" role="button">{t}Search page{/t}</a>
</div>
{/block}

View file

@ -1,4 +1,4 @@
{extends file='empty.tpl'}
{extends file='Tpl:empty.tpl'}
{block name="content"}
<div class="row">
<div class="col-md-auto">

View file

@ -1,4 +1,4 @@
{extends file='empty.tpl'}
{extends file='Tpl:empty.tpl'}
{block name="content"}
<div class="container">
<div class="form-group row">

1
example/vendor Symbolic link
View file

@ -0,0 +1 @@
../vendor

View file

@ -1,7 +0,0 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2022-04-25 18:40+0200\n"
"PO-Revision-Date: 2022-04-25 18:40+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"

View file

@ -1,735 +0,0 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2022-04-25 18:40+0200\n"
"PO-Revision-Date: 2022-04-25 18:40+0200\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: /home/brenard/dev/eesyphp/includes/url-helpers.php:5
msgid "Invalid element identifier."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-helpers.php:9
#: /home/brenard/dev/eesyphp/includes/url-public.php:222
#: /home/brenard/dev/eesyphp/includes/url-public.php:246
#, php-format
msgid "Item #% s not found."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/smarty.php:61
msgid "Smarty version not supported."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/smarty.php:148
msgid "No template specified."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/smarty.php:166
msgid "An error occurred while viewing this page."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:7
#: /home/brenard/dev/eesyphp/includes/translation.php:140
msgid "Hello world !"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:31
msgid "Any"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:89
msgid ""
"An error occurred while listing the items. If the problem persists, please "
"contact support."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:104
msgid "Search"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:128
#, php-format
msgid "Element %s"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:142
#, php-format
msgid "The element '% s' has been created."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:146
msgid "An error occurred while saving this item."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:153
msgid ""
"There are errors preventing this item from being saved. Please correct them "
"before attempting to add this item."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:160
msgid "New"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:170
msgid "You cannot edit this item."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:183
#, php-format
msgid "You have not made any changes to element '% s'."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:187
#, php-format
msgid "The element '% s' has been updated successfully."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:191
msgid "An error occurred while updating this item."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:199
msgid ""
"There are errors preventing this item from being saved. Please correct them "
"before attempting to save your changes."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:211
#, php-format
msgid "Element %s: Modification"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:226
msgid "This item is already archived."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:229
msgid "You cannot archive this item."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:232
#, php-format
msgid "The element '% s' has been archived successfully."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:235
msgid "An error occurred while archiving this item."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:249
msgid "You cannot delete this item."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:252
#, php-format
msgid "The element '% s' has been deleted successfully."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url-public.php:255
msgid "An error occurred while deleting this item."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/db.php:31
msgid "Unable to connect to the database."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/core.php:44
msgid "Pending"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/core.php:45
msgid "Validated"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/core.php:46
msgid "Refused"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/core.php:47
msgid "Archived"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:59
msgid "Fail to list PHP files."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:76
msgid "Fail to extract messages from PHP files using xgettext."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:86
msgid "Fail to list JS files."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:103
msgid "Fail to extract messages from JS files using xgettext."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:116
msgid ""
"Fail to extract messages from template files using tsmarty2c.php script."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:142
msgid "Fail to merge messages using msgcat."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:147
msgid "Extract messages that need to be translated"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:149
msgid "This command could be used to generate/update lang/messages.pot file."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:165
#, php-format
msgid "Compendium file %s not found."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:172
#, php-format
msgid "POT file not found (%s). Please run extract_messages first."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:184
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:301
#, php-format
msgid "Lang directory '%s' found"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:190
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:307
#, php-format
msgid "LC_MESSAGES directory not found in lang '%s' directory, ignore it."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:205
#, php-format
msgid "Fail to init messages in %s PO file using msginit (%s)."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:223
#, php-format
msgid "Fail to update messages in %s PO file using msgmerge (%s)."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:229
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:315
#, php-format
msgid "PO file not found in lang '%s' directory, ignore it."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:236
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:356
#, php-format
msgid "Fail to open root lang directory (%s)."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:241
msgid "Update messages in translation PO lang files"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:243
msgid ""
"This command could be used to init/update PO files in lang/*/LC_MESSAGES "
"directories."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:270
#, php-format
msgid "Lang alias symlink found: %s -> %s"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:277
#, php-format
msgid "JSON catalog symlink for %s -> %s created (%s)"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:281
#, php-format
msgid "Fail to create JSON catalog symlink for %s -> %s (%s)"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:287
#, php-format
msgid "JSON catalog symlink for %s -> %s already exist (%s)"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:293
#, php-format
msgid ""
"JSON catalog file for %s already exist, but it's not a symlink to %s (%s)"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:329
#, php-format
msgid "Fail to compile messages from %s PO file as MO file using msgfmt (%s)."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:339
#, php-format
msgid "Fail to open %s JSON catalog file in write mode (%s)."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:344
#, php-format
msgid "Fail to write %s JSON catalog in file (%s)."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:349
#, php-format
msgid "%s JSON catalog writed (%s)."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:362
msgid ""
"Compile messages from existing translation PO lang files to corresponding MO "
"files and JSON catalogs"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/translation-cli.php:367
msgid ""
"This command could be used to compile PO files in lang/*/LC_MESSAGES "
"directories to MO files and as JSON catalogs in public_html/translations."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/mail.php:14
#, php-format
msgid ""
"\n"
"\n"
"\n"
"Mail initialy intended for %s."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:98
msgid "Bad request"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:99
msgid "Invalid request."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:102
msgid "Authentication required"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:103
msgid "You have to be authenticated to access to this page."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:106
msgid "Access denied"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:107
msgid ""
"You do not have access to this application. If you think this is an error, "
"please contact support."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:110
msgid "Whoops ! Page not found"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:111
msgid "The requested page can not be found."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:119
msgid "Error"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:120
msgid "An unknown error occurred. If problem persist, please contact support."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:165
msgid ""
"Unable to determine the requested page. If the problem persists, please "
"contact support."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:318
msgid ""
"Unable to determine the requested page (loop detected). If the problem "
"persists, please contact support."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:347
msgid "This request cannot be processed."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:360
msgid ""
"Authentication required but force_authentication function is not defined."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/url.php:368
msgid "This request could not be processed correctly."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:8
#, php-format
msgid "The CLI command '%s' already exists."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:13
#, php-format
msgid "The CLI command '%s' handler is not callable !"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:54
#, php-format
msgid "Usage: %s [-h] [-qd] command\n"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:55
msgid " -h Show this message\n"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:56
msgid " -q / -d Quiet/Debug mode\n"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:57
msgid " --trace Trace mode (the most verbose)\n"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:58
msgid " command Command to run\n"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:60
msgid "Available commands:\n"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:102
msgid "Only one command could be executed !"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:127
#, php-format
msgid ""
"Invalid parameter \"%s\".\n"
"Note: Command's parameter/argument must be place after the command."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:149
#, php-format
msgid "An exception occured running command %s"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:155
#, php-format
msgid "Item #%s:\n"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:156
#, php-format
msgid "ID: %s"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:157
#, php-format
msgid "Name: '%s'"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:158
#, php-format
msgid "Date: %s"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:160
#, php-format
msgid "Description: %s"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:161
msgid "Not set"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:163
#, php-format
msgid "Status: %s"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:216
msgid "No item.\n"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:242
#, php-format
msgid "%d item(s)"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:248
msgid "List/search items"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:249
msgid "[patterns]"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:251
msgid "-o|--orderby Ordering list criterion. Possible values:"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:253
msgid "-r|--reverse Reverse order"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:254
msgid "-s|--status Filter on status. Possible values:"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:261
msgid "You must provide a valid ID."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:267
#: /home/brenard/dev/eesyphp/includes/cli.php:291
#, php-format
msgid "Item #%s not found."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:275
msgid "Show item"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:276
msgid "[ID]"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:281
msgid "You must provide item ID."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:285
msgid "Invalid item ID"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:296
msgid "Are you sure you want to delete this item? Type 'yes' to continue: "
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:300
msgid "User cancel"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:306
#, php-format
msgid "An error occured deleting item #%d."
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:313
msgid "Delete item"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:314
msgid "[item ID]"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:326
msgid "Export items (as CSV)"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:327
msgid "[output file path]"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:342
msgid "Restore items (from CSV)"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:343
msgid "[input file path]"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:412
msgid "Cron to handle item expiration"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:415
msgid "-j/--just-try Just-try mode : do not really removed expired item(s)"
msgstr ""
#: /home/brenard/dev/eesyphp/includes/cli.php:416
msgid "-m/--max-age Item expiration limit (in days, optional)"
msgstr ""
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:4
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:171
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:200
msgid "Confirmation"
msgstr ""
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:5
msgid "Do you confirm?"
msgstr ""
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:11
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:108
msgid "Cancel"
msgstr ""
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:17
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:114
msgid "Validate"
msgstr ""
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:52
msgid "OK"
msgstr ""
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:91
msgid "Question"
msgstr ""
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:92
msgid "Please enter your answer below:"
msgstr ""
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:143
msgid "Please wait"
msgstr ""
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:144
msgid "Please wait while your request is being processed."
msgstr ""
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:172
#: /home/brenard/dev/eesyphp/public_html/js/myconfirm.js:201
msgid "Are you sure?"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/form.tpl:7
#: /home/brenard/dev/eesyphp/templates/search.tpl:36
#: /home/brenard/dev/eesyphp/templates/show.tpl:5
msgid "Name"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/form.tpl:15
#: /home/brenard/dev/eesyphp/templates/search.tpl:11
#: /home/brenard/dev/eesyphp/templates/show.tpl:23
msgid "Status"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/form.tpl:25
#: /home/brenard/dev/eesyphp/templates/show.tpl:32
msgid "Description"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/form.tpl:33
#: /home/brenard/dev/eesyphp/templates/fatal_error.tpl:9
#: /home/brenard/dev/eesyphp/templates/show.tpl:42
msgid "Back"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/form.tpl:36
msgid "Save"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/form.tpl:38
#: /home/brenard/dev/eesyphp/templates/search.tpl:28
msgid "Add"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/fatal_error.tpl:5
msgid ""
"A fatal error has occurred and it is preventing this application from "
"working properly. Please try again later or contact support."
msgstr ""
#: /home/brenard/dev/eesyphp/templates/fatal_error.tpl:7
msgid "Error: %1"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/search.tpl:8
msgid "Pattern"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/search.tpl:16
msgid "Nb by page"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/search.tpl:23
msgid "Reset"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/search.tpl:35
msgid "Date"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/search.tpl:37
msgid "Actions"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/search.tpl:47
#: /home/brenard/dev/eesyphp/templates/search.tpl:50
msgid "View"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/search.tpl:51
#: /home/brenard/dev/eesyphp/templates/show.tpl:43
msgid "Modify"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/search.tpl:52
#: /home/brenard/dev/eesyphp/templates/show.tpl:44
msgid "Are you sure you want to archive this item?"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/search.tpl:52
#: /home/brenard/dev/eesyphp/templates/show.tpl:44
msgid "Archive"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/search.tpl:53
#: /home/brenard/dev/eesyphp/templates/show.tpl:45
msgid "Are you sure you want to delete this item?"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/search.tpl:53
#: /home/brenard/dev/eesyphp/templates/show.tpl:45
msgid "Delete"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/search.tpl:59
msgid "No item found."
msgstr ""
#: /home/brenard/dev/eesyphp/templates/search.tpl:68
msgid "%3 element"
msgid_plural "Elements %1 to %2 on %3"
msgstr[0] ""
msgstr[1] ""
#: /home/brenard/dev/eesyphp/templates/show.tpl:14
msgid "Creation date"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/show.tpl:35
msgid "Unspecified."
msgstr ""
#: /home/brenard/dev/eesyphp/templates/homepage.tpl:5
msgid "Hello, world!"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/homepage.tpl:6
msgid ""
"This is a simple app to show the different possibilities and basic "
"functionality."
msgstr ""
#: /home/brenard/dev/eesyphp/templates/homepage.tpl:8
msgid "This app contains some demo pages:"
msgstr ""
#: /home/brenard/dev/eesyphp/templates/homepage.tpl:9
msgid "Search page"
msgstr ""

View file

@ -2,11 +2,13 @@ parameters:
level: 5
paths:
- src
- includes
- public_html
- bin/eesyphp
- example/includes
- example/public_html
excludePaths:
- includes/config.local.php
- example/includes/config.local.php
- example/data/tmp/templates_c
universalObjectCratesClasses:
- EesyPHP\UrlRequest
ignoreErrors:
-
message: "#Instantiated class Mail_mime not found\\.#"
@ -23,5 +25,5 @@ parameters:
-
message: "#Variable \\$status_list might not be defined\\.#"
paths:
- includes/cli.php
- example/includes/cli.php

View file

@ -40,35 +40,45 @@ class App {
}
// Load overwrite configuration file
foreach (self :: get_option('overwrite_config_files', array(), 'array') as $file) {
foreach (self :: get('overwrite_config_files', array(), 'array') as $file) {
$file = Config::replace_variables($file);
if (is_file($file)) Config::load($file, true);
}
if (self :: get_option('sentry.enabled', true, 'bool'))
if (self :: get('sentry.enabled', true, 'bool'))
SentryIntegration :: init();
$sentry_transaction = new SentryTransaction();
$sentry_span = new SentrySpan('app.init', 'Application initialization');
// Define upload_tmp_dir
if (is_string(Config::get('upload_tmp_directory')))
ini_set('upload_tmp_dir', Config::get('upload_tmp_directory'));
if (is_string(self::get('upload_tmp_directory')))
ini_set('upload_tmp_dir', self::get('upload_tmp_directory'));
if (self :: get_option('log.enabled', true, 'bool'))
if (self :: get('log.enabled', true, 'bool'))
Log::init();
if (self :: get_option('session.enabled', true, 'bool'))
if (self :: get('session.enabled', true, 'bool'))
Session::init();
if (self :: get_option('template.enabled', true, 'bool'))
if (self :: get('templates.enabled', true, 'bool'))
Tpl :: init();
if (self :: get_option('url.enabled', true, 'bool'))
if (self :: get('url.enabled', true, 'bool')) {
Url::init();
if (self :: get_option('mail.enabled', true, 'bool'))
Url :: add_url_handler('#^$#', array('EesyPHP\\App', 'handle_homepage'));
}
if (self :: get('mail.enabled', true, 'bool'))
Email :: init();
if (self :: get_option('i18n.enabled', true, 'bool'))
if (self :: get('i18n.enabled', true, 'bool'))
I18n::init();
$sentry_span->finish();
}
/**
* Check if the application is initialized
* @return bool
*/
public static function initialized() {
return !is_null(self :: $root_directory_path);
}
/**
* Get a specific option value
*
@ -82,7 +92,7 @@ class App {
* is a string, split the value by comma (optional, default: true)
* @return mixed The configuration variable value
**/
public static function get_option($key, $default=null, $cast=null, $split=true) {
public static function get($key, $default=null, $cast=null, $split=true) {
return Config::get(
$key,
Config::loaded()?Config::get($key, $default, $cast, $split):$default,
@ -100,4 +110,16 @@ class App {
return self :: $root_directory_path?self :: $root_directory_path:'.';
}
/**
* Default homepage handler
* @param UrlRequest $request
* @return void
*/
public static function handle_homepage($request) {
if (Tpl::initialized())
Tpl :: display("homepage.tpl", _("Hello world !"));
else
echo "<h1>"._("Hello world!")."</h1>";
}
}

View file

@ -68,31 +68,31 @@ class Email {
public static function init($sender=null, $send_method=null, $send_params=null, $catch_all=null,
$headers=null, $php_mail_path=null, $php_mail_mime_path=null) {
if (is_null($sender))
$sender = Config::get('email.sender', null, 'string');
$sender = App::get('email.sender', null, 'string');
if ($sender) self :: $sender = $sender;
if (is_null($send_method))
$send_method = Config::get('email.send_method', null, 'string');
$send_method = App::get('email.send_method', null, 'string');
if ($send_method) self :: $send_method = $send_method;
if (is_null($send_params))
$send_params = Config::get('email.send_params', null, 'array');
$send_params = App::get('email.send_params', null, 'array');
if ($send_params) self :: $send_params = $send_params;
if (is_null($catch_all))
$catch_all = Config::get('email.catch_all');
$catch_all = App::get('email.catch_all');
if ($catch_all) self :: $catch_all = $catch_all;
if (is_null($headers))
$headers = Config::get('email.headers', null, 'array');
$headers = App::get('email.headers', null, 'array');
if ($headers) self :: $headers = $headers;
if (is_null($php_mail_path))
$php_mail_path = Config::get('email.php_mail_path', null, 'string');
$php_mail_path = App::get('email.php_mail_path', null, 'string');
if ($php_mail_path) self :: $php_mail_path = $php_mail_path;
if (is_null($php_mail_mime_path))
$php_mail_mime_path = Config::get('email.php_mail_mime_path', null, 'string');
$php_mail_mime_path = App::get('email.php_mail_mime_path', null, 'string');
if ($php_mail_mime_path) self :: $php_mail_mime_path = $php_mail_mime_path;
}

View file

@ -36,13 +36,13 @@ class I18n {
*/
public static function init($root_path=null, $default_locale=null) {
if (is_null($root_path))
self :: $root_path = Config::get(
self :: $root_path = App::get(
'i18n.root_directory', '${root_directory_path}/locales', 'string');
if (!is_null($root_path))
self :: $root_path = $root_path;
if (is_null($default_locale))
self :: $default_locale = Config::get('i18n.default_locale', null, 'string');
self :: $default_locale = App::get('i18n.default_locale', null, 'string');
if (!is_null($default_locale))
self :: $default_locale = $default_locale;
@ -68,7 +68,10 @@ class I18n {
else {
$lang = Locale::lookup(
self :: get_available_langs(),
Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']),
Locale::acceptFromHttp(
isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])?
$_SERVER['HTTP_ACCEPT_LANGUAGE']:null
),
true,
Locale::getPrimaryLanguage(self :: $default_locale)
);
@ -111,13 +114,13 @@ class I18n {
Log :: trace("Test: "._('Hello world !'));
// JS translation file
$js_translation_file = "translations/$lang.js";
if (
php_sapi_name() != "cli"
&& is_file(App :: root_directory_path()."/public_html/$js_translation_file")
&& Tpl :: initialized()
) {
Tpl :: add_js_file(array("lib/babel.js", "js/translation.js", $js_translation_file));
Tpl :: register_static_directory(self :: $root_path, null, 'locales/');
Tpl :: add_js_file("lib/babel.js", "js/translation.js");
Tpl :: add_js_file("locales/", "$lang.js");
}
if (php_sapi_name() == 'cli') {
@ -263,73 +266,131 @@ class I18n {
// Store list of generated POT files
$pot_files = array();
// List PHP files to parse
$php_files = run_external_command(
array('find', escapeshellarg(App :: root_directory_path()), '-name', "'*.php'"),
null, // no STDIN data
false // do not escape command args (already done)
// List EesyPHP PHP files to parse
$eesyphp_php_files = run_external_command(
array('find', '-name', "'*.php'"),
null, // no STDIN data
false, // do not escape command args (already done)
__DIR__ // Run from EesyPHP src directory
);
if (!is_array($php_files) || $php_files[0] != 0) {
Log :: fatal(_("Fail to list PHP files."));
if (!is_array($eesyphp_php_files) || $eesyphp_php_files[0] != 0) {
Log :: fatal(_("Fail to list EesyPHP PHP files."));
}
// Extract messages from PHP files using xgettext
// Extract messages from EesyPHP PHP files using xgettext
$pot_file = self :: $root_path."/eesyphp-messages.pot";
$result = run_external_command(
array(
"xgettext",
"--from-code utf-8",
"--language=PHP",
"-o", self :: $root_path."/php-messages.pot", // Output
"--omit-header", // No POT header
"--keyword=___", // Handle custom ___() translation function
"--files=-" // Read files to parse from STDIN
"-o", $pot_file, // Output
"--omit-header", // No POT header
"--keyword=___", // Handle custom ___() translation function
"--files=-" // Read files to parse from STDIN
),
$php_files[1] // Pass PHP files list via STDIN
$eesyphp_php_files[1], // Pass PHP files list via STDIN
true, // Escape parameters
__DIR__ // Run from EesyPHP src directory
);
if (!is_array($result) || $result[0] != 0)
Log :: fatal(_("Fail to extract messages from EesyPHP PHP files using xgettext."));
if (is_file($pot_file))
$pot_files[] = $pot_file;
// List application PHP files to parse
$php_files = run_external_command(
array('find', '-name', "'*.php'"),
null, // no STDIN data
false, // do not escape command args (already done)
App :: root_directory_path() // Run from Application root directory
);
if (!is_array($php_files) || $php_files[0] != 0) {
Log :: fatal(_("Fail to list application PHP files."));
}
// Extract messages from PHP files using xgettext
$pot_file = self :: $root_path."/php-messages.pot";
$result = run_external_command(
array(
"xgettext",
"--from-code utf-8",
"--language=PHP",
"-o", $pot_file, // Output
"--omit-header", // No POT header
"--keyword=___", // Handle custom ___() translation function
"--files=-" // Read files to parse from STDIN
),
$php_files[1], // Pass PHP files list via STDIN
true, // Escape parameters
App :: root_directory_path() // Run from EesyPHP src directory
);
if (!is_array($result) || $result[0] != 0)
Log :: fatal(_("Fail to extract messages from PHP files using xgettext."));
$pot_files[] = self :: $root_path."/php-messages.pot";
// List JS files to parse
$js_files = run_external_command(
array('find', escapeshellarg(App :: root_directory_path()."/public_html/js"), '-name', "'*.js'"),
null, // no STDIN data
false // do not escape command args (already done)
);
if (!is_array($js_files) || $js_files[0] != 0) {
Log :: fatal(_("Fail to list JS files."));
}
// Extract messages from JS files using xgettext
$result = run_external_command(
array(
"xgettext",
"--from-code utf-8",
"--language=JavaScript",
"-o", self :: $root_path."/js-messages.pot", // Output
"--omit-header", // No POT header
"--keyword=___", // Handle custom ___() translation function
"--files=-" // Read files to parse from STDIN
),
$js_files[1] // Pass JS files list via STDIN
);
if (!is_array($result) || $result[0] != 0)
Log :: fatal(_("Fail to extract messages from JS files using xgettext."));
$pot_files[] = self :: $root_path."/js-messages.pot";
if (Tpl :: initialized()) {
// Extract messages from templates files using tsmarty2c.php
// Extract messages from JS files using xgettext in each registered static directories
foreach(Tpl::static_directories() as $idx => $static_directory) {
// List JS files to parse
$result = run_external_command(
array (
App :: root_directory_path()."/vendor/bin/tsmarty2c.php",
"-o", self :: $root_path."/templates-messages.pot",
Tpl :: templates_directory(),
)
array('find', escapeshellarg(basename($static_directory)), '-name', "'*.js'"),
null, // no STDIN data
false, // do not escape command args (already done)
dirname($static_directory) // Run from parent directory
);
if (!is_array($result) || $result[0] != 0) {
Log :: fatal(_("Fail to list JS files in the directory of static files '%s'."), $static_directory);
return;
}
// Extract messages from JS files using xgettext
$pot_file = self :: $root_path."/js-$idx-messages.pot";
$result = run_external_command(
array(
"xgettext",
"--from-code utf-8",
"--language=JavaScript",
"-o", $pot_file, // Output
"--omit-header", // No POT header
"--keyword=___", // Handle custom ___() translation function
"--files=-" // Read files to parse from STDIN
),
$result[1], // Pass JS files list via STDIN
true, // Escape arguments
dirname($static_directory) // Run from parent directory
);
if (!is_array($result) || $result[0] != 0)
Log :: fatal(
_("Fail to extract messages from template files using tsmarty2c.php script."));
$pot_files[] = self :: $root_path."/templates-messages.pot";
_("Fail to extract messages from JS files in the directory of static files '%s' using xgettext."),
$static_directory);
if (is_file($pot_file))
$pot_files[] = $pot_file;
}
if (Tpl :: initialized()) {
foreach (Tpl :: templates_directories() as $idx => $templates_directory) {
// Extract messages from templates files using tsmarty2c.php
$result = run_external_command(
array(
App :: root_directory_path()."/vendor/smarty-gettext/smarty-gettext/tsmarty2c.php",
basename($templates_directory),
),
null, // Pass nothing on STDIN
true, // Escape arguments
dirname($templates_directory) // Run from parent directory
);
if (!is_array($result) || $result[0] != 0)
Log :: fatal(
_("Fail to extract messages from templates directory '%s' using tsmarty2c.php script."),
$templates_directory
);
if (!$result[1]) continue;
$pot_file = self :: $root_path."/templates-$idx-messages.pot";
$fd = fopen($pot_file, 'w');
fwrite($fd, $result[1]);
fclose($fd);
$pot_files[] = $pot_file;
}
}
$fd = fopen(self :: $root_path."/headers.pot", 'w');

View file

@ -72,19 +72,19 @@ class Log {
if ($filepath)
self :: $filepath = $filepath;
elseif (php_sapi_name() == 'cli')
self :: $filepath = Config::get(
'log.cli_logfile_path', Config::get('log.cli_file_path'));
self :: $filepath = App::get(
'log.cli_logfile_path', App::get('log.cli_file_path'));
else
self :: $filepath = Config::get('log.file_path');
self :: $filepath = App::get('log.file_path');
// Set log level
self :: set_level($level?$level:Config::get('log.level'));
self :: set_level($level?$level:App::get('log.level'));
// Log PHP errors
if (!is_null($php_errors_levels)) {
self :: $php_errors_levels = $php_errors_levels;
}
elseif ($levels = Config::get('log.php_errors_levels', array(), 'array')) {
elseif ($levels = App::get('log.php_errors_levels', array(), 'array')) {
$code = 'self :: $php_errors_levels = ';
while($level = array_shift($levels)) {
if (!is_string($level)) continue;

View file

@ -38,11 +38,11 @@ class SentryIntegration {
public static function init($dsn=null, $traces_sample_rate=null,
$php_error_types=null) {
\Sentry\init([
'dsn' => $dsn?$dsn:Config::get('sentry.dsn'),
'dsn' => $dsn?$dsn:App::get('sentry.dsn'),
'traces_sample_rate' => (
$traces_sample_rate?
$traces_sample_rate:
Config::get('sentry.traces_sample_rate', 0.2, 'float')
App::get('sentry.traces_sample_rate', 0.2, 'float')
),
]);
@ -57,7 +57,7 @@ class SentryIntegration {
});
if (!is_array($php_error_types))
$php_error_types = Config::get(
$php_error_types = App::get(
'sentry.php_error_types', self :: $php_error_types, 'array'
);
self :: $php_error_types = array();

View file

@ -27,7 +27,7 @@ class Session {
// Define session max duration
if (is_null($max_duration))
$max_duration = Config::get('session.max_duration', null, 'int');
$max_duration = App::get('session.max_duration', null, 'int');
if (is_int($max_duration))
self :: $max_duration = $max_duration;
@ -44,7 +44,7 @@ class Session {
// Handle session timeout
if (is_null($timeout))
$timeout = Config::get('session.timeout', null, 'int');
$timeout = App::get('session.timeout', null, 'int');
if (is_int($timeout) && $timeout) {
if (!isset($_SESSION['session_last_access'])) {
Log :: debug('Set initial session last access');

View file

@ -5,6 +5,7 @@ namespace EesyPHP;
use Exception;
use Smarty;
use Smarty_Security;
use League\MimeTypeDetection\ExtensionMimeTypeDetector;
class Tpl {
@ -21,10 +22,10 @@ class Tpl {
public static $smarty_security_policy = null;
/**
* Smarty templates directory path
* @var string
* Smarty templates directories path with their priority
* @var array<string,int>
*/
public static string $templates_dir;
public static array $templates_directories = array();
/**
* Smarty cache templates directory path
@ -38,6 +39,12 @@ class Tpl {
*/
public static bool $_debug_ajax;
/**
* Static directories path with their priority
* @var array<string,array>
*/
private static array $static_directories = array();
/**
* CSS files to load in next displayed page
* @var array<string>
@ -50,42 +57,110 @@ class Tpl {
*/
private static array $js_files = array();
/**
* MIME type detector object
* @var null|string
*/
private static $static_root_url;
/**
* MIME type detector object
* @var ExtensionMimeTypeDetector|null
*/
private static $mime_type_detector = null;
/**
* Initialization
* @param string $templates_dir Smarty templates directory path
* (optional, default: from template.directory config key)
* (optional, default: from templates.directory config key)
* @param string $templates_c_dir Smarty cache templates directory path
* (optional, default: from template.cache_directory config key)
* (optional, default: from templates.cache_directory config key)
* @param bool $debug_ajax Enable/disable AJAX returned data debugging in logs
* (optional, default: from template.debug_ajax or debug_ajax config keys if set,
* (optional, default: from templates.debug_ajax or debug_ajax config keys if set,
* false otherwise)
* @param bool $static_root_url Configure custom root URL path for static files
* (optional, default: from templates.static_root_url config key if set,
* '/static' otherwise. Set to False to disable)
* @return void
*/
public static function init($templates_dir=null, $templates_c_dir=null, $debug_ajax=null) {
// Check templates/templates_c directories
public static function init($templates_dir=null, $templates_c_dir=null, $debug_ajax=null,
$static_root_url=null) {
// Handle templates directories
$default_templates_directory = realpath(__DIR__."/../templates");
self :: register_templates_directory($default_templates_directory);
if (is_null($templates_dir))
$templates_dir = Config::get('template.directory', null, 'string');
if (is_null($templates_c_dir))
$templates_c_dir = Config::get('template.cache_directory', null, 'string');
if (!$templates_dir || !is_dir($templates_dir)) {
Log :: fatal(
"Template directory not found (%s)",
$templates_dir?$templates_dir:'not set');
return;
$templates_dir = App::get('templates.directory', null, 'string');
if ($templates_dir) {
if (!is_dir($templates_dir))
Log :: fatal("Template directory not found (%s)", $templates_dir);
self :: register_templates_directory($templates_dir);
}
if (!$templates_c_dir || !is_dir($templates_c_dir) || !is_writable($templates_c_dir)) {
Log :: fatal(
"Template cache directory not found or not writable (%s)",
$templates_c_dir?$templates_c_dir:'not set');
return;
// Handle and check templates_c directories
if (is_null($templates_c_dir))
$templates_c_dir = App::get('templates.cache_directory', null, 'string');
if ($templates_c_dir) {
if (!is_dir($templates_c_dir) || !is_writable($templates_c_dir)) {
Log :: fatal(
"Template cache directory not found or not writable (%s)",
$templates_c_dir);
return;
}
}
else {
$public_root_url = Url :: public_root_url();
if ($public_root_url != '/') {
$unique_name = preg_replace('#^https?://#', '', $public_root_url);
}
else {
$root_directory_path = App::root_directory_path();
if ($root_directory_path == '.') {
Log :: fatal(
'Fail to compute a unique templates cache directory for this application. An public '.
'root URL or an application root directory must be set if you do not provide it at '.
'initialization (or via config parameter).');
return;
}
$unique_name = $root_directory_path;
if (substr($unique_name, 0, 1) == '/')
$unique_name = substr($unique_name, 1);
if (substr($unique_name, -1) == '/')
$unique_name = substr($unique_name, 0, -1);
}
$templates_c_dir = sys_get_temp_dir().str_replace(
'/', '_', "eesyphp_templates_cache_$unique_name"
);
if (!is_dir($templates_c_dir) && !mkdir($templates_c_dir)) {
Log :: fatal(
'Fail to create application templates cache directory (%s)',
$templates_c_dir);
return;
}
}
self :: $smarty = new Smarty();
self :: $smarty->setTemplateDir($templates_dir);
self :: $smarty->setTemplateDir($default_templates_directory);
self :: $smarty->setCompileDir($templates_c_dir);
self :: $smarty->registerResource('Tpl', new TplSmartyResource());
if (is_null($debug_ajax))
$debug_ajax = Config::get('template.debug_ajax', Config::get('debug_ajax'));
$debug_ajax = App::get('templates.debug_ajax', App::get('debug_ajax'));
self :: $_debug_ajax = boolval($debug_ajax);
Log :: register_fatal_error_handler(array('\\EesyPHP\\Tpl', 'fatal_error'));
if (is_null($static_root_url))
$static_root_url = App::get('templates.static_root_url', 'static/', 'string');
if ($static_root_url) {
if (substr($static_root_url, 0, 1) == '/')
$static_root_url = substr($static_root_url, 1);
if (substr($static_root_url, -1) != '/')
$static_root_url = "$static_root_url/";
self :: $static_root_url = $static_root_url;
$default_static_directory = realpath(__DIR__."/../static");
self :: register_static_directory($default_static_directory, 100);
self :: register_function('static_url', array('EesyPHP\\Tpl', 'smarty_static_url'));
foreach(App :: get('templates.static_directories', array(), 'array') as $path)
self :: register_static_directory($path);
}
}
/**
@ -175,30 +250,50 @@ class Tpl {
/**
* Register CSS file(s) to load on next displayed page
* @param array<string|array<string>> $args CSS files to load
* @param string|array<string> $args CSS files to load
* @return void
*/
public static function add_css_file(...$args) {
// Check if the first argument is a custom static root URL
$root_url = self :: $static_root_url;
if (
$args && is_string($args[0]) && array_key_exists(
self :: clean_static_root_url($args[0]),
self :: $static_directories
)
)
$root_url = self :: clean_static_root_url(array_shift($args));
foreach ($args as $files) {
if (!is_array($files)) $files = array($files);
foreach ($files as $file) {
if (!in_array($file, self :: $css_files))
self :: $css_files[] = $file;
$path = $root_url.$file;
if (!in_array($path, self :: $css_files))
self :: $css_files[] = $path;
}
}
}
/**
* Register JS file(s) to load on next displayed page
* @param array<string|array<string>> $args JS files to load
* @param string|array<string> $args JS files to load
* @return void
*/
public static function add_js_file(...$args) {
// Check if the first argument is a custom static root URL
$root_url = self :: $static_root_url;
if (
$args && is_string($args[0]) && array_key_exists(
self :: clean_static_root_url($args[0]),
self :: $static_directories
)
)
$root_url = self :: clean_static_root_url(array_shift($args));
foreach ($args as $files) {
if (!is_array($files)) $files = array($files);
foreach ($files as $file) {
if (!in_array($file, self :: $js_files))
self :: $js_files[] = $file;
$path = $root_url.$file;
if (!in_array($path, self :: $js_files))
self :: $js_files[] = $path;
}
}
}
@ -210,7 +305,14 @@ class Tpl {
*/
protected static function define_common_variables($pagetitle=null) {
global $auth_user;
self :: assign('public_root_url', Url :: public_root_url());
self :: assign('pagetitle', $pagetitle);
self :: assign('main_pagetitle', App::get('main_pagetitle', null, 'string'));
self :: assign('session_key', isset($_SESSION['session_key'])?$_SESSION['session_key']:null);
// Handle CSS & JS files included
self :: add_css_file(App::get('templates.included_css_files', array(), 'array'));
self :: add_js_file(App::get('templates.included_js_files', array(), 'array'));
// Messages
self :: assign('errors', (isset($_SESSION['errors'])?$_SESSION['errors']:array()));
@ -260,7 +362,7 @@ class Tpl {
try {
Hook :: trigger('before_displaying_template');
self :: define_common_variables($pagetitle);
self :: $smarty->display($template);
self :: $smarty->display("Tpl:$template");
}
catch (Exception $e) {
Log :: exception($e, "Smarty - An exception occured displaying template '$template'");
@ -354,10 +456,229 @@ class Tpl {
}
/**
* Get the templates directory path
* @return string|null
* Get the templates directories path
* @return array<string>
*/
public static function templates_directory() {
return isset(self :: $templates_directory)?self :: $templates_directory:null;
public static function templates_directories() {
return array_keys(self :: $templates_directories);
}
/**
* Register a templates directory
* @param string $path The templates directory path
* @param int|null $priority The priority of this templates directory
* (optional, default: prior than all other registered directories)
* @return void
*/
public static function register_templates_directory($path, $priority=null) {
if (!is_dir($path)) {
Log :: fatal(
'register_templates_directory(%s): this templates directory does not exists',
$path);
return;
}
if (substr($path, -1) == '/')
$path = substr($path, 0, -1);
if (is_null($priority)) {
$priority = (
!empty(self :: $templates_directories)?
max(self :: $templates_directories) + 1:
100
);
}
Log :: trace(
'Register templates directory "%s" with priority %d',
$path, $priority);
self :: $templates_directories[$path] = $priority;
arsort(self :: $templates_directories);
}
/**
* Resolve templates path against registered templates directories
* @param string $path
* @return string|false
*/
public static function resolve_templates_path($path) {
foreach(array_keys(self :: $templates_directories) as $dir) {
$fullpath = "$dir/$path";
if (file_exists($fullpath)) {
Log::trace('Templates file "%s" resolved as "%s"', $path, $fullpath);
return $fullpath;
}
}
Log::trace('Templates file "%s" not found', $path);
return false;
}
/**
* Return the content of a Smarty template file.
*
* @param string $template The template name (eg: base.tpl)
*
* @return string The content of the Smarty template file
**/
public static function get_template_source($template) {
$path = self :: resolve_templates_path($template);
if (!is_readable($path)) {
// No error return with Smarty3 and highter because it's call
// template name in lower first systematically
return '';
}
return file_get_contents($path);
}
/**
* Return the timestamp of the last change of a Smarty
* template file.
*
* @param string $template The template name (eg: empty.tpl)
*
* @return int|null The timestamp of the last change of the Smarty template file
**/
public static function get_template_timestamp($template) {
$path = self :: resolve_templates_path($template);
if (is_file($path)) {
$time = filemtime($path);
if ($time)
return $time;
}
return null;
}
/**
* Clean static root URL helper
* @param string $value
* @return string
*/
public static function clean_static_root_url($value) {
if (substr($value, 0, 1) == '/')
$value = substr($value, 1);
if (substr($value, -1) != '/')
$value = "$value/";
return $value;
}
/**
* Get the static directories path
* @return array<string>
*/
public static function static_directories() {
$result = array();
foreach(self :: $static_directories as $root_url => $dirs)
foreach(array_keys($dirs) as $dir)
if (!in_array($dir, $result))
$result[] = $dir;
return $result;
}
/**
* Register a static directory
* @param string $path The static directory path
* @param int|null $priority The priority of this static directory
* (optional, default: prior than all other registered directories)
* @return void
*/
public static function register_static_directory($path, $priority=null, $root_url=null) {
if (is_null($root_url)) {
if (!self :: $static_root_url)
Log :: fatal(
'register_static_directory(%s): no root URL provided and no default value configured',
$path);
$root_url = self :: $static_root_url;
}
if (!array_key_exists($root_url, self :: $static_directories)) {
self :: $static_directories[$root_url] = array();
if (is_null($priority)) $priority = 100;
$pattern = "#^(?P<root_url>$root_url)(?P<path>.*)#";
Log :: trace(
'Register static file URL handler for root URL "%s" with pattern "%s" and directory '.
'"%s" (priority: %d)', $root_url, $pattern, $path, $priority);
Url :: add_url_handler(
$pattern,
array('EesyPHP\\Tpl', 'handle_static_file'),
false, // authenticated
false, // override
false, // API mode
array('GET') // methods
);
if (is_null(self :: $mime_type_detector))
self :: $mime_type_detector = new ExtensionMimeTypeDetector();
}
else {
if (is_null($priority)) {
$priority = max(self :: $static_directories[$root_url]);
$priority++;
}
Log :: trace(
'Register additionnal static directory "%s" for root URL "%s" (priority: %d)',
$path, $root_url, $priority);
}
if (substr($path, -1) == '/')
$path = substr($path, 0, -1);
self :: $static_directories[$root_url][$path] = $priority;
arsort(self :: $static_directories[$root_url]);
}
/**
* Resolve static path against registered static directories
* @param string $path
* @return string|false
*/
public static function resolve_static_path($root_url, $path) {
if (!array_key_exists($root_url, self :: $static_directories)) {
Log::error(
'No static directory registered for root URL "%s". Can no resolve static file "%s" path.',
$root_url, $path);
return false;
}
foreach(array_keys(self :: $static_directories[$root_url]) as $dir) {
$fullpath = "$dir/$path";
if (file_exists($fullpath))
return $fullpath;
}
Log::trace('Static file "%s%s" not found', $root_url, $path);
return false;
}
/**
* Handle URL request for static file
* Note: this URL handler is registered in EesyPHP\Url by self::init().
* @see self::init()
* @param UrlRequest $request
* @return void
*/
public static function handle_static_file($request) {
$path = self :: resolve_static_path($request->root_url, $request->path);
Log::trace('Resolved static file path for "%s": "%s"', $request->path, $path);
if (!$path)
Url :: trigger_error_404($request);
$mime_type = self :: $mime_type_detector->detectMimeTypeFromFile($path);
Log::trace('MIME type detected for "%s" is "%s"', $path, $mime_type);
dump_file($path, $mime_type);
}
/**
* Function to retrieve static file URL
* @param string $path The file path
* @return string|false
*/
public static function static_url($path) {
if (self :: $static_root_url)
return self :: $static_root_url.$path;
return false;
}
/**
* Smarty function to print static file URL
* @param array<string,mixed> $params Parameters from template file
* @param Smarty $smarty The smarty object
* @return void
*/
public static function smarty_static_url($params, $smarty) {
if (!isset($params['path'])) return;
$url = self :: static_url($params['path']);
if ($url) echo $url;
}
}

44
src/TplSmartyResource.php Normal file
View file

@ -0,0 +1,44 @@
<?php
namespace EesyPHP;
use Smarty_Resource_Custom;
/**
* Smarty ressource for EesyPHP templates
*
* @author Benjamin Renard <brenard@zionetrix.net>
*/
class TplSmartyResource extends Smarty_Resource_Custom {
// prepared fetch() statement
protected $fetch;
// prepared fetchTimestamp() statement
protected $mtime;
/**
* Fetch a template and its modification time
*
* @param string $name template name
* @param string $source template source
* @param integer $mtime template modification timestamp (epoch)
* @return void
*/
protected function fetch($name, &$source, &$mtime) {
$source = Tpl :: get_template_source($name);
$mtime = Tpl :: get_template_timestamp($name);
}
/**
* Fetch a template's modification time
*
* Note: implementing this method is optional. Only implement it if modification times can be
* accessed faster than loading the comple template source.
*
* @param string $name template name
* @return integer timestamp (epoch) the template was modified
*/
protected function fetchTimestamp($name) {
return Tpl :: get_template_timestamp($name);
}
}

View file

@ -57,7 +57,7 @@ class Url {
*/
public static function init($public_root_url=null, $api_mode=false) {
if (is_null($public_root_url))
$public_root_url = Config::get('public_root_url', null, 'string');
$public_root_url = App::get('public_root_url', null, 'string');
if (is_string($public_root_url) && $public_root_url) {
// Check URL end
if (substr(self :: $public_root_url, -1) == '/')
@ -201,6 +201,15 @@ class Url {
return false;
}
/**
* Trigger a 404 HTTP error
* @param UrlRequest|null $request Current UrlRequest object (optional, default: null)
* @return void
*/
public static function trigger_error_404($request=null) {
call_user_func_array(self :: $error_404_handler, array($request));
}
/**
* Interprets the requested URL and return the corresponding UrlRequest object
@ -506,6 +515,14 @@ class Url {
if (is_bool($value)) self :: $_api_mode = $value;
return self :: $_api_mode;
}
/**
* Get public root URL
* @return string
*/
public static function public_root_url() {
return (self :: $public_root_url?self :: $public_root_url:'/');
}
}
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab

View file

@ -2,6 +2,8 @@
namespace EesyPHP;
use League\MimeTypeDetection\ExtensionMimeTypeDetector;
/*
* Parser/formater values helpers
*/
@ -120,12 +122,28 @@ function cast($value, $type, $split=false) {
/*
* Generic file/directory helpers
*/
function dump_file($file_path, $max_age=3600) {
/**
* Dump file content to propose its download
* @param string $file_path The file path
* @param string|null $mime_type The file MIME type (optional, default: auto-detected)
* @param int|null $max_age Max age in second of this file in browser cache (optional,
* default: null=1h, set to False to disable Cache-Control header)
* @return void
*/
function dump_file($file_path, $mime_type=null, $max_age=null) {
if (is_file($file_path)) {
header('Content-Type: '.mime_content_type($file_path));
if (is_null($mime_type)) {
$detector = new ExtensionMimeTypeDetector();
$mime_type = $detector->detectMimeTypeFromFile($file_path);
Log::trace('MIME type detected for "%s" is "%s"', $file_path, $mime_type);
}
header("Content-Type: $mime_type");
$last_modified_time = filemtime($file_path);
$etag = md5_file($file_path);
header("Cache-Control: max-age=$max_age, must-revalidate");
$max_age = is_null($max_age)?3600:$max_age;
if ($max_age)
header("Cache-Control: max-age=$max_age, must-revalidate");
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT");
header("Etag: $etag");
@ -147,8 +165,7 @@ function dump_file($file_path, $max_age=3600) {
readfile($file_path);
exit();
}
header("HTTP/1.1 404 Not found");
exit();
Url :: trigger_error_404();
}
function delete_directory($dir, $recursive=true) {
@ -185,11 +202,14 @@ function delete_directory($dir, $recursive=true) {
* @param $data_stdin string|null The command arguments (optional, default: null)
* @param $escape_command_args boolean If true, the command will be escaped
* (optional, default: true)
* @param string|null $cwd The initial working dir for the command
* (optional, default: null = use current PHP process working
* directory)
*
* @return false|array An array of return code, stdout and stderr result or False in case of fatal
* error
**/
function run_external_command($command, $data_stdin=null, $escape_command_args=true) {
function run_external_command($command, $data_stdin=null, $escape_command_args=true, $cwd=null) {
if (is_array($command))
$command = implode(' ', $command);
if ($escape_command_args)
@ -200,7 +220,7 @@ function run_external_command($command, $data_stdin=null, $escape_command_args=t
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w"), // stderr
);
$process = proc_open($command, $descriptorspec, $pipes);
$process = proc_open($command, $descriptorspec, $pipes, $cwd);
if (!is_resource($process)) {
Log :: error("Fail to run external command: '$command'");

View file

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View file

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View file

Before

Width:  |  Height:  |  Size: 470 KiB

After

Width:  |  Height:  |  Size: 470 KiB

Some files were not shown because too many files have changed in this diff Show more