{"id":15732325,"url":"https://github.com/stopsopa/jms-serializer-lite","last_synced_at":"2025-03-31T03:25:49.514Z","repository":{"id":57060180,"uuid":"69496742","full_name":"stopsopa/jms-serializer-lite","owner":"stopsopa","description":"Simple library to easy dump/serialize objects/arrays from db to make them ready to expose through RESTful API - one direction","archived":false,"fork":false,"pushed_at":"2023-09-02T00:03:49.000Z","size":45,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-06T08:13:09.272Z","etag":null,"topics":["dumper","jms","json-feed","serializer","toarray"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stopsopa.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":"2016-09-28T19:28:48.000Z","updated_at":"2023-09-02T00:03:55.000Z","dependencies_parsed_at":"2024-10-24T23:17:24.714Z","dependency_job_id":null,"html_url":"https://github.com/stopsopa/jms-serializer-lite","commit_stats":{"total_commits":25,"total_committers":4,"mean_commits":6.25,"dds":0.64,"last_synced_commit":"2a2a162f44aeae27d8c1fd0f75f24ecddb93c5aa"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stopsopa%2Fjms-serializer-lite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stopsopa%2Fjms-serializer-lite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stopsopa%2Fjms-serializer-lite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stopsopa%2Fjms-serializer-lite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stopsopa","download_url":"https://codeload.github.com/stopsopa/jms-serializer-lite/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246409808,"owners_count":20772554,"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":["dumper","jms","json-feed","serializer","toarray"],"created_at":"2024-10-04T00:08:57.969Z","updated_at":"2025-03-31T03:25:49.494Z","avatar_url":"https://github.com/stopsopa.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/stopsopa/jms-serializer-lite.svg?branch=master)](https://travis-ci.org/stopsopa/jms-serializer-lite)\r\n[![Coverage Status](https://coveralls.io/repos/github/stopsopa/jms-serializer-lite/badge.svg)](https://coveralls.io/github/stopsopa/jms-serializer-lite)\r\n[![Latest Stable Version](https://poser.pugx.org/stopsopa/jms-serializer-lite/v/stable)](https://packagist.org/packages/stopsopa/jms-serializer-lite)\r\n\r\n# DEPRECATED\r\nCreated in 2016 - quite old now and not maintained.\r\n\r\nThat was actually usefull a lot back then. But please don't use it now.\r\n\r\n# Why?\r\n\r\nUsually first choice of library for Symfony 2/3 to dump data from db to provide any RESTful feeds is [jms/serializer](http://jmsyst.com/libs/serializer). This tool is designed to serialize and unserialize data to xml, json, or yml and back to initial data structures. But usually there is need to just provide data into one direction - to json feeds. Additionally usually there is need to serialize the same object in different ways. In jms/serializer and similar complex tools usually you can use \"groups\", unfortunately this solution is not flexible enough to deal with real life situations.\r\n \r\nSo what does this library special do? \r\n\r\nThis library gives you ability to serialize any nested data structures (usually ORM objects) to any array structure, ready to json_encode in simplest possible way, without loosing flexibility and without loosing inheritance to provide new serialization format by changing (overriding) old format. This library is also framework agnostic.\r\n\r\n# Readme\r\n\r\n* [Basic usage](#documentation)\r\n* [Nested entities](#nested-entities)\r\n* [Serialize from different angles](#serialize-from-different-angles)\r\n* [Shorter syntax and helper](#shorter-syntax-and-helper)\r\n  - [Default values](#default-values)\r\n  - [Excluding/Omitting entities](#excludingomitting-entities)\r\n  - [Save keys](#save-keys)\r\n  - [DumperInterface](#dumperinterface)\r\n  - [Force mode](#force-mode)\r\n  - [Scope and stack](#scope-and-stack)\r\n\r\n# Installation\r\n\r\n    composer require stopsopa/jms-serializer-lite\r\n    \r\n\r\n# Documentation\r\n\r\n\r\nWhen You have ORM entities like ...\r\n\r\n    Article:\r\n        id\r\n        title\r\n        content\r\n        comments # \u003cone-to-many with Comment entity\u003e\r\n        \r\n    Comment\r\n        id\r\n        article # \u003cmany-to-one with Article entity\u003e\r\n        user # \u003cmany-to-one with User entity\u003e\r\n        content\r\n        \r\n    User\r\n        id\r\n        login\r\n        name\r\n        surname\r\n        comments # \u003cone-to-many with Comment entity\u003e\r\n        \r\n... and there is need to serialize **Article** to RESTful feed:\r\n\r\n```json        \r\n{\r\n    \"id\": 1,\r\n    \"name\": \"First article\",\r\n    \"body\": \"Content of first article\"\r\n}\r\n```    \r\n    \r\nThe simplest way to start do that using this library is to create simple class (e.g.) **NewDumper** that extends class **Stopsopa\\LiteSerializer\\Dumper** ...\r\n    \r\n```php    \r\n\u003c?php\r\n\r\nnamespace MyProject;\r\n\r\nuse Stopsopa\\LiteSerializer\\Dumper;\r\n\r\nclass NewDumper extends Dumper\r\n{\r\n}\r\n```    \r\n    \r\n... and use it to get array ready to json_encode like ...\r\n    \r\n```php   \r\n$article = $man-\u003efind(...);\r\n\r\n$array = NewDumper::getInstance()-\u003edump($article);\r\n\r\necho json_encode($array, JSON_PRETTY_PRINT);\r\n```   \r\n    \r\nAfter executing this you will end up with error ...\r\n\r\n\r\n![Article exception screen](https://cloud.githubusercontent.com/assets/3743506/19212175/83eb5ac4-8d4c-11e6-8994-fcad60b4fa06.jpg)\r\n\r\n... that means that You need to implement method **dumpMyProject_Article** to \"explain\" new class how to transform entity to flat array ...\r\n\r\n\r\n```php   \r\nnamespace MyProject;\r\n\r\nclass NewDumper extends Dumper\r\n{\r\n    public function dumpMyProject_Article($entity) {\r\n        return array(\r\n            'id'    =\u003e $entity-\u003egetId(),\r\n            'name'  =\u003e $entity-\u003egetTitle(),\r\n            'body'  =\u003e $entity-\u003egetContent()\r\n        );\r\n    }\r\n}\r\n```   \r\n\r\n\r\n... now when You run this code again You will have what You need.\r\n\r\n\r\n## Nested entities\r\n\r\n\r\nTo serialize Article with all it's comments like ...\r\n        \r\n```json  \r\n{\r\n    \"id\": 1,\r\n    \"name\": \"First article\",\r\n    \"body\": \"Content of first article\",\r\n    \"comments\": [\r\n        {\r\n            \"id\": 2,\r\n            \"body\": \"Content of comment 1\"\r\n        },\r\n        {\r\n            \"id\": 1,\r\n            \"body\": \"Content of comment 2\"\r\n        }\r\n    ]\r\n}\r\n```   \r\n    \r\n... simply change method **dumpMyProject_Article** to ...    \r\n        \r\n\r\n\r\n```php   \r\nnamespace MyProject;\r\n\r\nclass NewDumper extends Dumper\r\n{\r\n    public function dumpMyProject_Article($entity) {\r\n        $data = array(\r\n            'id'        =\u003e $entity-\u003egetId(),\r\n            'name'      =\u003e $entity-\u003egetTitle(),\r\n            'body'      =\u003e $entity-\u003egetContent(),\r\n        );\r\n\r\n        $data['comments'] = $this-\u003einnerDump($entity-\u003egetComments());\r\n\r\n        return $data;\r\n    }\r\n}\r\n```    \r\n       \r\n... now when You try to execute it, You will see that **NewDump** require method **dumpMyProject_Comment** ...\r\n\r\n![Comment exception screen](https://cloud.githubusercontent.com/assets/3743506/19212164/554c2644-8d4c-11e6-8a1b-3d2f202cd0a0.jpg)\r\n\r\n\r\n\r\n```php   \r\nnamespace MyProject;\r\n\r\nclass NewDumper extends Dumper\r\n{\r\n    ...\r\n    public function dumpMyProject_Comment($entity) {\r\n        return array(\r\n            'id'        =\u003e $entity-\u003egetId(),\r\n            'body'      =\u003e $entity-\u003egetContent()\r\n        );\r\n    }\r\n}\r\n```    \r\n\r\n... and that's it.\r\n\r\n## Serialize from different angles\r\n\r\nWorth to mention is fact that class prepared above is ready to serialize classes Article and Comment for different use cases ...\r\n\r\n\r\n```php \r\n$dumper = NewDumper::getInstance();\r\n\r\n# to serialize single Article entity\r\n$array = $dumper-\u003edump($article); \r\n# result: {\"id\":1, ... , \"comments\":[...]}\r\n\r\n# to serialize array/collection of Article entities\r\n$array = $dumper-\u003edump(array($article1, $article2, ...));  \r\n# result: [ {\"id\":1, ... , \"comments\":[...] }, {\"id\":2, ... , \"comments\":[...] } ]\r\n\r\n# to serialize single Comment entity\r\n$array = $dumper-\u003edump($comment); \r\n# result: {\"id\":1, ...}\r\n\r\n# to serialize array/collection of Comment entities\r\n$array = $dumper-\u003edump(array($comment1, $comment2, ...));  \r\n# result: [ {\"id\":1, ... }, {\"id\":2, ... } ]        \r\n    \r\n```   \r\n \r\n \r\n## Shorter syntax and helper\r\n\r\n\r\nAll logic explained above can be much more condensed using helper 'toArray':\r\n\r\n\r\n```php\r\nclass NewDumper extends Dumper\r\n{\r\n    public function dumpMyProject_Article($entity) {\r\n        return $this-\u003etoArray($entity, array(\r\n            'id'        =\u003e 'id',\r\n            'name'      =\u003e 'title',\r\n            'body'      =\u003e 'content',\r\n            'comments'  =\u003e 'comments'\r\n        ));\r\n    }\r\n    public function dumpMyProject_Comment($entity) {\r\n        return $this-\u003etoArray($entity, array(\r\n            'id'        =\u003e 'id',\r\n            'body'      =\u003e 'content'\r\n        ));\r\n    }\r\n}   \r\n``` \r\n    \r\n... let's hold for a minute at this code, and try to understand what's going on here.    \r\n\r\n \u0026nbsp; \u0026nbsp; So \"key side\" of array (the left side with '**id**', '**name**', '**body**', '**comments**') is side where we declare keys for result array - that's obvious. \r\n \r\n  \u0026nbsp; \u0026nbsp; Right side (the value side of array with '**id**', '**title**', '**content**', '**comments**') is little more sophisticated. This values are passed to [AbstractEntity-\u003eget()](https://github.com/stopsopa/jms-serializer-lite/blob/master/src/Libs/AbstractEntity.php#L24) method, these are \"paths\" describing how to get values for these keys. See more about [AbstractEntity](https://github.com/stopsopa/jms-serializer-lite/blob/master/doc/AbstractEntity.md) in another page.\r\n\r\n\u0026nbsp;\r\n \r\n \r\n\u003e**Note**: \r\n\u003e\r\n\u003eIt is good idea to read chapter about AbstractEntity before continue reading this documentation.\r\n\r\n\u0026nbsp;\r\n \r\n \r\n#### Default values\r\n \r\n You can also specify default value to prevent throwing AbstractEntityException if path is wrong (wrong i mean if leads to nowhere). But to do that on the right hand side you need to use extended version of options ...\r\n  \r\n```php\r\n\r\npublic function dumpMyProject_Article($entity) {\r\n    return $this-\u003etoArray($entity, array(\r\n        'id'        =\u003e 'id',\r\n        'name'      =\u003e array(\r\n            'path'      =\u003e 'title',\r\n            'default'   =\u003e 'defaultname'            \r\n        ),\r\n    ));\r\n}  \r\n```  \r\n\r\n... so from now on if in object Article field 'title' will be **missing** you won't see Exception but method will return (like nothing happened) value 'defaultname'. \r\n\r\nWhen i say \"**missing**\" it means:\r\n\r\n - **if** $article is an array **OR** if object implements interface ArrayAccess\r\n \r\n    - **if** 'title' is valid key return value\r\n    \r\n - **if** $article is an object\r\n \r\n    - **if** path have postfix '()' look for public method 'title()' explicitely and try to execute it and return value        \r\n    \r\n    - **else** throw AbstractEntityException\r\n        \r\n    - **if** there is public method 'getTitle' execute it and return value\r\n    \r\n    - **else if** there is public method 'isTitle' execute it and return value\r\n    \r\n    - **else if** there is public method 'hasTitle' execute it and return value\r\n    \r\n    - **else if** object has (public or private) property 'title' then return value of this prop.\r\n     \r\n - throw AbstractEntityException because path is wrong, leads to nowhere...\r\n    \r\n... if all above can't reach value then \"**path is wrong**\" and value is **missing** because there is no value under this path. \r\n\r\n\u0026nbsp;\r\n\r\n\u003e**Note:** \r\n\u003e\r\n\u003eEmpty string or null value are still valid values it doesn't mean that path is wrong.\r\n\r\n\u0026nbsp;\r\n\r\nIf there is need to replace [false](http://php.net/manual/en/language.types.boolean.php#language.types.boolean.casting) value by something else it should be done like this:\r\n\r\n\r\n```php\r\nclass NewDumper extends Dumper\r\n{\r\n    public function dumpMyProject_Article($entity) {\r\n        $data = $this-\u003etoArray($entity, array(\r\n            'id'        =\u003e 'id',\r\n            'name'      =\u003e array('title', null), \r\n                # if path 'title' is wrong then \r\n                # return null instead of throw AbstractEntityException\r\n            'body'      =\u003e 'content',\r\n            'comments'  =\u003e 'comments'\r\n        ));\r\n\r\n        if (!$data['name']) {\r\n            $data['name'] = 'default value if here is something false';\r\n        }\r\n\r\n        return $data;\r\n    }\r\n}\r\n```\r\n\r\n#### Excluding/Omitting entities\r\n\r\nSometimes we don't want to have some particular entities in feed. To skip them just throw DumperContinueException: \r\n\r\n```php\r\n\r\nuse Stopsopa\\LiteSerializer\\Exceptions\\DumperContinueException;\r\n\r\nclass NewDumper extends Dumper\r\n{\r\n    public function dumpMyProject_Comment($entity) {\r\n    \r\n        if (!$entity-\u003eisModerated()) {\r\n            throw new DumperContinueException();\r\n        }\r\n        \r\n        return $this-\u003etoArray($entity, array(\r\n            'id'        =\u003e 'id',\r\n            'body'      =\u003e 'content'\r\n        ));\r\n    }\r\n}   \r\n```\r\n\r\n#### Save keys\r\n\r\nBy default dumper don't maintains key association during iteration:\r\n\r\n```php\r\n\r\nnamespace MyProject;\r\n\r\nuse Stopsopa\\LiteSerializer\\Dumper;\r\nuse Stopsopa\\LiteSerializer\\Exceptions\\DumperContinueException;\r\n\r\nclass Group {\r\n    protected $id;\r\n    protected $name;\r\n    public static function getInstance() { return new self(); }\r\n    public function getId() { return $this-\u003eid; }\r\n    public function setId($id) { $this-\u003eid = $id; return $this; }\r\n    public function getName() { return $this-\u003ename; }\r\n    public function setName($name) { $this-\u003ename = $name; return $this; }\r\n}\r\n# extend just to make this example shorter\r\n# the case is that we can build one-to-many relation using this classes\r\nclass User extends Group {\r\n    protected $groups = array();\r\n    public function getGroups() { return $this-\u003egroups; }\r\n    public function setGroups($groups) { $this-\u003egroups = $groups; return $this; }\r\n}\r\n\r\n$user = User::getInstance()-\u003esetId(50)-\u003esetName('user')-\u003esetGroups(array(\r\n    'group-1' =\u003e Group::getInstance()-\u003esetId(10)-\u003esetName('gr 1'),\r\n    'group-2' =\u003e Group::getInstance()-\u003esetId(11)-\u003esetName('gr 2'),\r\n    'group-3' =\u003e Group::getInstance()-\u003esetId(12)-\u003esetName('gr 3'),\r\n));\r\n\r\nclass NewDumper extends Dumper\r\n{\r\n    public function dumpMyProject_User($entity) {\r\n        return $this-\u003etoArray($entity, array(\r\n            'id'        =\u003e 'id',\r\n            'name'      =\u003e 'name',\r\n            'groups'    =\u003e 'groups'\r\n        ));\r\n    }\r\n    public function dumpMyProject_Group($entity) {\r\n        if ($entity-\u003egetName() === 'gr 2') {\r\n            throw new DumperContinueException();\r\n        }\r\n        return $this-\u003etoArray($entity, array(\r\n            'id'        =\u003e 'id',\r\n            'name'      =\u003e 'name'\r\n        ));\r\n    }\r\n}\r\n\r\necho json_encode(NewDumper::getInstance()-\u003edump($user), JSON_PRETTY_PRINT);\r\n```\r\n\r\n... return ...\r\n\r\n```json\r\n{\r\n    \"id\": 50,\r\n    \"name\": \"user\",\r\n    \"groups\": [\r\n        {\r\n            \"id\": 10,\r\n            \"name\": \"gr 1\"\r\n        },\r\n        {\r\n            \"id\": 12,\r\n            \"name\": \"gr 3\"\r\n        }\r\n    ]\r\n}\r\n```\r\n\r\nbut when you change ...\r\n\r\n```php\r\n    ...\r\n    public function dumpMyProject_User($entity) {\r\n        return $this-\u003etoArray($entity, array(\r\n            'id'        =\u003e 'id',\r\n            'name'      =\u003e 'name',\r\n            'groups'    =\u003e array(\r\n                'path' =\u003e 'groups',\r\n                'savekeys' =\u003e true\r\n            )\r\n        ));\r\n    }\r\n    ...\r\n```\r\n \r\n... keys will be maintained ...\r\n \r\n```json\r\n{\r\n    \"id\": 50,\r\n    \"name\": \"user\",\r\n    \"groups\": {\r\n        \"group-1\": {\r\n            \"id\": 10,\r\n            \"name\": \"gr 1\"\r\n        },\r\n        \"group-3\": {\r\n            \"id\": 12,\r\n            \"name\": \"gr 3\"\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n#### DumperInterface\r\n\r\nThere is special interface **Stopsopa\\LiteSerializer\\DumpToArrayInterface**. Implement this interface to declare how to dump entity right in **entity itself**.\r\n \r\n#### Default types serialization (integer, string, float, etc.)\r\n \r\n Anything else that is not array and is not object is serialized by method **dumpPrimitives**. You can easily change way of serializing even such values by overriding this method.\r\n \r\n#### Force mode\r\n \r\nAs you probably noticed everything what is 'foreachable' will be iterated and each element of \"collection\" will be serialized individually. But there is one situation when this behaviour \"can\" (don't must) be wrong. When entity implements interface Traversable and in json feed you need fields that are not accessible through 'foreach' on this class. In such situation would be good to have mechanizm to decide manually if serialize such class in normal mode or let dumper to iterate through. You can achieve this like:\r\n\r\n```php\r\n\r\n    public function dumpMyProject_User($entity) {\r\n        return $this-\u003etoArray($entity, array(\r\n            'id'        =\u003e 'id',\r\n            'name'      =\u003e 'name',\r\n            'order'    =\u003e array(\r\n                'path'     =\u003e 'order',\r\n                'mode'     =\u003e Dumper::MODE_ENTITY # or Dumper::MODE_COLLECTION\r\n                # default is Dumper::MODE_AUTO\r\n            )\r\n        ));\r\n    }\r\n```\r\n\r\n... or You can dump these entity manually (not in 'toArray' method) like:\r\n\r\n```php\r\n\r\n    public function dumpMyProject_User($entity) {\r\n        $data = $this-\u003etoArray($entity, array(\r\n            'id'        =\u003e 'id',\r\n            'name'      =\u003e 'name',\r\n        ));\r\n        \r\n        $tmp = array();\r\n        foreach ($entity-\u003egetOrder() as $o) {\r\n            $tmp[] = array(\r\n                'id'        =\u003e 'id',\r\n                'prise'     =\u003e 'price',\r\n                ...\r\n            );\r\n        }\r\n        $data['order'] = $tmp;\r\n        \r\n        return $data;\r\n    }\r\n```\r\n\r\n... naaa, too long.\r\n\r\n\r\n\r\n#### Scope and stack\r\n\r\nAs we saw higher in documentation ([link](https://github.com/stopsopa/jms-serializer-lite#serialize-from-different-angles)), it is possible to use one dumper class to dump bunch of entities from different perspective. Doing this though sometimes You might want to change way of working individual dumping methods.\r\nFor example if You want to dump article it is good in feed provide also information about user that created this article, but You don't need in this use case all informations about user. But if You will dump User and his all articles it would be good to provide all information about user and less from article. To distinguish these use cases in method itself You can use two private properties available in all methods - scope and stack.\r\n \r\nExample of using 'stack':\r\n \r\n ```php\r\n ...\r\n    public function dumpMyProject_User($entity) {\r\n\r\n        $map = array(\r\n            'id'        =\u003e 'id',\r\n            'name'      =\u003e 'name'\r\n        );\r\n\r\n        if (count($this-\u003estack) \u003c 1) {\r\n            # dump groups of user only if this is feed where\r\n            # user is on higher level of hierarchy\r\n            $map['groups'] = 'groups';\r\n        }\r\n        \r\n        # stack is array and contain more information about where we \r\n        # are in execution stack, inspect this later if You need.\r\n\r\n        return $this-\u003etoArray($entity, $map);\r\n    }\r\n ...\r\n ```\r\n \r\n Example of using 'scope':\r\n \r\n ```php \r\nclass NewDumper extends Dumper\r\n{\r\n    ...\r\n    public function dumpMyProject_User($entity) {\r\n\r\n        $map = array(\r\n            'id'        =\u003e 'id',\r\n            'name'      =\u003e 'name'\r\n        );\r\n\r\n        if ($this-\u003escope === 'dumpalsogroups') {\r\n            $map['groups'] = 'groups';\r\n        }\r\n\r\n        return $this-\u003etoArray($entity, $map);\r\n    }\r\n}\r\n\r\nNewDumper::getInstance()-\u003edumpScope($user, 'dumpalsogroups');\r\n ```\r\n\r\n\r\n \r\n \r\n\r\n\r\n \r\n\r\n\r\n\r\n       \r\n       \r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstopsopa%2Fjms-serializer-lite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstopsopa%2Fjms-serializer-lite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstopsopa%2Fjms-serializer-lite/lists"}