{"id":12274,"date":"2010-03-20T01:42:50","date_gmt":"2010-03-19T23:42:50","guid":{"rendered":"https:\/\/mamchenkov.net\/wordpress\/?p=12274"},"modified":"2011-05-08T00:24:57","modified_gmt":"2011-05-07T22:24:57","slug":"cakephp-graphviz-making-sense-of-a-numerous-models","status":"publish","type":"post","link":"https:\/\/mamchenkov.net\/wordpress\/2010\/03\/20\/cakephp-graphviz-making-sense-of-a-numerous-models\/","title":{"rendered":"CakePHP + GraphViz = making sense of a numerous models"},"content":{"rendered":"<!-- google_ad_section_start -->\n<p><strong>NOTE: THIS IS VERY MUCH OUTDATED! <a href=\"https:\/\/mamchenkov.net\/wordpress\/2011\/05\/08\/cakephp-graphviz-models\/\">Read about the update<\/a> or go directly to <a href=\"https:\/\/github.com\/mamchenkov\/CakePHP-GraphViz-Models\">GitHub repository<\/a> for the new version.<\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>I have a task at hand.\u00a0 I have to re-introduce myself to a rather large codebase.\u00a0 It&#8217;s a project that migrated to <a href=\"http:\/\/cakephp.org\/\">CakePHP<\/a> a couple of years ago and haven&#8217;t seen since.\u00a0 There was a whole team of people working on it sense then, and now I need to make sense of all those changes that were done and help reorganize and refactor them a bit.\u00a0 When I looked into CakePHP&#8217;s models\/ folder, I was surprised to find 50+ models there.\u00a0 Each and every one of them links to other models.\u00a0 And documentation is practically non-existing.\u00a0 How do I go about it?\u00a0 I hack up a little script to help me out.<\/p>\n<p>There is a really elegant and beautiful tool for graphing things &#8211; <a href=\"http:\/\/www.graphviz.org\/\">GraphViz<\/a>.\u00a0 If you haven&#8217;t heard of it, you need to drop whatever is that you are doing and familiarize yourself with GraphViz.\u00a0 Right now.\u00a0 Right.\u00a0 This. Second.\u00a0 You are missing out a whole universe until you do so.\u00a0 I&#8217;ll wait.<\/p>\n<p>Now that you are back, I just want to mention a very slick tool, which is a part of GraphViz package &#8211; <strong>dot<\/strong>.\u00a0 It is a simple language in which you can describe graphs.\u00a0 Sort of like &#8220;A goes to B, which goes to C&#8221;.\u00a0\u00a0 You specify your graph in a very human readable format in a text file, and then dot will transform that text file into an image format of your choice (PNG, JPEG, GIF, etc).\u00a0 The primary beauty of this is that those text files can be generated automatically by using pretty much any programming language.<\/p>\n<p>So here is what I did.\u00a0 I assumed the following:<\/p>\n<ol>\n<li>Project documentation should be in app\/docs\/ folder.\u00a0 That&#8217;s where I&#8217;ll put the script and that&#8217;s where it will generate the dot configuration, dot later will generate the graph of all my models and their relationships.<\/li>\n<li>Main project application folder is app\/.\u00a0 Models are stored in app\/models\/ folder.<\/li>\n<li>Project can have a number of plugins, which can have their own models, which I still want to know about.\u00a0 Plugins are in app\/plugins\/ and if plugin xyz has models, they are stored in app\/plugins\/xyz\/models.<\/li>\n<li>My project is under version control.\u00a0 Specifically I use Subversion, but it&#8217;s easy to adjust the script to support other systems.<\/li>\n<li>I can get current project revision by running a command in shell.\u00a0 For Subversion that is \/usr\/bin\/svnversion.<\/li>\n<\/ol>\n<p>I probably assumed a whole bunch of other things, but you can get an idea of how simple the setup is from the above ones.<\/p>\n<p>Here is how I generate a graph of all models and their dependencies:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ncd app\/docs\/\r\nphp -f graph.php &gt; graph.dot\r\ndot -Tpng graph.dot &gt; graph.png\r\n<\/pre>\n<p>Obviously, I can&#8217;t show you the full graph from that system (it&#8217;s not open source, it&#8217;s not mine, and it will drive you insane in a matter of seconds), but here is how a small part of that image looks like.<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" data-attachment-id=\"12275\" data-permalink=\"https:\/\/mamchenkov.net\/wordpress\/2010\/03\/20\/cakephp-graphviz-making-sense-of-a-numerous-models\/graph\/\" data-orig-file=\"https:\/\/i0.wp.com\/mamchenkov.net\/wordpress\/wp-content\/uploads\/2010\/03\/graph.png?fit=500%2C203&amp;ssl=1\" data-orig-size=\"500,203\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"Graph\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/mamchenkov.net\/wordpress\/wp-content\/uploads\/2010\/03\/graph.png?fit=500%2C203&amp;ssl=1\" class=\"aligncenter size-full wp-image-12275\" title=\"Graph\" src=\"https:\/\/i0.wp.com\/mamchenkov.net\/wordpress\/wp-content\/uploads\/2010\/03\/graph.png?resize=500%2C203&#038;ssl=1\" alt=\"\" width=\"500\" height=\"203\" srcset=\"https:\/\/i0.wp.com\/mamchenkov.net\/wordpress\/wp-content\/uploads\/2010\/03\/graph.png?w=500&amp;ssl=1 500w, https:\/\/i0.wp.com\/mamchenkov.net\/wordpress\/wp-content\/uploads\/2010\/03\/graph.png?resize=300%2C121&amp;ssl=1 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<p>There is a different colour for each type of model relationship ($belongsTo, $hasMany, and $hasAndBelongsToMany).  Each model folder is in a separate sub-graph cluster.  There is a legend graph on the image.  The current time stamp and version control revision are also imposed on the image for easier referencing.<\/p>\n<p>And here is the source for the graph.php script.  Feel free to modify any way you like.  If you spot any major bugs or better ways of doing things, please let me know in the comments.<\/p>\n<p><!--more--><\/p>\n<p><strong>Update (March 20, 2010)<\/strong>: Due to the complexity of the graph and model relationships at hand, I failed to see that the graph wasn&#8217;t quite accurate.  With some free time on my hands today, I fixed a few problems and reorganized the code.  Even though it&#8217;s a few lines longer, the whole thing is much simpler now.  And more accurate.<\/p>\n<p><strong>Update (March 22, 2010)<\/strong>: Added missing support for hasOne relationships.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n&lt;?php\r\n\/**\r\n * Generate a graph of model dependencies for CakePHP application\r\n *\r\n * Usage:\r\n *\r\n * $ php -f graph.php &gt; graph.dot &amp;&amp; dot -Tpng graph.dot &gt; graph.png\r\n *\r\n * Explanation:\r\n *\r\n * The script generates a description of all model relationships in dot format (GraphViz).  All models\r\n * are considered, both in app\/models\/ folder and in all app\/plugins\/SOMETHING\/models\/ folders.\r\n *\r\n * Note:\r\n *\r\n * The script relies on being in app\/docs\/ folder.  If you place it anywhere else, don't forget to\r\n * correct the paths in constants below.\r\n *\r\n * TODO:\r\n *\r\n * - Rewrite GraphViz part using the GraphViz PEAR module\r\n * - Fix models that fall outside cluster due to aliasing (e.g.: $belongsTo =&gt; array('Owner' =&gt; array('className'=&gt;'User')))\r\n *\r\n * @author Leonid Mamchenkov &lt;leonid@mamchenkov.net&gt;\r\n *\/\r\n\r\ndefine('PATH_TO_APP_MODELS', '\/..\/models');\r\ndefine('PATH_TO_PLUGINS', '\/..\/plugins');\r\ndefine('PATH_TO_SVNVERSION', '\/usr\/bin\/svnversion');\r\ndefine('UNKNOWN_REVISION', 'Unknown');\r\n\r\n\/**\r\n * Graph settings for each type of relationship.  Consult dot language documentation for more details.\r\n *\/\r\n$relationSettings = array(\r\n\t\t\t\t\t'belongsTo' =&gt; array('dir'=&gt;'forward', 'color'=&gt;'green'),\r\n\t\t\t\t\t'hasOne' =&gt; array('dir'=&gt;'forward', 'color'=&gt;'magenta'),\r\n\t\t\t\t\t'hasMany' =&gt; array('dir'=&gt;'forward', 'color'=&gt;'blue'),\r\n\t\t\t\t\t'hasAndBelongsToMany' =&gt; array('dir'=&gt;'both', 'color'=&gt;'red'),\r\n);\r\n\r\n\/**\r\n * Empty Model class is needed to bypass fatal errors when loading models, since we don't\r\n * load the full CakePHP architecture.\r\n *\/\r\nclass Model {\r\n}\r\n\r\n\/**\r\n * Find model paths based on current location\r\n *\r\n * @return array\r\n *\/\r\nfunction getModelsDirs() {\r\n\t$result = array();\r\n\r\n\t\/\/ app\/models\r\n\t$result&#x5B;] = realpath(dirname(__FILE__) . PATH_TO_APP_MODELS);\r\n\r\n\t\/\/ plugins\r\n\t$pluginsDir = new DirectoryIterator(realpath(dirname(__FILE__) . PATH_TO_PLUGINS));\r\n\tforeach ($pluginsDir as $fileInfo) {\r\n\t\tif ($fileInfo-&gt;isDot()) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tif ($fileInfo-&gt;isDir()) {\r\n\t\t\t$modelDir = $fileInfo-&gt;getPathname() . '\/models';\r\n\t\t\tif (is_dir($modelDir)) {\r\n\t\t\t\t$result&#x5B;] = $modelDir;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn $result;\r\n}\r\n\r\n\/**\r\n * Get model name based on file name\r\n *\r\n * @param object $fileInfo\r\n * @return string\r\n *\/\r\nfunction getModelName($fileInfo) {\r\n\t$result = ucfirst(preg_replace('\/\\.php$\/i', '', $fileInfo-&gt;getFilename()));\r\n\r\n\treturn $result;\r\n}\r\n\r\n\/**\r\n * Check if filename follows the model naming convention\r\n *\r\n * @param object $fileInfo\r\n * @return boolean\r\n *\/\r\nfunction isValidModel($fileInfo) {\r\n\t$result = false;\r\n\tif (preg_match('\/^&#x5B;A-z0-9]+\\.php$\/', $fileInfo-&gt;getFilename())) {\r\n\t\t$result = true;\r\n\t}\r\n\treturn $result;\r\n}\r\n\r\n\/**\r\n * Get two characters to use as targets in the legend\r\n *\r\n * @param string $last Last-used character\r\n * @return array\r\n *\/\r\nfunction getTargets($last = null) {\r\n\tif (! $last) {\r\n\t\t$last = '@'; \/\/ Next ASCII table character is A\r\n\t}\r\n\t$first = chr(ord($last) + 1);\r\n\t$second = chr(ord($last) + 2);\r\n\r\n\treturn array($first, $second);\r\n}\r\n\r\n\/**\r\n * Convert an array of settings into dot string\r\n *\r\n * @param array $settings Associative array of settings\r\n * @return string\r\n *\/\r\nfunction prepareSettings($settings) {\r\n\t$result = '';\r\n\r\n\tforeach ($settings as $key =&gt; $value) {\r\n\t\t$result .= sprintf(&quot;%s=\\&quot;%s\\&quot;, &quot;, $key, $value);\r\n\t}\r\n\t$result = preg_replace('\/,\\s$\/', '', $result);\r\n\tif ($result) {\r\n\t\t$result = &quot;&#x5B;$result]&quot;;\r\n\t}\r\n\r\n\treturn $result;\r\n}\r\n\r\n\/**\r\n * Generate a relation string in dot format\r\n *\r\n * @param string $from Source node\r\n * @param string $to Destination node\r\n * @param array $settings Array of edge settings\r\n *\/\r\nfunction prepareRelation($from, $to, $settings) {\r\n\t$result = '';\r\n\r\n\t$settingsString = prepareSettings($settings);\r\n\t$result = sprintf(&quot;\\t%s -&gt; %s %s;\\n&quot;, $from, $to, $settingsString);\r\n\r\n\treturn $result;\r\n}\r\n\r\n\/**\r\n * Generate a node string in dot format\r\n *\r\n * @param string $node Node name\r\n * @param array $settings Array of node settings\r\n *\/\r\nfunction prepareNode($node, $settings) {\r\n\t$result = '';\r\n\r\n\t$settingsString = prepareSettings($settings);\r\n\t$result = sprintf(&quot;\\t%s %s;\\n&quot;, $node, $settingsString);\r\n\r\n\treturn $result;\r\n}\r\n\r\n\/**\r\n * Find out the current revision of the project\r\n *\r\n * @return string Revision string or UNKNOWN_REVISION if failed to determine\r\n *\/\r\nfunction getRevision() {\r\n\t$result = UNKNOWN_REVISION;\r\n\r\n\tif (is_executable(PATH_TO_SVNVERSION)) {\r\n\t\t$result = trim(shell_exec(PATH_TO_SVNVERSION));\r\n\t}\r\n\r\n\treturn $result;\r\n}\r\n\r\n\/**\r\n * Print graph header\r\n *\/\r\nfunction printGraphHead() {\r\n\tprint &quot;digraph models {\\n&quot;;\r\n\tprint &quot;\\tlabel=\\&quot;Model relationships (Date: &quot; . date('Y-m-d H:i:s') . &quot;, SVN: &quot; . getRevision() . &quot;)\\&quot;;\\n&quot;;\r\n\tprint &quot;\\tlabelloc=\\&quot;t\\&quot;;\\n&quot;;\r\n}\r\n\r\n\/**\r\n * Print graph footer\r\n *\/\r\nfunction printGraphTail() {\r\n\tprint &quot;}\\n&quot;;\r\n}\r\n\r\n\/**\r\n * Print graph legend\r\n *\r\n * @param array $relationSettings Show sample nodes with relations and explanations on the graph\r\n *\/\r\nfunction printGraphLegend($relationSettings) {\r\n\tprint &quot;\\tsubgraph clusterLegend {\\n&quot;;\r\n\tprint &quot;\\t\\tlabel=\\&quot;Legend\\&quot;;\\n&quot;;\r\n\tprint &quot;\\t\\tstyle=\\&quot;filled\\&quot;;\\n&quot;;\r\n\t$second = '';\r\n\tforeach ($relationSettings as $type =&gt; $settings) {\r\n\t\t$settings&#x5B;'label'] = $type;\r\n\t\tlist($first, $second) = getTargets($second);\r\n\t\tprint &quot;\\t&quot; . prepareRelation($first, $second, $settings);\r\n\t}\r\n\tprint &quot;\\t}\\n&quot;;\r\n\r\n}\r\n\r\n\/**\r\n * Print node clusters in dot format\r\n *\r\n * To avoid misplacing nodes, first we generate a cluster for each model\r\n * location and put all models from that location as nodes of this cluster.\r\n *\r\n * @param array $modelsList Array with models\r\n *\/\r\nfunction printNodeClusters($modelsList) {\r\n\tforeach ($modelsList as $parent =&gt; $models) {\r\n\r\n\t\t\/\/ Generate a cluster subgraph for each model path (app\/models, plugin\/*\/models)\r\n\t\tprint &quot;\\tsubgraph cluster$parent {\\n&quot;;\r\n\t\tprint &quot;\\t\\tlabel=\\&quot;$parent\\&quot;;\\n&quot;;\r\n\r\n\t\tasort($models, SORT_STRING);\r\n\t\tforeach ($models as $modelName) {\r\n\t\t\tprint &quot;\\t\\t&quot; . prepareNode($modelName, array());\r\n\t\t}\r\n\t\tprint &quot;\\t}\\n&quot;;\r\n\t}\r\n}\r\n\r\n\/**\r\n * Print node relations in dot format\r\n *\r\n * @param array $relationData Array with relations data\r\n * @param array $relationSettings Array with relation settings\r\n *\/\r\nfunction printNodeRelations($relationData, $relationSettings) {\r\n\tforeach ($relationData as $parent =&gt; $models) {\r\n\r\n\t\tforeach ($models as $modelName =&gt; $relations) {\r\n\t\t\tforeach ($relations as $type =&gt; $targets) {\r\n\t\t\t\tforeach ($targets as $targetModel) {\r\n\t\t\t\t\tprint prepareRelation($modelName, $targetModel, $relationSettings&#x5B;$type]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\n\/\/ Gather data\r\n\r\n$relationData = array();\r\n$modelsList = array();\r\n$modelsDirs = getModelsDirs();\r\nforeach ($modelsDirs as $modelsDir) {\r\n\t$dir = new DirectoryIterator($modelsDir);\r\n\r\n\t\/\/ load AppModel or plugins' AppModel\r\n\t$parentDir = dirname($modelsDir);\r\n\t$parentDirRelative = basename($parentDir);\r\n\tif ($parentDirRelative == 'app') {\r\n\t\tif (file_exists($parentDir . '\/app_model.php')) {\r\n\t\t\trequire_once $parentDir . '\/app_model.php';\r\n\t\t}\r\n\t\telse {\r\n\t\t\tclass AppModel {\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\telse {\r\n\t\t$pluginAppModel = $parentDir . '\/' . $parentDirRelative . '_app_model.php';\r\n\t\tif (file_exists($pluginAppModel)) {\r\n\t\t\trequire_once $pluginAppModel;\r\n\t\t}\r\n\t}\r\n\r\n\tforeach ($dir as $fileInfo) {\r\n\t\tif (! isValidModel($fileInfo)) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t$modelFile = $fileInfo-&gt;getPathname();\r\n\t\trequire_once $modelFile;\r\n\t\t$modelName = getModelName($fileInfo);\r\n\r\n\t\t\/\/ The fact that we had the file doesn't necessarily mean that we have a model defined in it\r\n\t\tif (! class_exists($modelName)) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t$modelObject = new $modelName();\r\n\t\t$modelsList&#x5B;$parentDirRelative]&#x5B;] = $modelName;\r\n\r\n\t\tforeach ($relationSettings as $relationName =&gt; $settings) {\r\n\t\t\tif (!empty($modelObject-&gt;$relationName) &amp;&amp; is_array($modelObject-&gt;$relationName)) {\r\n\t\t\t\t$relationData&#x5B;$parentDirRelative]&#x5B;$modelName]&#x5B;$relationName] = array_keys($modelObject-&gt;$relationName);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\n\/\/ Print out the graph\r\nprintGraphHead();\r\nprintGraphLegend($relationSettings);\r\nprintNodeClusters($modelsList);\r\nprintNodeRelations($relationData, $relationSettings);\r\nprintGraphTail();\r\n\r\n?&gt;\r\n<\/pre>\n<!-- google_ad_section_end -->\n","protected":false},"excerpt":{"rendered":"<!-- google_ad_section_start -->\n<p>NOTE: THIS IS VERY MUCH OUTDATED! Read about the update or go directly to GitHub repository for the new version. &nbsp; I have a task at hand.\u00a0 I have to re-introduce myself to a rather large codebase.\u00a0 It&#8217;s a project that migrated to CakePHP a couple of years ago and haven&#8217;t seen since.\u00a0 There was &hellip; <a href=\"https:\/\/mamchenkov.net\/wordpress\/2010\/03\/20\/cakephp-graphviz-making-sense-of-a-numerous-models\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">CakePHP + GraphViz = making sense of a numerous models<\/span><\/a><\/p>\n<!-- google_ad_section_end -->\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_links_to":"","_links_to_target":""},"categories":[1,18],"tags":[1537,1559,1312,2276,38],"keyring_services":[],"class_list":["post-12274","post","type-post","status-publish","format-standard","hentry","category-general","category-programming","tag-cakephp","tag-databases","tag-graphs","tag-graphviz","tag-php"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":14838,"url":"https:\/\/mamchenkov.net\/wordpress\/2011\/05\/08\/cakephp-graphviz-models\/","url_meta":{"origin":12274,"position":0},"title":"CakePHP GraphViz Models","author":"Leonid Mamchenkov","date":"May 8, 2011","format":false,"excerpt":"I have completely and totally rewritten my old script that generates a graph of CakePHP models and their relationships. \u00a0Instead of pasting the code in here, I pushed all of its development to GitHub where it now enjoys a new repository. \u00a0Please have a look, try it out, and let\u2026","rel":"","context":"In &quot;All&quot;","block_context":{"text":"All","link":"https:\/\/mamchenkov.net\/wordpress\/category\/general\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":14845,"url":"https:\/\/mamchenkov.net\/wordpress\/2011\/05\/08\/day-in-brief\/","url_meta":{"origin":12274,"position":1},"title":"Day in brief","author":"Leonid Mamchenkov","date":"May 8, 2011","format":false,"excerpt":"GitHub: mamchenkov pushed to master at mamchenkov\/CakePHP-GraphViz-Models http:\/\/bit.ly\/itj7OI # GitHub: mamchenkov pushed to master at mamchenkov\/CakePHP-GraphViz-Models http:\/\/bit.ly\/mBMhZm # GitHub: mamchenkov pushed to master at mamchenkov\/CakePHP-GraphViz-Models http:\/\/bit.ly\/kDo9Rf # GitHub: mamchenkov merged pull request 1 on mamchenkov\/CakePHP-GraphViz-Models http:\/\/bit.ly\/kgmSF7 # I'm at Limassol Municipality Garden (Limassol) http:\/\/4sq.com\/ljqm0f # I'm at Kirzis Center (Emmanoil\u2026","rel":"","context":"In &quot;All&quot;","block_context":{"text":"All","link":"https:\/\/mamchenkov.net\/wordpress\/category\/general\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":14837,"url":"https:\/\/mamchenkov.net\/wordpress\/2011\/05\/07\/day-in-brief\/","url_meta":{"origin":12274,"position":2},"title":"Day in brief","author":"Leonid Mamchenkov","date":"May 7, 2011","format":false,"excerpt":"GitHub: mamchenkov created branch master at mamchenkov\/CakePHP-GraphViz-Models http:\/\/bit.ly\/mmbn2E # GitHub: mamchenkov created repository CakePHP-GraphViz-Models http:\/\/bit.ly\/mw9J0o # I'm at Carrefour http:\/\/4sq.com\/jPuyNd #","rel":"","context":"In &quot;All&quot;","block_context":{"text":"All","link":"https:\/\/mamchenkov.net\/wordpress\/category\/general\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":27276,"url":"https:\/\/mamchenkov.net\/wordpress\/2017\/01\/30\/generate-php-class-inheritance-diagrams-with-graphviz\/","url_meta":{"origin":12274,"position":3},"title":"Generate PHP Class Inheritance Diagrams with Graphviz","author":"Leonid Mamchenkov","date":"January 30, 2017","format":false,"excerpt":"It's not a secret that I'm a big fan of GraphViz\u00a0- powerful, yet easy to use graph visualization software. \u00a0And I've blog about it quite a few times. \u00a0Well, guess what - today is a perfect day for one more post. Over the weekend I was working on refactoring some\u2026","rel":"","context":"In &quot;All&quot;","block_context":{"text":"All","link":"https:\/\/mamchenkov.net\/wordpress\/category\/general\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/mamchenkov.net\/wordpress\/wp-content\/uploads\/2017\/01\/class-hierarchy-500x269.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":28449,"url":"https:\/\/mamchenkov.net\/wordpress\/2018\/03\/26\/php-object-graph-visualizer\/","url_meta":{"origin":12274,"position":4},"title":"PHP object graph visualizer","author":"Leonid Mamchenkov","date":"March 26, 2018","format":false,"excerpt":"koriym\/print_o is an object graph visualizer for PHP.\u00a0 Here's a Wikipedia answer to the question of \"What is an object graph?\": Object-oriented applications contain complex webs of interrelated objects. Objects are linked to each other by one object either owning or containing another object or holding a reference to another\u2026","rel":"","context":"In &quot;All&quot;","block_context":{"text":"All","link":"https:\/\/mamchenkov.net\/wordpress\/category\/general\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/mamchenkov.net\/wordpress\/wp-content\/uploads\/2018\/03\/object-graph-500x259.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":28182,"url":"https:\/\/mamchenkov.net\/wordpress\/2017\/11\/06\/object-graph-visualizing-php-objects\/","url_meta":{"origin":12274,"position":5},"title":"object-graph &#8211; visualizing PHP objects","author":"Leonid Mamchenkov","date":"November 6, 2017","format":false,"excerpt":"As you might know, I am a big fan of GraphViz.\u00a0 I've used numerous times for visualizing different parts of the project code and dependencies (see here and here for example). Today I came across a way to visualize PHP objects (not just classes) - object-graph library by Sebastian Bergmann,\u2026","rel":"","context":"In &quot;All&quot;","block_context":{"text":"All","link":"https:\/\/mamchenkov.net\/wordpress\/category\/general\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/mamchenkov.net\/wordpress\/wp-content\/uploads\/2017\/11\/object-graph-500x136.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]}],"jetpack_sharing_enabled":true,"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/posts\/12274","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/comments?post=12274"}],"version-history":[{"count":0,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/posts\/12274\/revisions"}],"wp:attachment":[{"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/media?parent=12274"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/categories?post=12274"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/tags?post=12274"},{"taxonomy":"keyring_services","embeddable":true,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/keyring_services?post=12274"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}