{"id":15287283,"url":"https://github.com/addiks/symfony_rdm","last_synced_at":"2025-04-13T05:08:13.732Z","repository":{"id":54816627,"uuid":"116869683","full_name":"addiks/symfony_rdm","owner":"addiks","description":"Helps with the use of domain driven design \u0026 rich domain model in symfony / doctrine applications.","archived":false,"fork":false,"pushed_at":"2024-11-12T10:55:01.000Z","size":1519,"stargazers_count":5,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-13T05:08:05.925Z","etag":null,"topics":["doctrine2","domaindrivendesign","orm","php","symfony"],"latest_commit_sha":null,"homepage":null,"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/addiks.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-01-09T20:54:03.000Z","updated_at":"2024-11-12T10:54:56.000Z","dependencies_parsed_at":"2023-11-22T06:26:16.745Z","dependency_job_id":"f29450ef-2d0a-4609-87bc-599aaafd7302","html_url":"https://github.com/addiks/symfony_rdm","commit_stats":{"total_commits":120,"total_committers":3,"mean_commits":40.0,"dds":0.06666666666666665,"last_synced_commit":"fdad2fdea5eac5d7e08e712cf9752c950c2d5d04"},"previous_names":[],"tags_count":67,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/addiks%2Fsymfony_rdm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/addiks%2Fsymfony_rdm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/addiks%2Fsymfony_rdm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/addiks%2Fsymfony_rdm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/addiks","download_url":"https://codeload.github.com/addiks/symfony_rdm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248665747,"owners_count":21142123,"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":["doctrine2","domaindrivendesign","orm","php","symfony"],"created_at":"2024-09-30T15:27:26.365Z","updated_at":"2025-04-13T05:08:13.710Z","avatar_url":"https://github.com/addiks.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"Symfony-RDM – Helper for using the Rich Domain Model in Symfony\n===================================\n\n[![Build Status](https://travis-ci.org/addiks/symfony_rdm.svg?branch=master)](https://travis-ci.org/addiks/symfony_rdm)\n[![Build Status](https://scrutinizer-ci.com/g/addiks/symfony_rdm/badges/build.png?b=master)](https://scrutinizer-ci.com/g/addiks/symfony_rdm/build-status/master)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/addiks/symfony_rdm/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/addiks/symfony_rdm/?branch=master)\n[![Code Coverage](https://scrutinizer-ci.com/g/addiks/symfony_rdm/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/addiks/symfony_rdm/?branch=master)\n\n## What\nThe goal of this project is to enrich the doctrine2-ORM mapping capabilities so that entities do not have to be\ndeveloped *for* doctrine anymore, but make it possible to map **any** object from anywhere to a database using doctrine,\neven if it was not developed for that purpose. It add's a lot of new ways on how data can be mapped from the database to\nan object (and back).\n\nThe currently implemented features are the following:\n - [Load (symfony-) services into entity fields.](Resources/doc/service_mapping.md)\n - [Have a switch (choice) of which mapping to load into a field.](Resources/doc/choice_mapping.md)\n - [Load an array with static keys into a field.](Resources/doc/array_mapping.md)\n - [Load a list with dynamic length containing other mappings.](Resources/doc/list_mapping.md)\n - [Load any object with it's own inner mappings into a field.](Resources/doc/object_mapping.md) (You can map the same class in different ways.)\n - [Have any mapping nullable.](Resources/doc/nullable_mapping.md)\n - [Have a mapping always map to *NULL*.](Resources/doc/null_mapping.md)\n - [Import mapping from another file.](Resources/doc/import_mapping.md)\n\nEach of these can be combined with any other, allowing for extremely dynamic ORM mapping capabilities.\n\n## How\nIt hooks into the events of doctrine and hydrates the marked fields with the described values.\nThere are multiple ways of defining which mappings should be in what fields of the services:\nPer annotations, YAML, XML, PHP or Static PHP. YAML-Mapping is not fully implemented yet and may be removed soon.\n\nI would suggest you to use the XML (or YAML) mapping because entities should be framework-agnostic. I personally prefer\nXML over YAML because with XML you at least have a schemata while with yaml you often have to guess what keys are\nallowed, what all the keys mean and who actually uses them. For more detauls see the linked documentations above.\n\n## Setup\nTo enable this functionality first install the project via composer (symfony normally comes with composer) using the\nfollowing command: **composer require addiks/symfony_rdm**\n\nThen [register the bundle in your symfony-application][1].\nPrior to symfony-4.0 this is done in the file \"app/AppKernel.php\" inside the method \"registerBundles\". From 4.0 onwards\nthis is done in the file \"config/bundles.php\". (If you know how to automate this, please let me know.)\n\n[1]: http://symfony.com/doc/current/bundles.html\n\nSymfony 2.x \u0026 3.x:\n\n```php\n// app/AppKernel.php\npublic function registerBundles()\n{\n    $bundles = array(\n        new Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle(),\n        # ...\n        new Addiks\\RDMBundle\\AddiksRDMBundle(), # \u003c== Add this line\n        new AppBundle\\AppBundle(),\n    );\n\n    …\n\n    return $bundles;\n}\n```\n\nSymfony \u003e= 4.0:\n\n```php\n// config/bundles.php\nreturn [\n    // 'all' means that the bundle is enabled for any Symfony environment\n    Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle::class =\u003e ['all' =\u003e true],\n    …\n    Addiks\\RDMBundle\\AddiksRDMBundle::class =\u003e ['all' =\u003e true], # \u003c== Add this line\n\n];\n```\n\nAfter that this bundle should work. If not create an issue here and provide as much details about the environment this\nis being used in, i may be able to help.\n\n## Two ways of retrieving data: safe or fast\nUsing this extension to extend the ORM mapping of doctrine entities can (depending on the ORM mapping configuration) introduce new database\ncolumns that doctrine would normally not know about. When loading or storing the data for these additional columns, there are two ways to\ninteract with them:\n\n### The safe but slow method\nThe safe but slow way to deal with these additional database columns is to load them one by one outside of doctrine, every time an entity\nis hydrated and store (UPDATE / INSERT) all modified entities in the database when the doctrine entity-manager is flushed.\nThis is safer as the faster approach because everything happens outside of doctrine's scope and changes to doctrine or other doctrine-\nplugins cannot interfere with the functionality of the loading and storing process. At the same time this approach is slower - often even\nMUCH slower - then the faster approach because now we may need to execute one extra select statement for every hydrated entity.\n**This can have a serious performance impact!**\nNevertheless, this is the default approach because while being slower, it is also the safer approach.\n\n### The fast but instable way\nThe alternative of loading and storing all data from and to the database outside of doctrine via extra SELECT statements is to let doctrine\nload and store these data for us in doctrine's own mechanisms. This way the performance is (nearly) the same as if these columns were\nnative doctrine columns, no extra SELECT, UPDATE or INSERT statements need to be executed. The problematic part of this solution is that\nfor this to work, we need to make doctrine aware of all these additional database columns so that doctrine can handle them for us\n**without** having doctrine actually using these data during it's own hydration of the entities. These are database-columns but **not**\nentity fields. If doctrine would try to map these columns to the entity fields on it's own, it would fail because they have no corresponding\nentity-fields by doctrines own logic. To prevent this from happening, this approach hooks deep into doctrine's own reflection mechanisms\nand fakes these entitiy-fields for doctrine. From doctrines point of view, these fields on the entities actually exist even if they are\nfake. This construct of hooking deep within doctrine makes a lot of assumptions about the internals of doctrine.\n**If any of these assumptions fail (because either doctrine changes them in a new version or another extension changes them) then this\nextension could fail to work properly!**\nBecause of this instability /  uncertainty, this method is not default but opt-in. To use this method you must define a symfony service\nparameter called `addiks_rdm.data_loader.stability` and set it to `fast-and-unstable`.\n\n`app/config/config.yml`:\n```\nparameters:\n    addiks_rdm.data_loader.stability: 'fast-and-unstable'\n```\n\nAfter that, you should also call a setup function named `symfony_rdm_composer_hook` in your entry scripts (`index.php`,\n`bin/console`, `app.php`, `app_dev.php`, ...) after composers `vendor/autoload.php` was included and after the symfony\nkernel was created. The composer `vendor/autoload.php` file returnes the class-loader object, this should be passed\ntogether with the symfony kernel to the mentioned function.\n\nExample:\n\n```php\n# ...\nuse Composer\\Autoload\\ClassLoader;\nuse function Addiks\\SymfonyRDM\\symfony_rdm_composer_hook;\n# ...\n/** @var ClassLoader $loader */\n$loader = require('/vendor/autoload.php');\n# ...\n$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);\n# ...\nsymfony_rdm_composer_hook($loader, $kernel);\n# ...\n```\n\nThis function `symfony_rdm_composer_hook` is declared in a file `composer_hook.php` in this projects root folder.\nUnder normal circumstances, this file should always be included automatically by composer. If not, you might get an\nerror message that this function is unknown. In this case, you might (temporarely) include that file manually:\n\n```php\nrequire_once('vendor/addiks/symfony_rdm/composer_hook.php');\n```\n\n## Service-FormType\nThis bundle also provides an additional new form-type called \"ServiceFormType\" which should prove valuable in\nconjunction with the service-hydration-abilities of this bundle. It allows to specify a list of service-id's as choices\nthat can be selected between in a form and the selected being set on the entity.\n\n```php\n\u003c?php\n\nuse Addiks\\RDMBundle\\Symfony\\FormType\\ServiceFormType;\n\nclass MyEntityFormType extends AbstractType\n{\n    public function buildForm(FormBuilderInterface $builder, array $options)\n    {\n        $builder-\u003eadd(\"someField\", ServiceFormType::class, [\n            'required' =\u003e false,\n            'choices' =\u003e [\n                'app.example_services.foo' =\u003e 'foo',\n                'app.example_services.bar' =\u003e 'bar',\n            ]\n        ]);\n    }\n    …\n}\n```\n\n## The future\n\nThis project may be extended with more features in the future, here are some ideas i have:\n\n- Allow object-decoration (custom proxy-objects) in, on and between entities.\n- Allow to use simple arrays instead of doctrine collection objects [or even custom collections.][4]\n- Inject service-container-parameters into entities (similar to services).\n- Re-use data from one column in multiple fields (maybe even across multiple entities).\n- [Generare non-object values from generator-services (or other routines) to be hydrated into unmapped fields][5]\n- [Populate fields with aggregated data from the database.][6]\n- Allow custom (non-generated) proxy-classes for final entities.\n\n[4]: https://stackoverflow.com/questions/3691943\n[5]: https://stackoverflow.com/questions/35414300\n[6]: https://stackoverflow.com/questions/26968809\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faddiks%2Fsymfony_rdm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faddiks%2Fsymfony_rdm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faddiks%2Fsymfony_rdm/lists"}