Skip to content

Commit

Permalink
Retrieve older content versions (#10)
Browse files Browse the repository at this point in the history
* Added function to retrieve older content versions
  • Loading branch information
astepin authored Mar 1, 2024
1 parent f21e0e5 commit af86338
Show file tree
Hide file tree
Showing 8 changed files with 534 additions and 9 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ $createdPage = $searchResults->getResultAt(0);
$resultContent = $client->content()->get(1234567890);
```

#### Fetch old versions of a page or comment by content id
```php
/* @var $client CloudPlayDev\ConfluenceClient\ConfluenceClient */

//Get a page or comment in a specific version
$resultContentInVersion2 = $client->content()->get(1234567890, 2);
```

#### Fetch page descendants
```php
use CloudPlayDev\ConfluenceClient\Api\Content;
Expand All @@ -76,6 +84,17 @@ use CloudPlayDev\ConfluenceClient\Api\Content;
$childContent = $client->content()->children($page, Content::CONTENT_TYPE_PAGE); //\CloudPlayDev\ConfluenceClient\Entity\ContentSearchResult
```

#### Fetch content history
```php
use CloudPlayDev\ConfluenceClient\Api\Content;
/* @var $client CloudPlayDev\ConfluenceClient\ConfluenceClient */
/* @var $page CloudPlayDev\ConfluenceClient\Entity\ContentPage */

//get child content
$pageId = 2323232323;
$historyData = $client->content()->history($pageId); //\CloudPlayDev\ConfluenceClient\Entity\ContentSearchResult
```

### Manipulating content

#### Create new page
Expand Down
44 changes: 35 additions & 9 deletions src/Api/Content.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
namespace CloudPlayDev\ConfluenceClient\Api;

use CloudPlayDev\ConfluenceClient\Entity\AbstractContent;
use CloudPlayDev\ConfluenceClient\Entity\ContentHistory;
use CloudPlayDev\ConfluenceClient\Entity\ContentSearchResult;
use CloudPlayDev\ConfluenceClient\Entity\ContentBody;
use CloudPlayDev\ConfluenceClient\Entity\Hydratable;
use CloudPlayDev\ConfluenceClient\Exception\ConfluencePhpClientException;
use Http\Client\Exception as HttpClientException;
use JsonException;
Expand Down Expand Up @@ -43,19 +45,28 @@ class Content extends AbstractApi
* default value for expand query parameter
*/
private const DEFAULT_EXPAND = 'space,version,body.storage,container';
private const DEFAULT_HISTORY_EXPAND = 'content,content.space,content.version,content.body.storage,content.container';

/**
* @see https://docs.atlassian.com/atlassian-confluence/REST/6.6.0/#content-getContent
* @param int $contentId
* @return AbstractContent|null
* @throws ConfluencePhpClientException
* @throws HttpClientException
* @throws JsonException
*/
public function get(int $contentId): ?AbstractContent
public function get(int $contentId, ?int $version = null): ?AbstractContent
{
$response = $this->httpGet(
self::getRestfulUri('content', $contentId),
['expand' => self::DEFAULT_EXPAND]
);
$fetchUri = ['content', $contentId];
$parameter = ['expand' => self::DEFAULT_EXPAND];

if ($version !== null) {
$fetchUri[] = 'version';
$fetchUri[] = $version;

$parameter = ['expand' => self::DEFAULT_HISTORY_EXPAND];
}

$response = $this->httpGet(self::getRestfulUri(...$fetchUri), $parameter);

return $this->hydrateResponse($response, AbstractContent::class);
}

Expand All @@ -69,7 +80,7 @@ public function get(int $contentId): ?AbstractContent
public function find(array $searchParameter): ContentSearchResult
{
$allowedSearchParameter = ['title', 'spaceKey', 'type', 'id'];
$queryParameter = array_filter($searchParameter, static function(string $searchKey) use ($allowedSearchParameter) {
$queryParameter = array_filter($searchParameter, static function (string $searchKey) use ($allowedSearchParameter) {
return in_array($searchKey, $allowedSearchParameter, true);
}, ARRAY_FILTER_USE_KEY);

Expand Down Expand Up @@ -138,7 +149,7 @@ public function create(AbstractContent $content): AbstractContent
];

if (count($content->getAncestors()) > 0) {
$ancestorsData = array_map(static function(int $id) {
$ancestorsData = array_map(static function (int $id) {
return ['id' => $id];
}, $content->getAncestors());

Expand Down Expand Up @@ -236,4 +247,19 @@ public function convert(ContentBody $convertBody, string $to = 'view', ?Abstract
);

}

/**
* Returns the history of a particular piece of content, sorted by version number in descending order.
*
* @param int $contentId
* @return Hydratable
* @throws HttpClientException
*/
public function history(int $contentId): Hydratable
{
return $this->hydrateResponse(
$this->httpGet(self::getRestfulUri('content', $contentId, 'history')),
ContentHistory::class
);
}
}
23 changes: 23 additions & 0 deletions src/Entity/AbstractContent.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ abstract class AbstractContent implements Hydratable
private ?int $containerId = null;
private string $containerType = Content::CONTENT_TYPE_PAGE;

private bool $isLatest = true;

/**
* @return string
*/
Expand Down Expand Up @@ -271,6 +273,11 @@ public function addAncestor(int $id): self
*/
public static function load(array $data): self
{
/* handle older content versions */
if(isset($data['content'], $data['when'])) {
return self::load($data['content']);
}

Assert::true(isset($data['id'],
$data['type'],
$data['title'],
Expand Down Expand Up @@ -302,8 +309,24 @@ public static function load(array $data): self
$content->setContent((string)$data['body']['storage']['value']);
}

if(isset($data['status'])) {
Assert::string($data['status']);
$content->setLatest($data['status'] === 'current');
}

return $content;
}

public function isLatest(): bool
{
return $this->isLatest;
}

protected function setLatest(bool $isLatest): AbstractContent
{
$this->isLatest = $isLatest;
return $this;
}


}
133 changes: 133 additions & 0 deletions src/Entity/ContentHistory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php
declare(strict_types=1);

namespace CloudPlayDev\ConfluenceClient\Entity;

use CloudPlayDev\ConfluenceClient\Exception\HydrationException;
use DateTimeImmutable;
use DateTimeInterface;
use Webmozart\Assert\Assert;

class ContentHistory implements Hydratable
{


private DateTimeInterface $createdDate;
private DateTimeInterface $updatedDate;
private bool $isLatest = false;
private User $createdBy;
private User $updatedBy;

private int $lastVersionNumber;

/**
* @throws HydrationException
*/
public static function load(array $data): ContentHistory
{
$contentHistory = new self;
Assert::keyExists($data, 'createdDate');
Assert::keyExists($data, 'createdBy');
Assert::keyExists($data, 'lastUpdated');
Assert::isArray($data['createdBy']);
Assert::isArray($data['lastUpdated']);

Assert::keyExists($data['lastUpdated'], 'by');
Assert::isArray($data['lastUpdated']['by']);

if(isset($data['latest'])) {
Assert::boolean($data['latest']);
$contentHistory->setLatest($data['latest']);
}

$contentHistory->setCreatedDate(self::getDateTimeFromString($data['createdDate']));
$contentHistory->setCreatedBy(User::load($data['createdBy']));
$contentHistory->setUpdatedBy(User::load($data['lastUpdated']['by']));

$contentHistory->setUpdatedDate(self::getDateTimeFromString($data['lastUpdated']['when']));

$contentHistory->setLastVersionNumber($data['lastUpdated']['number']);

return $contentHistory;
}

/**
* @throws HydrationException
*/
private static function getDateTimeFromString(string $dateString): DateTimeInterface
{
$dateTimeImmutable = DateTimeImmutable::createFromFormat('Y-m-d\TH:i:s.vZ', $dateString);
if($dateTimeImmutable === false) {
throw new HydrationException('Invalid date string: ' . $dateString);
}

return $dateTimeImmutable;
}

private function setLatest(bool $latest): ContentHistory
{
$this->isLatest = $latest;
return $this;
}

private function setCreatedDate(DateTimeInterface $createFromFormat): ContentHistory
{
$this->createdDate = $createFromFormat;
return $this;
}

private function setCreatedBy(User $user): ContentHistory
{
$this->createdBy = $user;
return $this;
}

private function setUpdatedBy(User $user): ContentHistory
{
$this->updatedBy = $user;
return $this;
}

public function setUpdatedDate(DateTimeInterface $updatedDate): ContentHistory
{
$this->updatedDate = $updatedDate;
return $this;
}

public function getUpdatedDate(): DateTimeInterface
{
return $this->updatedDate;
}

public function getCreatedDate(): DateTimeInterface
{
return $this->createdDate;
}

public function isLatest(): bool
{
return $this->isLatest;
}

public function getCreatedBy(): User
{
return $this->createdBy;
}

public function getUpdatedBy(): User
{
return $this->updatedBy;
}

public function getLastVersionNumber(): int
{
return $this->lastVersionNumber;
}

public function setLastVersionNumber(int $lastVersionNumber): void
{
$this->lastVersionNumber = $lastVersionNumber;
}


}
Loading

0 comments on commit af86338

Please sign in to comment.