{"id":20254775,"url":"https://github.com/chippyash/builder-pattern","last_synced_at":"2025-04-11T00:04:38.622Z","repository":{"id":23676645,"uuid":"27048018","full_name":"chippyash/Builder-Pattern","owner":"chippyash","description":"PHP Implementation of event driven Builder Pattern","archived":false,"fork":false,"pushed_at":"2018-07-04T22:15:02.000Z","size":60,"stargazers_count":3,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-11T00:04:26.010Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chippyash.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-11-23T21:15:27.000Z","updated_at":"2025-02-16T03:48:18.000Z","dependencies_parsed_at":"2022-08-21T21:20:31.223Z","dependency_job_id":null,"html_url":"https://github.com/chippyash/Builder-Pattern","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chippyash%2FBuilder-Pattern","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chippyash%2FBuilder-Pattern/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chippyash%2FBuilder-Pattern/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chippyash%2FBuilder-Pattern/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chippyash","download_url":"https://codeload.github.com/chippyash/Builder-Pattern/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248317705,"owners_count":21083528,"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":[],"created_at":"2024-11-14T10:34:49.996Z","updated_at":"2025-04-11T00:04:38.589Z","avatar_url":"https://github.com/chippyash.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# chippyash/builder-pattern\n\n## Quality Assurance\n\n![PHP 5.5](https://img.shields.io/badxge/PHP-5.5-blue.svg)\n![PHP 5.6](https://img.shields.io/badge/PHP-5.6-blue.svg)\n![PHP 7](https://img.shields.io/badge/PHP-7-blue.svg)\n[![Build Status](https://travis-ci.org/chippyash/Builder-Pattern.svg?branch=master)](https://travis-ci.org/chippyash/Builder-Pattern)\n[![Test Coverage](https://codeclimate.com/github/chippyash/Builder-Pattern/badges/coverage.svg)](https://codeclimate.com/github/chippyash/Builder-Pattern/coverage)\n[![Code Climate](https://codeclimate.com/github/chippyash/Builder-Pattern/badges/gpa.svg)](https://codeclimate.com/github/chippyash/Builder-Pattern)\n\nThe above badges represent the current development branch.  As a rule, I don't push\n to GitHub unless tests, coverage and usability are acceptable.  This may not be\n true for short periods of time; on holiday, need code for some other downstream\n project etc.  If you need stable code, use a tagged version. Read 'Further Documentation'\n and 'Installation'.\n \n[Test Contract](https://github.com/chippyash/Builder-Pattern/blob/master/docs/Test-Contract.md)  (37 tests, 65 assertions) in the docs directory.\n\nPlease note that developer support for PHP5.5 was withdrawn at version 3.0.0 of this library.\nIf you need support for PHP 5.5, please use a version `\u003e=2,\u003c3`\n \n## What?\n\nProvides an implementation of the [Builder Pattern](http://en.wikipedia.org/wiki/Builder_pattern) \nfor PHP.\n\n*  Everything has a test case\n*  It's PHP 5.6+\n\nThe library is released under the [GNU GPL V3 or later license](http://www.gnu.org/copyleft/gpl.html)\n\nIf you have [PlantUML](http://plantuml.sourceforge.net/) installed, you can view the UML diagrams in the docs folder.\n\nSee the test contract in the docs folder.\n\n## Why\n\nSolve the problem once!  The requirement was to have a builder pattern implementation \nthat can:\n\n* be used to build test data sets or other items\n* allow test scripts to modify builder behaviour via the directors\n\n## How\n\nThe solution breaks the problem into parts:\n\n* Builders build a data set\n* Modifiers utilise events to communicate changes in the builder behaviour\n* Renderers are responsible for doing something with the built data\n* Directors control the process (as per the builder pattern) and can communicate to\nbuilders via the Modifier\n\n### Coding Basics\n\nPlease see the example script, Builders and Director in the examples folder.  They\ndemonstrate all the principles of using the library.  Try changing the Director\nto use a different Renderer.  Add some additional data items to a builder.  Add a\nmodification into a builder, with a Director method that allows the client script\nto control the build.\n\n### Creating Builders\n\nExtend your builder from AbstractBuilder and add a protected function setBuildItems()\nto add items to the $this-\u003ebuildItems associative array.  Items can be simple\nvalue holders or implementations of another builder. e.g.\n\n\u003cpre\u003e\n    protected function setBuildItems()\n    {\n        $this-\u003ebuildItems = [\n            'name' =\u003e '',\n            'createdate' =\u003e new \\DateTime(),\n            'account' =\u003e new AccountBuilder(),\n            'exportName =\u003e function(){return 'BuilderPattern!';}\n        ];\n    }\n\u003c/pre\u003e\n\nUnder normal circumstances, you can reference your builder items using\n\n\u003cpre\u003e\n    $builder-\u003eitemname = $value\n    $value = $builder-\u003eitemname\n    //or\n    $builder-\u003eSetItemname($value)\n    $value = $builder-\u003egetItemname()\n\u003c/pre\u003e\n\nUsing the set... method has the advantage that it presents a fluent interface\nthus allowing you to chain setters together.\n\nIn some circumstances, you may want to add some special processing to setting\nand getting.  Simply create a public setItemname($value) method or getItemname()\nmethod.  Similarly you can provide a hasItemname() method to override default isset()\nbehaviour.\n\n\u003cpre\u003e\n    public function setName($value)\n    {   \n        $this-\u003ebuildItems['name'] = ucfirst($value);\n        return $this;\n    }\n\u003c/pre\u003e\n\nYou can create a collection builder by extending AbstractCollectionBuilder.  In\nthis case you do not need to add a setBuildItems() method as this is already done \nin the abstract parent class.\n\nNote that adding override methods generally does not make sense for a collection\nbuilder.  Collection builders support methods for adding builders to the collection:\n\n\u003cpre\u003e\n    $cBuilder-\u003eaddBuilder($builder);\n    $cBuilder-\u003esetCollection(array($builder1, $builder2, ...));\n    $collection = $cBuilder-\u003egetCollection()\n\u003c/pre\u003e\n\nAll builders support building and getting the results:\n\n\u003cpre\u003e\n    if ($builder-\u003ebuild()) {\n        $result = $builder-\u003egetResult();\n    } else {\n        //...\n    }\n\u003c/pre\u003e\n\n### Creating Directors\n\nCreate a Director by extending the AbstractDirector class and providing it with\na constructor that extends the parent\n\n\u003cpre\u003e\nclass CustomerDirector extends AbstractDirector\n{\n    public function __construct()\n    {\n        parent::__construct(new CustomerBuilder(), new JsonRenderer());\n    }\n}\n\u003c/pre\u003e\n\nYou can use the supplied renderers, or create your own.  The above snippet is the\nminimum you need to do.  You can add setup steps in the constructor:\n\n\u003cpre\u003e\n    public function __construct(EventManagerAwareInterface $modifier)\n    {\n        $builder = new CustomerBuilder();\n        parent::__construct($builder, new JsonRenderer());\n        \n        //set test account details\n        $builder-\u003esetName('Mrs Felicia Bailey');\n        $builder-\u003eaccount-\u003eid = '023197';\n    }\n\u003c/pre\u003e\n\nYou can also add methods that are available to clients of the director:\n\n\u003cpre\u003e\n    public function setName($name)\n    {\n        $this-\u003ebuilder-\u003esetName($name);\n        return $this;\n    }\n\n    public function setAccountId($id)\n    {\n        $this-\u003ebuilder-\u003eaccount-\u003esetId($id);\n        return $this;\n    }\n\u003c/pre\u003e\n\n### Modifying the build\n\nThe library supports an event driven modification system that gives you great\ncontrol over the build process.  By default the Builders do not support this. To\nenable it you need to call the setModifier() method on the root builder, which\nwill ripple it down the builder tree.  A stock modifier is provided in the form\nof Chippyash\\BuilderPattern\\Modifier, but you can create your own by implementing\nthe Zend\\EventManager\\EventManagerAwareInterface if you need to.\n\nIf you are using the BuilderPattern in some large system you may want to instantiate\nthe Modifier outside of the Directors and pass it in, so the event train is shared\nbetween all your application components.  The CustomerDirector example does this:\n\n\u003cpre\u003e\nclass CustomerDirector extends AbstractDirector\n{\n    public function __construct(EventManagerAwareInterface $modifier)\n    {\n        $builder = new CustomerBuilder();\n        $builder-\u003esetModifier($modifier);\n    }\n}\n\u003c/pre\u003e\n\nBy default, the AbstractDirector knows about and supports two events, \n\n* ModifiableInterface::PHASE_PRE_BUILD\n* ModifiableInterface::PHASE_POST_BUILD\n\nThese are triggered just before build commences and just after success of the build \nrespectively. NB. You can create triggers and listeners for other events.\n\n#### Adding modifiers\n\nAdding a modifier (trigger) to the pre or post build trigger stack is straightforward, \nsimply call the root builder modify() method.  modify() expects two parameters:\n\n* an array of parameters which must at least contain an 'name' item specifying\nthe required action.\n* the name of an event, usually ModifiableInterface:l:PHASE_PRE_BUILD or\nModifiableInterface::PHASE_POST_BUILD, but it can be any string\n\nHere's an example from the CustomerDirector:\n\n\u003cpre\u003e\n    public function buyItem($itemId, $amount)\n    {\n        $this-\u003ebuilder-\u003emodify(\n                ['name' =\u003e 'addPurchase',\n                 'id' =\u003e $itemId,\n                 'date' =\u003e new \\DateTime],\n                ModifiableInterface::PHASE_PRE_BUILD\n                );\n        $this-\u003ebuilder-\u003emodify(\n                ['name' =\u003e 'updateBalance',\n                 'amount' =\u003e $amount],\n                ModifiableInterface::PHASE_PRE_BUILD\n                );\n        \n        return $this;\n    }\n\u003c/pre\u003e\n\nThe modify() method is best used for the two supported events.  If you want \nto trigger another type of event you can call the trigger method on the event \nmanager directly\n\n\u003cpre\u003e\n    $modifer-\u003egetEventManager()-\u003etrigger($eventName, $this, $params);\n\u003c/pre\u003e\n\nThis allows a great degree of control, particularly where you are using builders \nas part of a larger system, and that system is able to modify the eventual build\nresult a long time before the build actually takes place.\n\nOf course for every trigger, you need one or more listeners.  You put these in\nyour Builder classes.  In Builders that you want to have listeners, extend the \nsetModifier() method to set up your listeners:\n\n\u003cpre\u003e\n    public function setModifier(EventManagerAwareInterface $modifier)\n    {\n        parent::setModifier($modifier);\n        $this-\u003emodifier-\u003egetEventManager()-\u003eattach(ModifiableInterface::PHASE_PRE_BUILD, [$this,'preBuildListener']);\n    }\n\u003c/pre\u003e\n\nIn this example, we are telling the event manager to use the preBuildListener() method\nto answer to a pre build trigger.  A typical implementation might be:\n\n\u003cpre\u003e\n    public function preBuildListener(Event $e)\n    {\n        if ($e-\u003egetParam('name') == 'updateBalance') {\n            $this-\u003ebalance += $e-\u003egetParam('amount');\n        }\n    }\n\u003c/pre\u003e\n\n### A note on renderers\n\nBeing able to build some sort of data structure is well and good, but the real\npower of the BuilderPattern comes from what you can do with it.  Three basic\nrenderers are provided:\n\n* PassthruRenderer - simply passes back the result of builder-\u003egetResult()\n* JsonRenderer - returns builder-\u003egetResult() as a Json string\n* XmlRenderer - returns builder-\u003egetResult() as an XML definition\n\nYou will almost certainly want to create your own renderers, simply do this by\nimplementing the RendererInterface.  Some ideas:\n\n* creation of configured objects (although this is usually better handled through\na dependency injection container; Symfony provides a good one. However, the \nBuilderPattern allows for in-app object construction, rather than at application\nstart.)\n* creating diagrams via an SVG implementation\n* firing commands to external processes (I've used this to create entries on a\nmock service provider to set up system tests, for instance.) \n\n### Changing the library\n\n1.  fork it\n2.  write the test\n3.  amend it\n4.  do a pull request\n\nFound a bug you can't figure out?\n\n1.  fork it\n2.  write the test\n3.  do a pull request\n\nNB. Make sure you rebase to HEAD before your pull request\n\n## Where?\n\nThe library is hosted at [Github](https://github.com/chippyash/Builder-Pattern).\nIt is available at [Packagist.org](https://packagist.org/packages/chippyash/builderpattern) as a\n[Composable](https://getcomposer.org/) module\n\n### Installation\n\nInstall [Composer] (https://getcomposer.org/)\n\n#### For production\n\nadd\n\n\u003cpre\u003e\n    \"chippyash/builderpattern\": \"\u003e=3,\u003c4\"\n\u003c/pre\u003e\n\nto your composer.json \"requires\" section.\n\n#### For development\n\nClone this repo, and then run Composer in local repo root to pull in dependencies\n\n\u003cpre\u003e\n    git clone git@github.com:chippyash/Builder-Pattern.git DataBuilder\n    cd DataBuilder\n    composer install --dev\n\u003c/pre\u003e\n\nTo run the tests:\n\n\u003cpre\u003e\n    cd DataBuilder\n    vendor/bin/phpunit -c test/phpunit.xml test/\n\u003c/pre\u003e\n\n## Some other stuff\n\nCheck out [ZF4 Packages](http://zf4.biz/packages?utm_source=github\u0026utm_medium=web\u0026utm_campaign=blinks\u0026utm_content=builderpattern) for more packages\n\n## License\n\nThis software library is released under the [BSD 3 Clause license](https://opensource.org/licenses/BSD-3-Clause)\n\nThis software library is Copyright (c) 2015-2016, Ashley Kitson, UK\n\nA commercial license is available for this software library, please contact the author. \nIt is normally free to deserving causes, but gets you around the limitation of the GPL\nlicense, which does not allow unrestricted inclusion of this code in commercial works.\n\n## History\n\n1.0.0 initial version\n\n1.0.1 integrate travis and coveralls\n\n1.0.2 complete test pack\n\n1.0.3 add test contract\n\n1.1.0 new feature: allow use of closures as build items\n\n1.1.1 make library agnostic of Zend-EventManager version\n\n2.0.0 BC Break: change namespace from chippyash\\BuilderPattern to Chippyash\\BuilderPattern\n\n2.0.1 move from coveralls to codeclimate\n\n2.0.2 Add link to packages\n\n2.0.3 Verify PHP7 compatibility\n\n2.0.4 Update build runner\n\n2.0.5 update composer - forced by packagist composer.json format change\n\n3.0.0 BC Break. Withdraw support for older PHP versions\n\n3.1.0 Change of license from GPL V3 to BSD 3 Clause","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchippyash%2Fbuilder-pattern","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchippyash%2Fbuilder-pattern","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchippyash%2Fbuilder-pattern/lists"}