{"id":19773924,"url":"https://github.com/badoo/jira-client","last_synced_at":"2025-04-10T01:16:20.071Z","repository":{"id":35162901,"uuid":"214408889","full_name":"badoo/jira-client","owner":"badoo","description":"Badoo JIRA API Client with code generator","archived":false,"fork":false,"pushed_at":"2024-02-12T10:45:34.000Z","size":134,"stargazers_count":67,"open_issues_count":7,"forks_count":18,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-10T01:16:15.566Z","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":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/badoo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","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":"2019-10-11T10:31:42.000Z","updated_at":"2025-02-25T12:37:38.000Z","dependencies_parsed_at":"2023-01-15T15:05:36.178Z","dependency_job_id":"2dd9a0c7-0e43-4ccb-8e86-404667b1fb79","html_url":"https://github.com/badoo/jira-client","commit_stats":{"total_commits":34,"total_committers":9,"mean_commits":"3.7777777777777777","dds":0.6470588235294117,"last_synced_commit":"2fe6735201af8ce126fd09d226468f0aa4460e6b"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badoo%2Fjira-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badoo%2Fjira-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badoo%2Fjira-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badoo%2Fjira-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/badoo","download_url":"https://codeload.github.com/badoo/jira-client/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248137891,"owners_count":21053775,"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-12T05:11:32.355Z","updated_at":"2025-04-10T01:16:20.053Z","avatar_url":"https://github.com/badoo.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"* [Introduction](#introduction)\n* [Quick start](#quick-start)\n  * [Install](#install)\n  * [Initialize the client](#initialize-the-client)\n  * [Create new issue](#create-new-issue)\n  * [Get existing issue](#get-the-issue)\n  * [Update existing issue](#update-the-issue)\n  * [Delete exiting issue](#delete-the-issue)\n* [Documentation](#documentation)\n  * [Client and ClientRaw](#client-and-clientraw)\n  * [\\Badoo\\Jira\\Issue class](#badoojiraissue-class)\n  * [Custom fields](#custom-fields)\n  * [Issue changelog](#issue-changelog)\n  * [Other instances](#other-instances-of-the-badoo-jira-api-client)\n* [Advanced topics](#advanced-topics)\n  * [Managing API requests](#managing-api-requests)\n  * [Extending \\Badoo\\Jira\\Issue](#extending-badoojiraissue)\n  * [Writing new CustomField base class](#writing-your-own-custom-field-base-class)\n\n\n# Introduction\n\nThis is Badoo JIRA REST Client. It contains a bunch of wrapper classes for most common API objects:\nIssues, Components and so on.\n\nThis makes code easier to write because of autocompletion your IDE will provide you.\n\nYou can also generate lots of classes for custom fields to get the documentation for your own JIRA installation\nright in PHP code.\n\n\n# Quick start\n\n## Install\n\n```bash\ncomposer require badoo/jira-client\n```\n\n## Initialize the client\n\n```php\n$Jira = \\Badoo\\Jira\\REST\\Client::instance();\n$Jira\n    -\u003esetJiraUrl('https://jira.example.com/')\n    -\u003esetAuth('user', 'token/password');\n```\n\n## Create new issue\n\n```php\n$Request = new \\Badoo\\Jira\\Issue\\CreateRequest('SMPL', 'Task');\n\n$Request\n    -\u003esetSummary('Awesome issue!')\n    -\u003esetDescription('description of issue created by Badoo JIRA PHP client')\n    -\u003esetLabels(['hey', 'it_works!'])\n    -\u003eaddComponent('Other');\n\n$Issue = $Request-\u003esend();\n\nprint_r(\n    [\n        'key'           =\u003e $Issue-\u003egetKey(),\n        'summary'       =\u003e $Issue-\u003egetSummary(),\n        'description'   =\u003e $Issue-\u003egetDescription(),\n    ]\n);\n```\n\n## Get the issue\n\n```php\n$Issue = new \\Badoo\\Jira\\Issue('SMPL-1');\n\nprint_r(\n    [\n        'key'           =\u003e $Issue-\u003egetKey(),\n        'summary'       =\u003e $Issue-\u003egetSummary(),\n        'description'   =\u003e $Issue-\u003egetDescription(),\n    ]\n);\n```\n\n## Update the issue\n\n```php\n$Issue\n    -\u003esetSummary('Awesome issue!')\n    -\u003esetDescription('Yor new description for issue')\n    -\u003eedit('customfield_12345', \u003cvalue for field\u003e);\n\n$Issue-\u003esave();\n```\n\n## Delete the issue\n\n```php\n$Issue = new \\Badoo\\Jira\\Issue('SMPL-1');\n$Issue-\u003edelete();\n```\n\n# Documentation\n\n\u003e NOTE: all examples in this documentation related to any interaction with JIRA consider you configured 'global'\n\u003e client object.\n\u003e\n\u003e Read [Configure the client](#configure-the-client) section above to know how to do that.\n\n## Client and ClientRaw\n\nThe client to JIRA API is split into two parts:\n\n#### The simplest interface to API: \\Badoo\\Jira\\REST\\ClientRaw\n\nIt can request API and parse responses.\nThrows an `\\Badoo\\Jira\\REST\\Exception` for API errors or parsed response data when everything went OK.\n\nThat's all, it has no other complex logic inside: you decide what URI to request, which type of HTTP request to send\n(GET, POST, etc.) and what parameters to send.\n\nConsider ClientRaw as a smart wrapper for PHP curl.\n\n```php\n$RawClient = new \\Badoo\\Jira\\REST\\ClientRaw('https://jira.example.com');\n$RawClient-\u003esetAuth('user', 'token/password');\n\n$fields = $RawClient-\u003eget('/field');\nprint_r($fields);\n```\n\n#### Structured client \\Badoo\\Jira\\REST\\Client\n\nIt is split into several sections, one for each prefix of API methods: e.g. /issue, /field, /project and so on.\nEach section has bindings to the  most popular API methods with parameters it accepts.\n\nThe idea is free you from remembering URIs and HTTP request types for common actions. It enables your IDE to give you a\nhint about available API methods and the options you can provide to each.\n\nSome of sections also cache API responses and have special 'synthetic' methods for most common actions. For example,\nyou can't get info on particular field by its ID using only API. You have also search through the response.\nBut with `\\Badoo\\Jira\\REST\\Client` you can do this\n\n```php\n$Client = new \\Badoo\\Jira\\REST\\Client('https://jira.example.com/');\n$Client-\u003esetAuth('user', 'password/token');\n\n$FieldInfo = $Client-\u003efield()-\u003eget('summary');\nprint_r($FieldInfo);\n```\n\nWhen you can't find something in structured client, you still can access Raw client inside it to do everything you need:\n```php\n$Client = \\Badoo\\Jira\\REST\\Client::instance();\n$response = $Client-\u003egetRawClient()-\u003eget('/method/you/wat/to/request', [\u003cparameters]);\n```\n\nThe structured client also has a 'global' client object. This object can be accessed via instance() static method:\n```php\n$Client = \\Badoo\\Jira\\REST\\Client::instance();\n```\nUnder the hood is 'new \\Badoo\\Jira\\REST\\Client()', but ::instance() will always return you the same\nobject for all calls to method.\n\nAlmost all wrapper classes inside `\\Badoo\\Jira` library require a configured API client to work.\nIt is always received as the last parameter of any static method or constructor of wrapper and it always defaults to\n'global' client when the value was not provided.\n\nOnce you configured the global client you don't need to give API client to all wrappers you initialize.\nThey will get it by themselves.\n\n```php\n\\Badoo\\Jira\\REST\\Client::instance()\n    -\u003esetJiraUrl('https://jira.example.com')\n    -\u003esetAuth('user', 'password/token');\n```\n\n\u003e NOTE: all following examples in documentation, related to any interaction with JIRA, consider you configured 'global'\n\u003e client object. That is why we don't pass initialized JIRA API Client to all Issue, CustomField and other objects.\n\nThe only reason we left the way to provide API client to all wrappers as a parameter is to enable you to interact with\nseveral JIRA installations from one piece of code. For example, if you want to work with your staging and production\ninstances at the same time:\n\n```php\n$Prod = new \\Badoo\\Jira\\REST\\Client('https://jira.example.com/');\n$Prod-\u003esetAuth('user', 'password/token');\n\n$Staging = new \\Badoo\\Jira\\REST\\Client('https://staging.jira.example.com/');\n$Staging-\u003esetAuth('user', 'password/token');\n\n$ProdIssue = new \\Badoo\\Jira\\Issue('SMPL-1', $Prod);\n$StagingIssue = new \\Badoo\\Jira\\Issue('SMPL-1', $Staging);\n\n// ...\n```\n\n## \\Badoo\\Jira\\Issue class\n\n### Getting \\Badoo\\Jira\\Issue instances\n\nTo get an issue object you can create it providing only an issue key.\n\n```php\n$Issue = new \\Badoo\\Jira\\Issue('SMPL-1');\n```\n\nThis is equivalent to:\n```php\n$Client = \\Badoo\\Jira\\REST\\Client::instance();\n$Issue = new \\Badoo\\Jira\\Issue('SMPL-1', $Client);\n```\n\nIf you want, you can instantiate another API client and provide it to `\\Badoo\\Jira\\Issue` constructor.\nThis might be useful when you have several JIRA instances and want to work with them from single piece of code.\nLook at [Client and ClientRaw](#client-and-clientraw) section of documentation to see how to configure instance of API client.\n\n### Updating the issue\n\n`\\Badoo\\Jira\\Issue` object accumulates changes for fields in internal properties. This means, none of changes you did with\nyour $Issue object will be applied to real JIRA issue until you call -\u003esave(). This allows you to update issue\nin compact way, putting several field changes into a single API request. $Issue object will also continue to return old\nfield values until you send changes to JIRA with -\u003esave().\n\n```php\n$Issue = new \\Badoo\\Jira\\Issue('SMPL-1');\n$Issue\n    -\u003esetSummary('new summary')\n    -\u003esetDescription('new description')\n    -\u003eedit('customfield_12345', 'new custom field value');\n\n$Issue-\u003egetSummary(); // will return old issue summary, not the one you tried to set 3 lines of code ago\n\n$Issue-\u003esave(); // makes API request to JIRA, updates all 3 fields you planned\n\n$Issue-\u003egetSummary(); // will return new issue summary, as expected\n```\n\n### Checking if we can edit the field\n\nNot all fields can be changed even if you have them displayed in fields list.\nThis can be caused by project permissions or issue edit screen configuration. To check if current user can update\nfield through API, use `-\u003eisEditable();`\n\n```php\n$Issue = new \\Badoo\\Jira\\Issue('SMPL-1');\nif ($Issue-\u003eisEditable('summary')) {\n    // we can edit summary\n} else {\n    // we can't edit summary\n}\n```\n\n### Initializing \\Badoo\\Jira\\Issue object on partial fields data\n\nYou also can create `\\Badoo\\Jira\\Issue` object on data that contains only some fields. For example, you store in your DB\nsome issues info for your own reasons: key, summary, and description. You can create `\\Badoo\\Jira\\Issue` object on this\ndata without breaking the object logic: it still will load data from API when you need it.\n\n```php\n// Consider you get this data from your database:\n$db_data = [\n    'key' =\u003e 'SMPL-1',\n    'summary' =\u003e 'summary of example issue',\n    'description' =\u003e 'description of example issue',\n];\n\n// First, create an \\stdClass object to mimic API response:\n$IssueInfo = new \\stdClass();\n$IssueInfo-\u003ekey = $db_data['key'];\n\n$IssueInfo-\u003efields = new \\stdClass();\n$IssueInfo-\u003efields-\u003esummary = $db_data['summary'];\n$IssueInfo-\u003efields-\u003edescription = $db_data['description'];\n\n// Now we can create an issue object. It will store key, summary and description field values in internal cache\n// When you need some additional data, e.g. creation time or assignee - object will still load it from API on demand.\n$Issue = \\Badoo\\Jira\\Issue::fromStdClass($IssueInfo, ['key', 'summary', 'description']);\n```\n\n## Custom fields\n\nYou can generate a custom field with special generator stored in this repositroy.\nFor more information follow `CFGenerator` subdirectory and open README.md file.\nYou will find both quickstart and detailed documentation on generator there.\n\nIn this section we consider you already created a class for regular custom field,\navailable out of the box in JIRA:\n'Checkboxes', 'Number Field', 'Radio Buttons', 'Select List (single choice)' and so on.\n\nLet's consider you created custom field class (or classes) inside `\\Example\\CustomField` namespace.\n\n### Field value: get, check, set\n\n```php\n$MyCustomField = \\Example\\CustomFields\\MyCustomField::forIssue('SMPL-1'); // get field value from JIRA API\n\n$field_value = $MyCustomField-\u003egetValue();\n$field_is_empty = $Value-\u003eisEmpty(); // true when field has no value\n\nif ($Value-\u003eisEditable()) {\n    $MyCustomField-\u003esetValue($MyCustomField::VALUE_AWESOME); // consider this is a select field\n    $MyCustomField-\u003esave(); // send API request to update field value in JIRA\n}\n```\n\n### Several custom fields on single issue\n\nWhen you need to work with several custom fields of the same issue, it is a better practice to use single $Issue object\nfor it:\n\n```php\n$Issue = new \\Badoo\\Jira\\Issue('SMPL-1');\n\n$MyCustomField1 = new \\Example\\CustomFields\\MyCustomField1($Issue);\n$MyCustomField2 = new \\Example\\CustomFields\\MyCustomField2($Issue);\n\n$MyCustomField1-\u003esetValue('value of first field');\n$MyCustomField2-\u003esetValue('value of second field');\n\n$Issue-\u003esave();\n```\n\n## Issue changelog\n\nChangelog of issue has the following structure:\n```\n    - changelog record 1 (issue update event 1)\n        - changelog item 1 (field 1 changed)\n        - changelog item 2 (field 2 changed)\n        - ...\n    - changelog record 2 (issue update event 2)\n        - changelog item 1 (field 1 changed)\n        - ...\n```\n\nThere is a special `\\Badoo\\Jira\\History` class designed to work with this data.\nIt uses its own wrappers for each piece of information from changelog:\n\n```\n\\Badoo\\Jira\\Issue\\History\n    \\Badoo\\Jira\\Issue\\HistoryRecord[]\n        \\Badoo\\Jira\\Issue\\LogRecordItem[]\n```\n\n### Getting issue's history of changes\n\nIf you already have an issue object to work with, just use `-\u003egetHistory()` method:\n\n```php\n$Issue = new \\Badoo\\Jira\\Issue('SMPL-1');\n\n$History = $Issue-\u003egetHistory();\n```\n\nWhen you have none, just create an object using static method:\n```php\n$History = \\Badoo\\Jira\\Issue\\History::forIssue('SMPL-1');\n```\n\nHistory class has some useful methods to help you solve most common tasks:\n- track field changes,\n- calculate time in statuses,\n- get last change of issue,\n- get last change of specific issue field,\n- ...and so on\n\nDiscover it's methods using your IDE autocompletion, they might be useful!\n\n## Other instances of the Badoo JIRA API Client\n\nMost of the wrapper classes, e.g. User, Status, Priority and so on, have ability to transparently load data from API on\ndemand.\n\nAs for CustomFields and Issue objects, you have 2 ways of initialization: with static methods (e.g. `::get()`)\nand regular constructor:\n\n```php\n$User = new \\Badoo\\Jira\\User(\u003cuser name\u003e);\n\n$User = \\Badoo\\Jira\\User::byEmail(\u003cuser email\u003e);\n```\n\nMost of them have shorthand static methods:\n\n```php\n$users = \\Badoo\\Jira\\User::search(\u003cpattern\u003e); // looks for all users with login, email or display name similar to pattern\n$Version = \\Badoo\\Jira\\Version::byName(\u003cproject\u003e, \u003cversion name\u003e); // looks for version with specific name in project\n$components = \\Badoo\\Jira\\Component::forProject(\u003cproject\u003e); // lists all components available in project\n```\n\nNames of this methods have similar structure. For convenience we decided to follow next convention:\n\n* _::search()_ static methods are about multi-criteria search of instances.\n  This is applicable, e.g. for `\\Badoo\\Jira\\Issue::search()` where you use complex JQL queries and\n  `\\Badoo\\Jira\\User::search()` where JIRA looks through several user attributes trying to find you a user.\n* _::get()_ static methods are about getting a single object by its ID with immediate request to API inside method.\n  This allows you to control where exactly you will get the `\\Badoo\\Jira\\REST\\Exception` on API errors if you need it.\n* _::by\u003cCriteria\u003e()_ static methods provide you with single or multiple objects identified by some single criteria.\n\n  Example:\n  * \\Badoo\\Jira\\User::byEmail() gives you a JIRA User by its email\n  * \\Badoo\\Jira\\Version::byName() gives you a JIRA Version by its name.\n* _::for\u003cInstance\u003e()_ static methods look for all items somehow related to Instance.\n\n  Example:\n  * `\\Badoo\\Jira\\CustomField::forIssue()` gives you a custom field object related to an issue\n  * `\\Badoo\\Jira\\Version::forProject()` gives you all versions created in specific project\n\n* _::fromStdClass()_ method is used by all wrapper classes for initialization on data from API.\n  If you got some information from API with specific request using, say, `\\Badoo\\Jira\\REST\\ClientRaw`,\n  you still can operate with typed objects instead of raw \\stdClass' ones\n\n  Example:\n  ```php\n  $PriorityInfo = \\Badoo\\Jira\\REST\\ClientRaw::instance()-\u003eget('priority/\u003cpriority ID\u003e');\n  $Priority = \\Badoo\\Jira\\Issue\\Priority::fromStdClass($PriorityInfo);\n  ```\n\nThe classes who work as active records and know not only how to load data from API, but also how to set it, use\nthe same behaviour as `\\Badoo\\Jira\\Issue` uses: they accumulate changes within object and push them to API only on\n`-\u003esave()` method call.\n\n# Advanced topics\n\n## Managing API requests\n\nOnce $Issue object is created with 'new' instruction - it has only issue key and client inside.\nIt will load data only when you try to get some field for the first time:\n\n```php\n$Issue = new \\Badoo\\Jira\\Issue('SMPL-1'); // no request to API here, just an empty object is returned\n$Issue-\u003egetSummary(); // causes request to JIRA API\n```\n\nWhen $Issue object loads data from API by himself, it does not select the fields to load.\nThis increases API response time and loads lots of data which is not required 'right now' for getting issue's summary,\nbut \\Badoo\\Jira\\Issue has no idea how many additional -\u003eget\u003cField\u003e() calls it will get,\nso it is better to load all info once, than ask API many times, when you need the summary, then the description, status,\npriority and so on.\n\nWe compared the time it takes the JIRA to load the data and send it to the client (see examples/measure-load-time.php).\nIt may vary from installation to installation, but almost always (as far as we know - always) the 'get all fields'\nrequest will be more effective than 3 'get single field' requests and frequently it will be more effective than 2 ones.\n\n```text\nGet single field time: 0.42949662208557\nGet all fields time: 0.84061505794525\n```\n\nYou can make it do the API call immediately after new instance creation by using one of class' static methods:\n```php\n$Issue = \\Badoo\\Jira\\Issue::byKey('SMPL-1'); // causes request to JIRA API\n$Issue-\u003egetSummary(); // no request here, object already has all the data on issue\n```\n\nThe only thing `\\Badoo\\Jira\\Issue` manages inside is 'expand'. JIRA API allows you to request various portions of\ninformation for issue, controlled by 'expand' parameter.\nE.g. in most cases you don't need rendered HTML code of fields, or issue changelog.\nThis data will not be loaded by `\\Badoo\\Jira\\Issue` by default when you call -\u003eget\u003cField\u003e().\nOnly default data provided by JIRA API will be loaded.\n\nWhen you need an issue history, `\\Badoo\\Jira\\Issue` object _has_ to request API once again to get it.\nIt will also provide object with updated fields information and you will get updated summary, description and so on\nif they changed since the last call to API.\n\nIn most cases, when you work with a single issue, you don't need to bother yourself with this internal logic\nof `\\Badoo\\Jira\\Issue` class, but understanding is required to manage API requests in an effective way when you\nstart to work with lots of issues at the same time:\nyou can choose several ways of Issue objects initialization and this will\nhave different side effects on API requests amount and effectiveness.\n\nFor example, if you know you need only summary and description for lots of issues, you can request only them.\nThis will dramatically reduce the time of API response:\n```php\n// load only summary and description for the latest 1000 issues in project 'SMPL'.\n$issues = \\Badoo\\Jira\\Issue::search('project = SMPL ORDER BY issuekey DESC', ['summary', 'description']);\n\nforeach($issues as $Issue) {\n    $Issue-\u003egetDescription(); // this will not make \\Badoo\\Jira\\Issue to silently request JIRA API in background\n\n    $Issue-\u003egetPriority(); // but this - will. $Issue object has no status information in cache.\n}\n```\n\nIssue history can be quite hard to load for JIRA. It affects API response time significantly,\nespecially when you have long changelogs.\nThis is the thing you also can optimize by telling `\\Badoo\\Jira\\Issue` what do you need:\n```php\n// load latest 100 issues from project 'SMPL'\n$issues = \\Badoo\\Jira\\Issue::search(\n    'project = SMPL ORDER BY issuekey DESC',\n    [],\n    [\\Badoo\\Jira\\REST\\Section\\Issue::EXP_CHANGELOG],\n    100\n);\n\nforeach ($issues as $Issue) {\n    $description = $Issue-\u003egetDescription(); // this will not cause API request\n    $status_changes = $Issue-\u003egetHistory()-\u003etrackField('status'); // this will not cause API request too!\n}\n```\n\nUnfortunately, you can't use both $fields and $expand parameters at the same time.\nThis is because of internal logic of `\\Badoo\\Jira\\Issue` cache, that will be broken by such combination.\nWe will fix this issue in the future if it show up itself as problematic.\n\n\n### Managing API requests with custom fields\n\nYou can instantiate a custom field object in several ways. As for `\\Badoo\\Jira\\Issue` instantiation,\nthey differ in API requests required for initialization and values update.\n\n```php\n$MyCustomField = \\Example\\CustomFields\\MyJIRACustomField::forIssue('SMPL-1');\n\n// The example above is equivalent to:\n$Issue = \\Badoo\\Jira\\Issue::byKey('SMPL-1', ['key', \\Example\\CustomFields\\MyJIRACustomField::ID]);\n$MyCustomField = new \\Example\\CustomFields\\MyJIRACustomField($Issue);\n```\n\nIn both examples CustomField object we creted has \\Badoo\\Jira\\Issue object under the hood.\nThe difference reveals when you start to work with several custom fields of one issue.\n\nInitialization with static method `::forIssue()` will always create new \\Badoo\\Jira\\Issue object under the hood.\nThis means that fields:\n```php\n$MyCustomField1 = \\Example\\CustomFields\\MyFirstCustomField::forIssue('SMPL-1');\n$MyCustomField2 = \\Example\\CustomFields\\MySecondCustomField::forIssue('SMPL-1');\n```\nwill have different `\\Badoo\\Jira\\Issue` objects, even though they are refer to the single JIRA issue.\n\nAll custom fields use `\\Badoo\\Jira\\Issue` as instrument to manage their values:\nthey load data through it and edit themselves using interface Issue provides.\n\nWhen you call `$CustomField-\u003esetValue()`, it actually is simillar to `$Issue-\u003eedit(\u003ccustom field id\u003e, \u003cnew field value\u003e);`.\n\nThat means you are able to 'stack' several custom field changes in one $Issue object to send updates to API only once,\nmaking interaction with API more optimal.\n\n```php\n$Issue = \\Badoo\\Jira\\Issue::byKey('SMPL-1'); // causes API request to get all issue fields\n\n$MyCustomField1 = new \\Example\\CustomFields\\MyFirstCustomField($Issue);\n$MyCustomField2 = new \\Example\\CustomFields\\MySecondCustomField($Issue);\n// other custom fields initialization\n\n$MyCustomField1-\u003esetValue('new value'); // no API requests here. Field value in JIRA remains the same\n$MyCustomField2-\u003esetValue($MyCustomField2::VALUE_CHANGED); // no API requests here too.\n// other custom fields changes\n\n$Issue-\u003esave(); // API request to JIRA with field updates\n\n// Now JIRA issue has new field values and one new changelog record.\n// You can also use $MyCustomField2-\u003esave(); - it is the same,\n// but with $Issue-\u003esave(); it is more clear what is happening\n```\n\n### Managing API requests with other classes\n\nOther classes, like Status, Priority and User, have special `::get` static method which duplicates a regular constructor\nbut has effect on requests to API.\n\n```php\n$Status = new \\Badoo\\Jira\\Issue\\Status(\u003cstatus ID\u003e); // no request to API here\n$Status-\u003egetName(); // requests API in background. This is where exception will be thrown on errors.\n\n// ...\n\n$Status = \\Badoo\\Jira\\Issue\\Status::get(\u003cstatus ID\u003e); // request to API here. This is where exception will be thrown on errors.\n```\n\n## Extending \\Badoo\\Jira\\Issue\n\n`\\Badoo\\Jira\\Issue` is about abstract JIRA instance. It has no idea about custom fields you oftenly use, statuses you\nfrequently transition to, and so on. It is much more convenient to have your own shortcuts for actions you do often\n\nTo do this, we recomment to craete you own Issue class to extend `\\Badoo\\Jira\\Issue` functionality with your own methods.\n\nFor example, you might want to easily close issue with one call, setting resolution to some special value.\nHere is the receipt:\n```php\nnamespace Example;\n\nclass Issue extends \\Badoo\\Jira\\Issue {\n    public function markDone() : Issue\n    {\n\n        return $this;\n    }\n}\n\n// ...\n\n$Issue = new \\Example\\Issue('SMPL-1');\n$Issue-\u003emarkDone();\n```\n\nYou would probably want to extend `\\Badoo\\Jira\\Issue\\CreateRequest` to return your Issue object instead of\noriginal one:\n\n```php\nnamespace Example;\n\nclass CreateRequest extends \\Badoo\\Jira\\Issue\\CreateRequest {\n    public function create() : \\Badoo\\Jira\\Issue\n    {\n        $Issue = parent::create();\n\n        $IssueInfo = new \\stdClass();\n        $IssueInfo-\u003eid = $Issue-\u003egetId();\n        $IssueInfo-\u003ekey = $Issue-\u003egetKey();\n\n        return \\Example\\Issue::fromStdClass($IssueInfo, ['id', 'key']);\n    }\n}\n```\n\n### Methods to use in child class\n\nHere is just a piece of code with examples. They are much more informative than lost of words.\n```php\nnamespace Example;\n\nclass Issue extends \\Badoo\\Jira\\Issue {\n    public function getSomeDataFromRawApiResponse()\n    {\n        /** @var \\stdClass $IssueInfo - contains an issue data obtained from JIRA API,\n                                        returned from \\Badoo\\Jira\\ClientRaw 'as-is'. */\n        $IssueInfo = $this-\u003egetBaseIssue();\n\n        $issue_key = $IssueInfo-\u003ekey;\n        $issue_id = $IssueInfo-\u003eid;\n        $self_link = $IssueInfo-\u003eself;\n        $summary = $IssueInfo-\u003efields-\u003esummary;\n        // ...\n    }\n\n    public function getFieldUsingCache() : \\stdClass\n    {\n        return $this-\u003egetFieldValue('customfield_12345');\n        // this is equivalent to\n        //  $this-\u003egetBaseIssue()-\u003efields-\u003ecustomfield_12345;\n        // but will not cause API request when you use partial field inititialization\n    }\n\n    public function getMyCustomField() : \\Example\\CustomFields\\MyCustomField\n    {\n        return $this-\u003egetCustomField(\\Example\\CustomFields\\MyCustomField::class);\n        // this will also not cause API request when you use partial field initialization, but also return you\n        // the same object of \\Example\\CustomFields\\MyCustomField each time you use the method\n    }\n}\n```\n\n## Writing your own custom field base class\n\nAll custom fields should be inherited from `\\Badoo\\Jira\\Issue\\CustomFields\\CustomField` class or one of its children\nThe simplest examples of custom field base classes are `\\Badoo\\Jira\\CustomFields\\TextField` and\n`\\Badoo\\Jira\\CustomFields\\NumberField`.\n\nThere are some additional special methods you should know about:\n* `$this-\u003egetOriginalObject()` - gets field value as it is provided by JIRA API.\n* `$this-\u003edropCache()` - drops internal object cache, e.g. drops cached field value.\n\n`getOriginalObject()` method requests bound Issue object for current field value.\nIt caches value inside current object, it is safe to call it multiple times in a row.\nThis will not cause several API requests.\nWe expect you to always use this method instead of `$this-\u003eIssue-\u003egetFieldValue()` when you write your own\nwrapper inherited directly from `\\Badoo\\Jira\\Issue\\CustomFields\\CustomField`.\n\n`dropCache()` method is intended to drop all data about field value cached internally in object. If you plan to use\ninternal properties in your custom class, don't forget to redefine `dropCache()` method so\nit clears values of your fields.\n\n`dropCache()` method is called by bound Issue object once it loads data from API. This is a way to notify all\nexisting bound custom field objects that field value might have been updated.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbadoo%2Fjira-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbadoo%2Fjira-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbadoo%2Fjira-client/lists"}