{"id":16758106,"url":"https://github.com/foo123/tico","last_synced_at":"2025-09-06T19:42:18.188Z","repository":{"id":58125981,"uuid":"251061402","full_name":"foo123/tico","owner":"foo123","description":"Super-simple and versatile MVC Web Framework for PHP","archived":false,"fork":false,"pushed_at":"2024-09-08T12:56:21.000Z","size":187,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-24T14:51:25.941Z","etag":null,"topics":["mvc-framework","web-framework"],"latest_commit_sha":null,"homepage":"https://foo123.github.io/","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/foo123.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-29T15:10:42.000Z","updated_at":"2024-09-08T12:56:24.000Z","dependencies_parsed_at":"2024-04-21T09:37:47.707Z","dependency_job_id":"25870495-157b-46e6-8e3c-0cf64df841fe","html_url":"https://github.com/foo123/tico","commit_stats":null,"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo123%2Ftico","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo123%2Ftico/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo123%2Ftico/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo123%2Ftico/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/foo123","download_url":"https://codeload.github.com/foo123/tico/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248261909,"owners_count":21074225,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mvc-framework","web-framework"],"created_at":"2024-10-13T04:04:10.026Z","updated_at":"2025-09-06T19:42:18.177Z","avatar_url":"https://github.com/foo123.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tico\n\nMini, super-simple and versatile MVC Web Framework for PHP (**v.1.22.0** in progress)\n\n\n**Uses:**\n\n1. [Importer](https://github.com/foo123/Importer) class \u0026amp; asset dependency loader\n2. [Dromeo](https://github.com/foo123/Dromeo) versatile pattern router\n3. [InTpl](https://github.com/foo123/InTpl) simple php templates w/ inheritance\n4. HttpFoundation, adapted from [Symfony's HttpFoundation component (v.7.3.1 / 2025)](https://github.com/symfony/http-foundation)\n\n\n**Hooks in order of execution:**\n\n**serve normal response**\n\n1. `tico_before_serve`\n2. `tico_before_middleware_before`\n3. `tico_after_middleware_before`\n4. `tico_before_route`\n5. `tico_after_route`\n6. `tico_before_middleware_after`\n7. `tico_after_middleware_after`\n8. `tico_prepared_response`\n9. `tico_cache_response`\n10. `tico_send_response`\n11. `tico_after_serve`\n\n**serve cached response**\n\n1. `tico_serve_cache`\n2. `tico_before_serve_cached`\n3. `tico_after_serve_cached`\n\n**various hooks run in-between when data are set or changed:**\n\n1. `tico_request`, set request object\n2. `tico_response`, set response object\n3. `tico_set_callback`, change streamed output via callback\n4. `tico_set_content`, change output content\n5. `tico_set_file`, change/remove output file\n6. `tico_redirect`, change/remove redirect url\n7. `tico_autoload`, change/remove autoload classes\n8. `tico_enqueue`, change/remove enqueued asset\n\n\n**demo** (see `/demo/index.php`)\n\n```php\ndefine('ROOT', dirname(__FILE__));\ninclude(ROOT . '/../tico/Tico.php');\n\nclass MyModel\n{\n    public function getMsg()\n    {\n        return \"Hello\";\n    }\n}\n\ntico('http://localhost:8000', ROOT)\n    // some options\n    -\u003eoption('webroot', ROOT) // default\n    -\u003eoption('views', [tico()-\u003epath('/views')])\n    -\u003eoption('normalized_uris', true) // default\n    -\u003eoption('normalize_uri', function($part) {\n        return str_replace(array('ά','έ','ή','ί','ϊ','ΐ','ό','ύ','ϋ','ΰ','ώ','ς'), array('α','ε','η','ι','ι','ι','ο','υ','υ','υ','ω','σ'), mb_strtolower($part, 'UTF-8'));\n    })\n    /*-\u003eoption('tpl_render', function($tpl, $data, $viewsFolders) {\n        // custom template renderer\n        return MyFancyTpl::render($tpl, $data);\n    })*/\n    //-\u003eset('model', new MyModel()) // simple dependency injection container\n    -\u003eset('model', function() {\n        return new MyModel();\n    }) // container supports lazy factory-like functions\n    -\u003eset('cache', function() {\n        // any custom caching solution can be used that has get/set methods, here a simple CacheManager\n        include tico()-\u003epath('/cache/CacheManager.php');\n        return (new CacheManager())\n            -\u003eoption('cache_dur_sec', 10 * 60/*10 minutes*/)\n            -\u003eoption('cache_dir', tico()-\u003epath('/cache/data'))\n        ;\n    }) // container supports lazy factory-like functions\n    -\u003ehook('tico_before_serve_cached', function() {\n        // a custom hook\n        tico()-\u003evariable('tico_before_serve_cached__content', tico()-\u003evariable('tico_before_serve_cached__content').\"\\n\\n\u003c!--cached version--\u003e\");\n    })\n;\n\n\n// if cache enabled and served, exit fast and early\n(tico()-\u003eserveCache())\n\nor\n\n// else serve request normally, using full framework\n(tico()\n// middleware functionality\n-\u003emiddleware(function($next) {\n\n    // eg check if user is authenticated,\n    // for example check user cookie and set user var appropriately\n    tico()-\u003eset('user', tico()-\u003erequest()-\u003ecookies-\u003eget('user', 'guest'));\n    // start session example (eg native php session)\n    $session = new HttpSession(/*array(..)*/);\n    tico()-\u003erequest()-\u003esetSession($session);\n    $session-\u003estart();\n    if (!$session-\u003ehas('count')) $session-\u003eset('count', 0);\n    $next();\n\n})\n-\u003emiddleware(function($next) {\n\n    // if this condition is met, abort current request, eg user is not authenticated\n    if (('guest'==tico()-\u003eget('user')) \u0026\u0026 ('/hello/foo'==tico()-\u003erequestPath()))\n        //tico()-\u003eredirect(tico()-\u003euri('/hello/bar'), 302);\n        tico()-\u003eoutput(\n            array('title' =\u003e 'Hello!', 'msg' =\u003e 'guest'),\n            'hello.tpl.php'\n        );\n    // else pass along\n    else\n        $next();\n\n})\n\n\n// can handle other ports from same script, as long as handling is directed to this file\n// on :4040 port, '*' means on any port\n-\u003eonPort(4040, function() {\n\n    tico()\n        -\u003eon('*', '/', function() {\n\n            tico()-\u003eoutput(\n                array('title' =\u003e 'Demo Port Index'),\n                '4040/index.tpl.php'\n            );\n\n        })\n        -\u003eon(false, function() {\n\n            tico()-\u003eoutput(\n                array(),\n                '4040/404.tpl.php',\n                array('StatusCode' =\u003e 404)\n            );\n\n        })\n    ;\n\n})\n\n// can handle subdomains from same script, as long as subdomain handling is directed to this file\n// on \"foo.\" subdomain, '*' means on any subdomain\n-\u003eonSubdomain('foo', function() {\n\n    tico()\n        -\u003eon('*', '/', function() {\n\n            tico()-\u003eoutput(\n                array('title' =\u003e 'Demo Subdomain Index'),\n                'foo/index.tpl.php'\n            );\n\n        })\n        -\u003eon(false, function() {\n\n            tico()-\u003eoutput(\n                array(),\n                'foo/404.tpl.php',\n                array('StatusCode' =\u003e 404)\n            );\n\n        })\n    ;\n\n})\n\n// on main domain / port\n-\u003eon('*', '/', function() {\n\n    tico()-\u003eoutput(\n        array('title' =\u003e 'Demo Index'),\n        'index.tpl.php'\n    );\n\n})\n-\u003eon(['get', 'post'], '/hello/{:msg}', function($params) {\n\n    $session = tico()-\u003erequest()-\u003egetSession();\n    $session-\u003eset('count', $session-\u003eget('count')+1);\n    tico()-\u003eoutput(\n        array(\n            'title' =\u003e 'Hello!',\n            'msg' =\u003e $params[':']['msg'], // original msg\n            'count'=\u003e $session-\u003eget('count')\n        ),\n        'hello.tpl.php'\n    );\n\n})\n// non-ascii/unicode normalized uris\n-\u003eon(['get', 'post'], '/γεια/{:msg}', function($params) {\n\n    $session = tico()-\u003erequest()-\u003egetSession();\n    $session-\u003eset('count', $session-\u003eget('count')+1);\n    tico()-\u003eoutput(\n        array(\n            'title' =\u003e 'Γειά!',\n            'msg' =\u003e $params[':']['msg'], // original msg\n            'count'=\u003e $session-\u003eget('count')\n        ),\n        'hello.tpl.php'\n    );\n\n})\n// group routes under common prefix\n-\u003eonGroup('/foo', function() {\n\n    tico()\n        // /foo\n        -\u003eon('*', '/', function() {\n            tico()-\u003eoutput(\n                array(\n                    'title' =\u003e 'Group Route',\n                    'msg' =\u003e 'Group Route /foo',\n                    'count'=\u003e 0\n                ),\n                'hello.tpl.php'\n            );\n        })\n        // /foo/moo\n        -\u003eon('*', '/moo', function() {\n            tico()-\u003eoutput(\n                array(\n                    'title' =\u003e 'Group Route',\n                    'msg' =\u003e 'Group Route /foo/moo',\n                    'count'=\u003e 0\n                ),\n                'hello.tpl.php'\n            );\n        })\n        // /foo/koo\n        -\u003eonGroup('/koo', function() {\n            tico()\n                // /foo/koo\n                -\u003eon('*', '/', function() {\n                    tico()-\u003eoutput(\n                        array(\n                            'title' =\u003e 'Group Route',\n                            'msg' =\u003e 'Group Route /foo/koo',\n                            'count'=\u003e 0\n                        ),\n                        'hello.tpl.php'\n                    );\n                })\n                // /foo/koo/soo\n                -\u003eon('*', '/soo', function() {\n                    tico()-\u003eoutput(\n                        array(\n                            'title' =\u003e 'Group Route',\n                            'msg' =\u003e 'Group Route /foo/koo/soo',\n                            'count'=\u003e 0\n                        ),\n                        'hello.tpl.php'\n                    );\n                })\n            ;\n        })\n    ;\n\n})\n-\u003eon('*', '/json/api', function() {\n\n    tico()-\u003eoutput(array(\n        'param1' =\u003e '123',\n        'param2' =\u003e '456',\n        'param3' =\u003e '789'\n    ), 'json');\n\n})\n-\u003eon('*', '/download', function() {\n\n    tico()-\u003eoutput(\n        tico()-\u003epath('/file.txt'),\n        'file'\n    );\n\n})\n-\u003eon('*', '/redirect', function() {\n\n    tico()-\u003eredirect(tico()-\u003euri('/'), 302);\n\n})\n-\u003eon(false, function() {\n\n    tico()-\u003eoutput(\n        array(),\n        '404.tpl.php',\n        array('StatusCode' =\u003e 404)\n    );\n\n})\n\n// middlewares are same for main domain and all subdomains and all ports\n-\u003emiddleware(function($next) {\n\n    // post process, eg create cache files from response\n    if ((200 == tico()-\u003eresponse()-\u003egetStatusCode()) \u0026\u0026 'text/html'==tico()-\u003eresponse()-\u003eheaders-\u003eget('Content-Type') \u0026\u0026 !tico()-\u003eresponse()-\u003egetFile() \u0026\u0026 !tico()-\u003eresponse()-\u003egetCallback())\n    {\n        tico()-\u003eresponse()-\u003esetContent(tico()-\u003eresponse()-\u003egetContent().'\u003c!-- post processed --\u003e');\n    }\n\n}, 'after')\n\n-\u003eserve())\n;\n```\n\n**see also:**\n\n* [ModelView](https://github.com/foo123/modelview.js) a simple, fast, powerful and flexible MVVM framework for JavaScript\n* [tico](https://github.com/foo123/tico) a tiny, super-simple MVC framework for PHP\n* [LoginManager](https://github.com/foo123/LoginManager) a simple, barebones agnostic login manager for PHP, JavaScript, Python\n* [SimpleCaptcha](https://github.com/foo123/simple-captcha) a simple, image-based, mathematical captcha with increasing levels of difficulty for PHP, JavaScript, Python\n* [Dromeo](https://github.com/foo123/Dromeo) a flexible, and powerful agnostic router for PHP, JavaScript, Python\n* [PublishSubscribe](https://github.com/foo123/PublishSubscribe) a simple and flexible publish-subscribe pattern implementation for PHP, JavaScript, Python\n* [Localizer](https://github.com/foo123/Localizer) a simple and versatile localization class (l10n) for PHP, JavaScript, Python\n* [Importer](https://github.com/foo123/Importer) simple class \u0026amp; dependency manager and loader for PHP, JavaScript, Python\n* [EazyHttp](https://github.com/foo123/EazyHttp), easy, simple and fast HTTP requests for PHP, JavaScript, Python\n* [Contemplate](https://github.com/foo123/Contemplate) a fast and versatile isomorphic template engine for PHP, JavaScript, Python\n* [HtmlWidget](https://github.com/foo123/HtmlWidget) html widgets, made as simple as possible, both client and server, both desktop and mobile, can be used as (template) plugins and/or standalone for PHP, JavaScript, Python (can be used as [plugins for Contemplate](https://github.com/foo123/Contemplate/blob/master/src/js/plugins/plugins.txt))\n* [Paginator](https://github.com/foo123/Paginator)  simple and flexible pagination controls generator for PHP, JavaScript, Python\n* [Formal](https://github.com/foo123/Formal) a simple and versatile (Form) Data validation framework based on Rules for PHP, JavaScript, Python\n* [Dialect](https://github.com/foo123/Dialect) a cross-vendor \u0026amp; cross-platform SQL Query Builder, based on [GrammarTemplate](https://github.com/foo123/GrammarTemplate), for PHP, JavaScript, Python\n* [DialectORM](https://github.com/foo123/DialectORM) an Object-Relational-Mapper (ORM) and Object-Document-Mapper (ODM), based on [Dialect](https://github.com/foo123/Dialect), for PHP, JavaScript, Python\n* [Unicache](https://github.com/foo123/Unicache) a simple and flexible agnostic caching framework, supporting various platforms, for PHP, JavaScript, Python\n* [Xpresion](https://github.com/foo123/Xpresion) a simple and flexible eXpression parser engine (with custom functions and variables support), based on [GrammarTemplate](https://github.com/foo123/GrammarTemplate), for PHP, JavaScript, Python\n* [Regex Analyzer/Composer](https://github.com/foo123/RegexAnalyzer) Regular Expression Analyzer and Composer for PHP, JavaScript, Python\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoo123%2Ftico","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffoo123%2Ftico","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoo123%2Ftico/lists"}