{"action":"created","comment":{"url":"https://api.github.com/repos/silverstripe/silverstripe-framework/pulls/comments/89745899","pull_request_review_id":10281436,"id":89745899,"diff_hunk":"@@ -0,0 +1,399 @@\n+<?php\n+\n+namespace SilverStripe\\Forms;\n+\n+use Exception;\n+use InvalidArgumentException;\n+use SilverStripe\\Assets\\File;\n+use SilverStripe\\Assets\\Storage\\AssetContainer;\n+use SilverStripe\\Core\\Object;\n+use SilverStripe\\ORM\\ArrayList;\n+use SilverStripe\\ORM\\DataObject;\n+use SilverStripe\\ORM\\DataObjectInterface;\n+use SilverStripe\\ORM\\RelationList;\n+use SilverStripe\\ORM\\SS_List;\n+use SilverStripe\\ORM\\UnsavedRelationList;\n+use SilverStripe\\ORM\\ValidationException;\n+\n+/**\n+ * Provides operations for reading and writing uploaded files to/from\n+ * {@see File} dataobject instances.\n+ * Allows writing to a parent record with the following relation types:\n+ *   - has_one\n+ *   - has_many\n+ *   - many_many\n+ * Additionally supports writing directly to the File table not attached\n+ * to any parent record.\n+ *\n+ * @mixin FormField\n+ */\n+trait FileUploadable {\n+\tuse Uploadable;\n+\n+\t/**\n+\t * Flag to automatically determine and save a has_one-relationship\n+\t * on the saved record (e.g. a \"Player\" has_one \"PlayerImage\" would\n+\t * trigger saving the ID of newly created file into \"PlayerImageID\"\n+\t * on the record).\n+\t *\n+\t * @var boolean\n+\t */\n+\tpublic $relationAutoSetting = true;\n+\n+\t/**\n+\t * Parent data record. Will be infered from parent form or controller if blank.\n+\t *\n+\t * @var DataObject\n+\t */\n+\tprotected $record;\n+\n+\t/**\n+\t * Items loaded into this field. May be a RelationList, or any other SS_List\n+\t *\n+\t * @var SS_List\n+\t */\n+\tprotected $items;\n+\n+\tprotected function constructFileUploadable() {\n+\t\t$this->constructUploadable();\n+\t}\n+\n+\n+\t/**\n+\t * Force a record to be used as \"Parent\" for uploaded Files (eg a Page with a has_one to File)\n+\t *\n+\t * @param DataObject $record\n+\t * @return $this\n+\t */\n+\tpublic function setRecord($record) {\n+\t\t$this->record = $record;\n+\t\treturn $this;\n+\t}\n+\t/**\n+\t * Get the record to use as \"Parent\" for uploaded Files (eg a Page with a has_one to File) If none is set, it will\n+\t * use Form->getRecord() or Form->Controller()->data()\n+\t *\n+\t * @return DataObject\n+\t */\n+\tpublic function getRecord() {\n+\t\tif ($this->record) {\n+\t\t\treturn $this->record;\n+\t\t}\n+\t\tif (!$this->getForm()) {\n+\t\t\treturn null;\n+\t\t}\n+\n+\t\t// Get record from form\n+\t\t$record = $this->getForm()->getRecord();\n+\t\tif ($record && ($record instanceof DataObject)) {\n+\t\t\t$this->record = $record;\n+\t\t\treturn $record;\n+\t\t}\n+\n+\t\t// Get record from controller\n+\t\t$controller = $this->getForm()->getController();\n+\t\tif ($controller\n+\t\t\t&& $controller->hasMethod('data')\n+\t\t\t&& ($record = $controller->data())\n+\t\t\t&& ($record instanceof DataObject)\n+\t\t) {\n+\t\t\t$this->record = $record;\n+\t\t\treturn $record;\n+\t\t}\n+\n+\t\treturn null;\n+\t}\n+\n+\n+\t/**\n+\t * Loads the related record values into this field. This can be uploaded\n+\t * in one of three ways:\n+\t *\n+\t *  - By passing in a list of file IDs in the $value parameter (an array with a single\n+\t *    key 'Files', with the value being the actual array of IDs).\n+\t *  - By passing in an explicit list of File objects in the $record parameter, and\n+\t *    leaving $value blank.\n+\t *  - By passing in a dataobject in the $record parameter, from which file objects\n+\t *    will be extracting using the field name as the relation field.\n+\t *\n+\t * Each of these methods will update both the items (list of File objects) and the\n+\t * field value (list of file ID values).\n+\t *\n+\t * @param array $value Array of submitted form data, if submitting from a form\n+\t * @param array|DataObject|SS_List $record Full source record, either as a DataObject,\n+\t * SS_List of items, or an array of submitted form data\n+\t * @return $this Self reference\n+\t * @throws ValidationException\n+\t */\n+\tpublic function setValue($value, $record = null) {","path":"src/Forms/FileUploadable.php","position":null,"original_position":128,"commit_id":"5532293c66d57eeb80f8b2e73f72c86a266a3b8d","original_commit_id":"7943c0cdf175876aac6bf6232d690b2ce2b542dc","user":{"login":"tractorcow","id":936064,"avatar_url":"https://avatars.githubusercontent.com/u/936064?v=3","gravatar_id":"","url":"https://api.github.com/users/tractorcow","html_url":"https://github.com/tractorcow","followers_url":"https://api.github.com/users/tractorcow/followers","following_url":"https://api.github.com/users/tractorcow/following{/other_user}","gists_url":"https://api.github.com/users/tractorcow/gists{/gist_id}","starred_url":"https://api.github.com/users/tractorcow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tractorcow/subscriptions","organizations_url":"https://api.github.com/users/tractorcow/orgs","repos_url":"https://api.github.com/users/tractorcow/repos","events_url":"https://api.github.com/users/tractorcow/events{/privacy}","received_events_url":"https://api.github.com/users/tractorcow/received_events","type":"User","site_admin":false},"body":"Yes, hence the division between fileuplodable / uploadable. :)\r\n\r\nThe best I could do is to maybe split out \"uploadable\" into an adjacent trait, rather than a nested one. However, you would still need to manually `use` it everywhere you used `FileUploadable`, so I don't see much of a use case where it would be of benefit.","created_at":"2016-11-28T09:45:56Z","updated_at":"2016-11-28T09:45:56Z","html_url":"https://github.com/silverstripe/silverstripe-framework/pull/6325#discussion_r89745899","pull_request_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/pulls/6325","_links":{"self":{"href":"https://api.github.com/repos/silverstripe/silverstripe-framework/pulls/comments/89745899"},"html":{"href":"https://github.com/silverstripe/silverstripe-framework/pull/6325#discussion_r89745899"},"pull_request":{"href":"https://api.github.com/repos/silverstripe/silverstripe-framework/pulls/6325"}}},"pull_request":{"url":"https://api.github.com/repos/silverstripe/silverstripe-framework/pulls/6325","id":94744225,"html_url":"https://github.com/silverstripe/silverstripe-framework/pull/6325","diff_url":"https://github.com/silverstripe/silverstripe-framework/pull/6325.diff","patch_url":"https://github.com/silverstripe/silverstripe-framework/pull/6325.patch","issue_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/issues/6325","number":6325,"state":"open","locked":false,"title":"API Refactor UploadField, FileField and AssetField into traits","user":{"login":"tractorcow","id":936064,"avatar_url":"https://avatars.githubusercontent.com/u/936064?v=3","gravatar_id":"","url":"https://api.github.com/users/tractorcow","html_url":"https://github.com/tractorcow","followers_url":"https://api.github.com/users/tractorcow/followers","following_url":"https://api.github.com/users/tractorcow/following{/other_user}","gists_url":"https://api.github.com/users/tractorcow/gists{/gist_id}","starred_url":"https://api.github.com/users/tractorcow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tractorcow/subscriptions","organizations_url":"https://api.github.com/users/tractorcow/orgs","repos_url":"https://api.github.com/users/tractorcow/repos","events_url":"https://api.github.com/users/tractorcow/events{/privacy}","received_events_url":"https://api.github.com/users/tractorcow/received_events","type":"User","site_admin":false},"body":"This is done in preparation for a new FileField which will be used within react, provided by the silverstripe/asset-admin module.\r\n\r\nBehaviour which handled the upload of user-submitted files has been refactored into an \"Uploadable\" trait.\r\n\r\nAdditional behaviour which handled the upload of user-submitted files, specifically for saving into File dataobjects within has_one / has_many / many_many relations has been refactored into FileUploadable, which extends this base trait.\r\n\r\nAssetField and UploadField now no longer extend FileField, but instead directly extend FormField, and have the necessary traits.\r\n","created_at":"2016-11-22T03:57:52Z","updated_at":"2016-11-28T09:45:56Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ae8832f9fd6292f759c37fc83bf71323095ca201","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/pulls/6325/commits","review_comments_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/pulls/6325/comments","review_comment_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/pulls/comments{/number}","comments_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/issues/6325/comments","statuses_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/statuses/5532293c66d57eeb80f8b2e73f72c86a266a3b8d","head":{"label":"open-sausages:pulls/4.0/uploadfield","ref":"pulls/4.0/uploadfield","sha":"5532293c66d57eeb80f8b2e73f72c86a266a3b8d","user":{"login":"open-sausages","id":12824172,"avatar_url":"https://avatars.githubusercontent.com/u/12824172?v=3","gravatar_id":"","url":"https://api.github.com/users/open-sausages","html_url":"https://github.com/open-sausages","followers_url":"https://api.github.com/users/open-sausages/followers","following_url":"https://api.github.com/users/open-sausages/following{/other_user}","gists_url":"https://api.github.com/users/open-sausages/gists{/gist_id}","starred_url":"https://api.github.com/users/open-sausages/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/open-sausages/subscriptions","organizations_url":"https://api.github.com/users/open-sausages/orgs","repos_url":"https://api.github.com/users/open-sausages/repos","events_url":"https://api.github.com/users/open-sausages/events{/privacy}","received_events_url":"https://api.github.com/users/open-sausages/received_events","type":"Organization","site_admin":false},"repo":{"id":37888247,"name":"silverstripe-framework","full_name":"open-sausages/silverstripe-framework","owner":{"login":"open-sausages","id":12824172,"avatar_url":"https://avatars.githubusercontent.com/u/12824172?v=3","gravatar_id":"","url":"https://api.github.com/users/open-sausages","html_url":"https://github.com/open-sausages","followers_url":"https://api.github.com/users/open-sausages/followers","following_url":"https://api.github.com/users/open-sausages/following{/other_user}","gists_url":"https://api.github.com/users/open-sausages/gists{/gist_id}","starred_url":"https://api.github.com/users/open-sausages/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/open-sausages/subscriptions","organizations_url":"https://api.github.com/users/open-sausages/orgs","repos_url":"https://api.github.com/users/open-sausages/repos","events_url":"https://api.github.com/users/open-sausages/events{/privacy}","received_events_url":"https://api.github.com/users/open-sausages/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/open-sausages/silverstripe-framework","description":"SilverStripe Framework, the MVC framework that powers SilverStripe CMS","fork":true,"url":"https://api.github.com/repos/open-sausages/silverstripe-framework","forks_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/forks","keys_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/keys{/key_id}","collaborators_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/teams","hooks_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/hooks","issue_events_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/issues/events{/number}","events_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/events","assignees_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/assignees{/user}","branches_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/branches{/branch}","tags_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/tags","blobs_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/git/refs{/sha}","trees_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/git/trees{/sha}","statuses_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/statuses/{sha}","languages_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/languages","stargazers_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/stargazers","contributors_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/contributors","subscribers_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/subscribers","subscription_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/subscription","commits_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/commits{/sha}","git_commits_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/git/commits{/sha}","comments_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/comments{/number}","issue_comment_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/issues/comments{/number}","contents_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/contents/{+path}","compare_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/compare/{base}...{head}","merges_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/merges","archive_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/downloads","issues_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/issues{/number}","pulls_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/pulls{/number}","milestones_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/milestones{/number}","notifications_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/labels{/name}","releases_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/releases{/id}","deployments_url":"https://api.github.com/repos/open-sausages/silverstripe-framework/deployments","created_at":"2015-06-23T00:36:38Z","updated_at":"2015-06-23T00:36:43Z","pushed_at":"2016-11-28T09:32:15Z","git_url":"git://github.com/open-sausages/silverstripe-framework.git","ssh_url":"git@github.com:open-sausages/silverstripe-framework.git","clone_url":"https://github.com/open-sausages/silverstripe-framework.git","svn_url":"https://github.com/open-sausages/silverstripe-framework","homepage":"http://silverstripe.org/","size":95401,"stargazers_count":0,"watchers_count":0,"language":"PHP","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":0,"forks":1,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"silverstripe:master","ref":"master","sha":"1be2e70a2a5d08cc4a6eae055c40ec7a2331d4be","user":{"login":"silverstripe","id":379348,"avatar_url":"https://avatars.githubusercontent.com/u/379348?v=3","gravatar_id":"","url":"https://api.github.com/users/silverstripe","html_url":"https://github.com/silverstripe","followers_url":"https://api.github.com/users/silverstripe/followers","following_url":"https://api.github.com/users/silverstripe/following{/other_user}","gists_url":"https://api.github.com/users/silverstripe/gists{/gist_id}","starred_url":"https://api.github.com/users/silverstripe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/silverstripe/subscriptions","organizations_url":"https://api.github.com/users/silverstripe/orgs","repos_url":"https://api.github.com/users/silverstripe/repos","events_url":"https://api.github.com/users/silverstripe/events{/privacy}","received_events_url":"https://api.github.com/users/silverstripe/received_events","type":"Organization","site_admin":false},"repo":{"id":1318892,"name":"silverstripe-framework","full_name":"silverstripe/silverstripe-framework","owner":{"login":"silverstripe","id":379348,"avatar_url":"https://avatars.githubusercontent.com/u/379348?v=3","gravatar_id":"","url":"https://api.github.com/users/silverstripe","html_url":"https://github.com/silverstripe","followers_url":"https://api.github.com/users/silverstripe/followers","following_url":"https://api.github.com/users/silverstripe/following{/other_user}","gists_url":"https://api.github.com/users/silverstripe/gists{/gist_id}","starred_url":"https://api.github.com/users/silverstripe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/silverstripe/subscriptions","organizations_url":"https://api.github.com/users/silverstripe/orgs","repos_url":"https://api.github.com/users/silverstripe/repos","events_url":"https://api.github.com/users/silverstripe/events{/privacy}","received_events_url":"https://api.github.com/users/silverstripe/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/silverstripe/silverstripe-framework","description":"SilverStripe Framework, the MVC framework that powers SilverStripe CMS","fork":false,"url":"https://api.github.com/repos/silverstripe/silverstripe-framework","forks_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/forks","keys_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/keys{/key_id}","collaborators_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/teams","hooks_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/hooks","issue_events_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/issues/events{/number}","events_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/events","assignees_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/assignees{/user}","branches_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/branches{/branch}","tags_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/tags","blobs_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/git/refs{/sha}","trees_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/git/trees{/sha}","statuses_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/statuses/{sha}","languages_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/languages","stargazers_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/stargazers","contributors_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/contributors","subscribers_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/subscribers","subscription_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/subscription","commits_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/commits{/sha}","git_commits_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/git/commits{/sha}","comments_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/comments{/number}","issue_comment_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/issues/comments{/number}","contents_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/contents/{+path}","compare_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/compare/{base}...{head}","merges_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/merges","archive_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/downloads","issues_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/issues{/number}","pulls_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/pulls{/number}","milestones_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/milestones{/number}","notifications_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/labels{/name}","releases_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/releases{/id}","deployments_url":"https://api.github.com/repos/silverstripe/silverstripe-framework/deployments","created_at":"2011-02-02T02:04:13Z","updated_at":"2016-11-18T01:35:31Z","pushed_at":"2016-11-28T08:13:57Z","git_url":"git://github.com/silverstripe/silverstripe-framework.git","ssh_url":"git@github.com:silverstripe/silverstripe-framework.git","clone_url":"https://github.com/silverstripe/silverstripe-framework.git","svn_url":"https://github.com/silverstripe/silverstripe-framework","homepage":"http://silverstripe.org/","size":124956,"stargazers_count":533,"watchers_count":533,"language":"PHP","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":628,"mirror_url":null,"open_issues_count":678,"forks":628,"open_issues":678,"watchers":533,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/silverstripe/silverstripe-framework/pulls/6325"},"html":{"href":"https://github.com/silverstripe/silverstripe-framework/pull/6325"},"issue":{"href":"https://api.github.com/repos/silverstripe/silverstripe-framework/issues/6325"},"comments":{"href":"https://api.github.com/repos/silverstripe/silverstripe-framework/issues/6325/comments"},"review_comments":{"href":"https://api.github.com/repos/silverstripe/silverstripe-framework/pulls/6325/comments"},"review_comment":{"href":"https://api.github.com/repos/silverstripe/silverstripe-framework/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/silverstripe/silverstripe-framework/pulls/6325/commits"},"statuses":{"href":"https://api.github.com/repos/silverstripe/silverstripe-framework/statuses/5532293c66d57eeb80f8b2e73f72c86a266a3b8d"}}}}
{"actor":{"display_login":"tractorcow"}}