{"id":19215550,"url":"https://github.com/alwaysblank/cyrus","last_synced_at":"2026-06-15T12:32:29.187Z","repository":{"id":62518090,"uuid":"121564273","full_name":"alwaysblank/cyrus","owner":"alwaysblank","description":"Build HTML with object chaining, for fun and...not having to close tags manually.","archived":false,"fork":false,"pushed_at":"2018-04-11T18:20:36.000Z","size":55,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-11-14T12:03:55.935Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/alwaysblank.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}},"created_at":"2018-02-14T21:38:19.000Z","updated_at":"2019-05-29T04:28:51.000Z","dependencies_parsed_at":"2022-11-02T13:30:50.680Z","dependency_job_id":null,"html_url":"https://github.com/alwaysblank/cyrus","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/alwaysblank/cyrus","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alwaysblank%2Fcyrus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alwaysblank%2Fcyrus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alwaysblank%2Fcyrus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alwaysblank%2Fcyrus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alwaysblank","download_url":"https://codeload.github.com/alwaysblank/cyrus/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alwaysblank%2Fcyrus/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34363539,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-11-09T14:14:02.671Z","updated_at":"2026-06-15T12:32:29.166Z","avatar_url":"https://github.com/alwaysblank.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cyrus\n### a simple object-based HTML generator\n\n## Usage\n\nCyrus uses objects and method chaining to construct semantic HTML elements and then output them for you.\n\nThe basic process is as follows:\n\n```php\n$element = new Cyrus;\n\n$element-\u003esetEl('h1')-\u003esetClass('headline-el')-\u003eaddContent('This is a Headline!')-\u003edisplay();\n```\n\n\u003e **Note:** You can also instatiate Cyrus with its internal factory:\n\u003e\n\u003e ```php\n\u003e $element = Cyrus::open(); // this is the same as `$element = new Cyrus;`\n\u003e ```\n\nThe above code will print out the following:\n\n```html\n\u003ch1 class=\"headline-el\"\u003eThis is a Headline!\u003c/h1\u003e\n```\n\nIt supports any tag type, even ones you made up:\n\n```php\n$fakeTag = new Cyrus;\n\n$fakeTag-\u003esetEl('fake-tag')-\u003esetContent('This isn\\'t a real tag, but it\\'s rendered anyway!')-\u003edisplay();\n\n// \u003cfake-tag\u003e\n// This isn't a real tag, but it's rendered anyway!\n// \u003c/fake-tag\u003e\n```\n\nIn general the order you chain methods in doesn't matter: `$element-\u003esetClass('a-class')-\u003esetEl('p')` is function equivalent to `$element-\u003esetEl('p')-\u003esetClass('a-class')`. There are, however, a few exceptions:\n\n- Nesting (see next section) requires `openChild` at the beginning fo a child element and `closeChild` at the end: Any other order will cause Cyrus to fail.\n- Methods that overwrite content (i.e. `setEl`) will overwrite the actions of previous calls in the chain (unless separated by child barriers).\n- Calls to `construct` or `display` should always come last. Since they don't return the current object, they'll break the chain, and attempting to chain other things after them will cause some errors.\n\n#### Initial Class\n\nWhen instantiating Cyrus, you can specify a class for the primary element, by doing the following:\n\n```php\n$test = new Cyrus('test-1');\n// or...\n$test = Cyrus::open('test-1');\n// \u003cdiv class=\"test-1\"\u003e\u003c/div\u003e\n```\n\n### Nesting\n\nYou can nest elements inside of one another using the `openChild` and `closeChild` methods:\n\n```php\n$nested = new Cyrus;\n\n$nested-\u003esetClass('parent')\n    -\u003eopenChild()-\u003esetEl('span')-\u003esetClass('child')-\u003eaddContent(\"I'm a child!\")-\u003ecloseChild()\n-\u003edisplay();\n\n// \u003cdiv class=\"parent\"\u003e\n//    \u003cspan class=\"child\"\u003eI'm a child!\u003c/span\u003e\n// \u003c/div\u003e\n```\n\n#### Object Nesting\n\nIf you pass a Cyrus object to `addContent`, that object will be inserted as content and automatically expanded.\n\n```php\n$parent = new Cyrus;\n$child = new Cyrus;\n\n$child-\u003esetClass('child')-\u003esetEl('span')-\u003eaddContent(\"I'm a child\");\n\n$parent-\u003esetClass('parent')-\u003eaddContent($child)-\u003edisplay();\n\n// \u003cdiv class=\"parent\"\u003e\n//    \u003cspan class=\"child\"\u003eI'm a child!\u003c/span\u003e\n// \u003c/div\u003e\n```\n\n#### Advanced Nesting\n\nYou can also nest items after a chain has been terminated by using the `nest` method an assigning an ID when calling `openChild`. This is especially useful if, say, you want to insert (or not) content based on a conditional without resorting to creating an entirely separate Cyrus instatiation:\n\n```php\n$nestedAgain = new Cyrus;\n\n$nestedAgain-\u003esetClass('parent')-\u003eopenChild('childID')-\u003esetClass('child')-\u003ecloseChild();\n\nif(true) :\n    $nestedAgain-\u003enest('childID')-\u003eaddContent(\"I've been inserted!\")-\u003ecloseChild();\nendif;\n\n$nestedAgain-\u003edisplay();\n\n// \u003cdiv class=\"parent\"\u003e\n//    \u003cdiv class=\"child\"\u003eI've been inserted\u003c/div\u003e\n// \u003c/div\u003e\n```\n\nYou must point to nested elements directly, and define the entire path if they are nested more than one level down. You can do this by delimiting the ids with `/`, like so:\n\n```php\n$deepNesting = new Cyrus;\n\n$deepNesting-\u003esetClass('wrapper')\n\t-\u003eopenChild('level1')-\u003esetClass('level-1')\n\t\t-\u003eopenChild('level2')-\u003esetClass('level-2')-\u003ecloseChild()\n\t-\u003ecloseChild();\n\t\n$deepNesting-\u003enest('level1/level2')-\u003eaddContent('Content')-\u003ecloseChild()-\u003ecloseChild();\n\n$deepNesting-\u003edisplay();\n\n//\u003cdiv class=\"wrapper\"\u003e\n//\t\u003cdiv class=\"level-1\"\u003e\n//\t\t\u003cdiv class=\"level-2\"\u003eContent\u003c/div\u003e\n//\t\u003c/div\u003e\n//\u003c/div\u003e\t\t\n\n```\n\nIt's important to note that when opening up nesting contexts like this, *all* children must be closed. There are a two convenience methods that can help you with this, `closeChildren` and `closeAll`. `closeChildren` takes an integer as an argument, and will close a number children equal to that integer. `closeAll` takes no arguments, and will close all chilren that are open in the current context.\n\n\n### Methods\n\nTo learn how methods operate, have a look at the source files (`./src`). Each method is well documented.\n\nThe follow will cover some special functionality and edge cases.\n\n#### Short forms\n\nAny method that begins with \"set\" can be called in a shortened form, i.e. you can call `setClass` as just `class`.\n\n```php\n$element-\u003eel('blockquote');\n// is equivalent to...\n$element-\u003esetEl('blockquote');\n\n$element-\u003eattr('target', 'new');\n// is equivalent to...\n$element-\u003esetAttr('target', 'new);\n```\n\nMost nesting functions have short forms as well:\n\n```php\n$el-\u003eo();\n// is equivalent to...\n$el-\u003eopenChild();\n\n$el-\u003ec();\n// is equivalent to...\n$el-\u003ecloseChild();\n\n$el-\u003eca();\n// is equivalent to...\n$el-\u003ecloseAll();\n\n$el-\u003en('something');\n// is equivalent to...\n$el-\u003enest('something');\n```\n\n#### Advanced Attribute Manipulation\n\n##### Unset Attribute\n\nIf you find you want to unset an attribute, call `setAttr` on it with the `false` argument:\n\n```php\n$element-\u003esetAttr('data-target', 'menu')-\u003edisplay();\n// \u003cdiv data-target=\"menu\"\u003e\u003c/div\u003e\n$element-\u003esetAttr('data-target', false)-\u003edisplay();\n// \u003cdiv\u003e\u003c/div\u003e\n```\n\n##### Valueless Attributes\n\nIf you want to set an attribute that doesn't have a value--i.e. `checked`--you can do so by calling `setAttr` with the `true` argument:\n\n```php\n$element-\u003esetEl('input')-\u003esetAttr('type', 'radio')-\u003esetAttr('checked', true);\n// \u003cinput type=\"radio\" checked\u003e\n```\n\n#### setAttr, etc\n`setAttr` and all of its aliased methods (i.e. `setClass`, `setURL`, etc) stack up whatever is passed to the same attribute--they don't overwrite anything. The only exception to this is if you pass `false` as an argument to `setAttr`, as this will completely remove that attribute from the element.\n\nThis value stacking means that the following statements are equivalent:\n\n```php\n$element-\u003esetAttr('class', 'test1')-\u003esetClass('test2');\n// is equivalent to...\n$element-\u003esetClass('test1 test2');\n```\n\n#### Negate Element with False Content\nUsing `setContent` to set the only content of an element explictly to bool `false` will cause that element to not be generated. This can be useful if you want elements to only appear if they have content. In order for the element to be negated, the following must be true:\n\n  * The element has only one item of content (i.e. count($this-\u003econtent) === 1)\n  * That content item is exactly equal to bool `false` (not a _falsey value_, but the literal boolean `false`)\n  * The element in question is not a self-closing element\n\nExamples:\n\n```php\n$element-\u003eclass('outside')\n  -\u003econtent('hello')\n  -\u003eo()-\u003eclass('inside')-\u003econtent(false)-\u003ec();\n// \u003cdiv class=\"outside\"\u003ehello\u003c/div\u003e\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falwaysblank%2Fcyrus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falwaysblank%2Fcyrus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falwaysblank%2Fcyrus/lists"}