{"id":21556955,"url":"https://github.com/osmphp/framework","last_synced_at":"2025-04-10T10:22:53.069Z","repository":{"id":57033506,"uuid":"221459028","full_name":"osmphp/framework","owner":"osmphp","description":"Osm Framework is an open-source, insanely fast, unprecedentedly extensible, and fun to work with PHP 8 framework for creating modern Web applications. It's built on top of tried and tested Symfony and Laravel components.","archived":false,"fork":false,"pushed_at":"2022-05-30T09:38:04.000Z","size":4055,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"v0.15","last_synced_at":"2025-03-24T09:11:30.251Z","etag":null,"topics":["framework","osmframework","osmphp","osmsoftware","php"],"latest_commit_sha":null,"homepage":"https://osm.software/blog/framework/","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/osmphp.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-11-13T12:53:51.000Z","updated_at":"2024-08-21T00:41:58.000Z","dependencies_parsed_at":"2022-08-23T20:50:33.089Z","dependency_job_id":null,"html_url":"https://github.com/osmphp/framework","commit_stats":null,"previous_names":[],"tags_count":111,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osmphp%2Fframework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osmphp%2Fframework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osmphp%2Fframework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osmphp%2Fframework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/osmphp","download_url":"https://codeload.github.com/osmphp/framework/tar.gz/refs/heads/v0.15","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248199079,"owners_count":21063641,"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":["framework","osmframework","osmphp","osmsoftware","php"],"created_at":"2024-11-24T08:10:27.193Z","updated_at":"2025-04-10T10:22:53.042Z","avatar_url":"https://github.com/osmphp.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/osmphp/framework/actions\"\u003e\u003cimg src=\"https://github.com/osmphp/framework/workflows/tests/badge.svg\" alt=\"Build Status\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://packagist.org/packages/osmphp/framework\"\u003e\u003cimg src=\"https://img.shields.io/packagist/dt/osmphp/framework\" alt=\"Total Downloads\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://packagist.org/packages/osmphp/framework\"\u003e\u003cimg src=\"https://img.shields.io/packagist/v/osmphp/framework\" alt=\"Latest Stable Version\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://packagist.org/packages/osmphp/framework\"\u003e\u003cimg src=\"https://img.shields.io/packagist/l/osmphp/framework\" alt=\"License\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nOsm Framework is an open-source, insanely fast, unprecedentedly extensible, and\nfun to work with PHP 8 framework for creating modern Web applications. It's\nbuilt on top of tried and tested Symfony and Laravel components.\n\n# Documentation \n\n* Getting Started\n    * [Introduction](https://osm.software/blog/21/05/framework-introduction.html)\n    * [Installation](https://osm.software/blog/21/08/framework-installation.html)\n    * [Command Line Aliases](https://osm.software/blog/21/08/framework-command-line-aliases.html)  \n    * Directory Structure\n    * Using Gulp\n    * Nginx\n    * Apache\n* Writing PHP Code\n    * [Computed Properties](https://osm.software/blog/21/09/framework-computed-properties.html)\n    * [Modules](https://osm.software/blog/21/09/framework-modules.html)\n    * [Dynamic Traits](https://osm.software/blog/21/09/framework-dynamic-traits.html)\n    * [Application](https://osm.software/blog/21/09/framework-application.html)\n    * Hint Classes\n    * Reflection\n    * Testing\n    * PHPStorm\n* Creating Web Applications\n    * Requests\n    * Routes\n    * Areas\n    * Advices\n    * Responses\n    * Views And Components\n    * Themes\n    * Assets\n* Creating Console Applications \n* Processing Data\n    * Migrations\n    * Database \n    * [Search](https://osm.software/blog/21/05/framework-search.html)\n* Writing JavaScript Code\n    * Classes\n    * Controllers\n    * Testing \n* Other Features\n    * [Logging](https://osm.software/blog/21/09/framework-logging.html)\n    * Caching\n    * Configuration\n    * Translations\n    * Maintenance Mode\n    * Production Mode\n    * Helper Functions\n    * Extending Gulp Scripts\n* [License](https://github.com/osmphp/framework/blob/HEAD/LICENSE)\n\n# Top Features\n\n## Extensibility (Dynamic Traits) \n\nLet's examine the extensibility bit in more detail. \n\nImagine using some e-commerce software that processes new sales order as follows:\n\n    class Order extends Object_ {\n        public function submit(): void {\n            $this-\u003evalidate();\n            $this-\u003eapplyDiscounts();\n            $this-\u003eapplyTaxes();\n            $this-\u003esave();\n        }\n        \n        protected function validate(): void {\n            // standard validation logic\n            ...\n        }\n        \n        ...\n    }\n\nIf you need to customize this logic, for example, check if all the purchased items are in stock, you can add it after the validation phase:\n\n    trait OrderTrait {\n        protected function around_validate(callable $proceed): void {\n            // first, execute the standard validation\n            $proceed();\n            \n            // then, add the logic that checks the stock\n            ...\n        }\n    } \n\nUnder the hood, Osm Framework applies this PHP trait dynamically to `Order` class, and overrides standard `validate()` method with your custom `around_validate()` method.\n\nThis way, you can customize any method, in almost any class.\n\nYou can introduce new properties and methods to existing classes, too:  \n\n    /**\n     * @property bool @are_all_items_in_stock   \n     */\n    trait OrderTrait {\n        protected function checkStockItem(): bool {\n            ...\n        } \n    } \n\n## Fast And Test-Friendly Computed Properties\n\nIn Osm Framework, a **computed (or \"lazy\") property** is a public property of a PHP class that is computed once on first access using matching `get_` method.  \n\nFor example, consider a class that reads and transforms a Markdown file into HTML:\n\n    /**\n     * @property string $path Relative file path in the `data` directory. \n     *      Provide this property in the constructor.\n     * @property string $absolute_path Absolute file path\n     *\n     * @property string $text Original text in Markdown format\n     * @property string $html Text converted to HTML\n     */\n    class MarkdownFile extends Object_ {\n        protected function get_absolute_path(): string {\n            // get the reference to the global application object which,\n            // among other things, stores the absolute path of the `data`\n            // directory in its `paths-\u003edata` property \n            global $osm_app; /* @var App $osm_app */\n    \n            return \"{$osm_app-\u003epaths-\u003edata}/posts/{$this-\u003epath}\";\n        }\n    \n        protected function get_text(): string {\n            return file_get_contents($this-\u003eabsolute_path);\n        }\n\n        protected function get_html(): ?string {\n            // convert the text into HTML using `michelf/php-markdown` \n            // Composer package\n            return MarkdownExtra::defaultTransform($this-\u003etext);\n        }\n    } \n\nTypical usage:\n\n    // `MarkdownFile::new()` creates new instance of the class, \n    // just as `new MarkdownFile()` would do, plus it applies dynamic traits\n    $file = MarkdownFile::new(['path' =\u003e 'welcome.md']);\n    \n    echo $file-\u003ehtml;\n    \nWhile accessing formally undefined `html` property for the first time, PHP internally creates it and assigns it a value computed using `get_html()` method. On subsequent access, PHP just returns previously computed property value. The same happens with `text` and `absolute_path` properties.\n\nComputed properties save precious CPU cycles. On one hand, property values are only computed if they are actually accessed. On the other hand, some properties are accessed hundreds or even thousands times while handling a single HTTP request, and thanks to very fast subsequent access these properties have significant performance increase.\n\nComputed properties are also test-friendly. In the following example, the unit test fully concentrates on HTML transformation by omitting `text` property computation - and all the file handling - by providing its value in the constructor:\n\n    public function test_markdown_transformation() {\n        // GIVEN a bold text written in Markdown\n        $file = MarkdownFile::new(['text' =\u003e '**test**']);\n        \n        // WHEN you convert it to HTML\n        // THEN it is marked with `\u003cstrong\u003e` HTML element\n        $this-\u003eassertEquals('\u003cp\u003e\u003cstrong\u003etest\u003c/strong\u003e\u003c/p\u003e', $file-\u003ehtml); \n    }     \n\n## More Results With Less Effort Using Reflection \n\nWith Osm Framework, you develop faster by letting it to infer mundane things from class definitions. \n\nFor example, in order to introduce new console command, you only have to define a class extending the `Command` class, and the framework adds it to the system automatically.\nIt also inspects property definitions, finds the `Option` and `Argument` attributes, and exposes them as command-line options and arguments:\n\n    /**\n     * @property bool $caps #[Option] If specified, the person name is upper-cased\n     * @property string $person_name #[Argument] The person to greet\n     */\n    class Hello extends Command\n    {\n        public string $name = 'hello';\n        public string $description = 'A sample command';\n    \n        public function run(): void {\n            $name = $this-\u003ecaps ? strtoupper($this-\u003eperson_name) : $this-\u003eperson_name;\n            $this-\u003eoutput-\u003ewriteln(\"Hello, {$name}\");\n        }\n    }\n    \nWith the `gulp watch` running, you can use the command without further ado:\n\n    \u003eosm hello vo\n    Hello, vo\n    \n    \u003eosm hello vo --caps\n    Hello, VO \n\nThe other example stores the property in the application cache just by marking property as `Cached`:\n\n    /**\n     * @property string $cached_property #[Cached('my_cache_entry')]\n     */\n    class MyClass extends Object_\n    {\n        protected function get_cached_property(): string {\n            ...\n        }\n    }       \n    \n## Exceptional Performance\n\nOsm Framework is very fast, for two reasons.\n\nFirst, it offloads performance-hungry parts into pre-execution (or \"compilation\") phase, and aggressively uses caching techniques.\n\nSecond, where it really makes a difference, it puts performance first, sometimes even above established programming practices. \n\nOne example is implementation of computed properties. The implementation is really fast, but it sacrifices encapsulation principle - the computed properties are public.\n\nAnother example is `$osm_app` global variable. Global variables in general are a known anti-pattern. However, as tests have shown, replacing `get_app()` accessor function with direct variable access gives significant performance boost, and, hence, the `$osm_app`\nglobal variable became the main internal API entry point.   ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fosmphp%2Fframework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fosmphp%2Fframework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fosmphp%2Fframework/lists"}