Refactor API notification usage
- Remove "mapFields()" from BaseModel - Add new Notification API entity (including collection) - Add new NotificationFactory method "getApiList()"
This commit is contained in:
		
					parent
					
						
							
								4a3544582c
							
						
					
				
			
			
				commit
				
					
						582f6bd4a3
					
				
			
		
					 9 changed files with 164 additions and 109 deletions
				
			
		|  | @ -5892,10 +5892,11 @@ api_register_func('api/friendica/activity/unattendmaybe', 'api_friendica_activit | ||||||
|  * Returns notifications |  * Returns notifications | ||||||
|  * |  * | ||||||
|  * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' |  * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' | ||||||
|  |  * | ||||||
|  * @return string|array |  * @return string|array | ||||||
|  * @throws BadRequestException |  | ||||||
|  * @throws ForbiddenException |  * @throws ForbiddenException | ||||||
|  * @throws InternalServerErrorException |  * @throws BadRequestException | ||||||
|  |  * @throws Exception | ||||||
|  */ |  */ | ||||||
| function api_friendica_notification($type) | function api_friendica_notification($type) | ||||||
| { | { | ||||||
|  | @ -5908,7 +5909,7 @@ function api_friendica_notification($type) | ||||||
| 		throw new BadRequestException("Invalid argument count"); | 		throw new BadRequestException("Invalid argument count"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	$notifications = DI::notify()->select(['uid' => api_user()], ['order' => ['seen' => 'ASC', 'date' => 'DESC'], 'limit' => 50]); | 	$notifications = DI::notification()->getApiList(local_user()); | ||||||
| 
 | 
 | ||||||
| 	if ($type == "xml") { | 	if ($type == "xml") { | ||||||
| 		$xmlnotes = false; | 		$xmlnotes = false; | ||||||
|  |  | ||||||
|  | @ -17,14 +17,14 @@ abstract class BaseCollection extends \ArrayIterator | ||||||
| 	protected $totalCount = 0; | 	protected $totalCount = 0; | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * @param BaseModel[] $models | 	 * @param BaseEntity[] $entities | ||||||
| 	 * @param int|null     $totalCount | 	 * @param int|null     $totalCount | ||||||
| 	 */ | 	 */ | ||||||
| 	public function __construct(array $models = [], int $totalCount = null) | 	public function __construct(array $entities = [], int $totalCount = null) | ||||||
| 	{ | 	{ | ||||||
| 		parent::__construct($models); | 		parent::__construct($entities); | ||||||
| 
 | 
 | ||||||
| 		$this->totalCount = $totalCount ?? count($models); | 		$this->totalCount = $totalCount ?? count($entities); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  |  | ||||||
|  | @ -11,7 +11,22 @@ namespace Friendica; | ||||||
|  */ |  */ | ||||||
| abstract class BaseEntity implements \JsonSerializable | abstract class BaseEntity implements \JsonSerializable | ||||||
| { | { | ||||||
|  | 	/** | ||||||
|  | 	 * Returns the current entity as an json array | ||||||
|  | 	 * | ||||||
|  | 	 * @return array | ||||||
|  | 	 */ | ||||||
| 	public function jsonSerialize() | 	public function jsonSerialize() | ||||||
|  | 	{ | ||||||
|  | 		return $this->toArray(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Returns the current entity as an array | ||||||
|  | 	 * | ||||||
|  | 	 * @return array | ||||||
|  | 	 */ | ||||||
|  | 	public function toArray() | ||||||
| 	{ | 	{ | ||||||
| 		return get_object_vars($this); | 		return get_object_vars($this); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ use Psr\Log\LoggerInterface; | ||||||
|  * |  * | ||||||
|  * @property int id |  * @property int id | ||||||
|  */ |  */ | ||||||
| abstract class BaseModel | abstract class BaseModel extends BaseEntity | ||||||
| { | { | ||||||
| 	/** @var Database */ | 	/** @var Database */ | ||||||
| 	protected $dba; | 	protected $dba; | ||||||
|  | @ -48,23 +48,9 @@ abstract class BaseModel | ||||||
| 		$this->originalData = $data; | 		$this->originalData = $data; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** |  | ||||||
| 	 * Maps a data array (original/current) to a known field list of the chosen model |  | ||||||
| 	 * |  | ||||||
| 	 * This is useful to filter out additional attributes, which aren't part of the db-table (like readonly cached fields) |  | ||||||
| 	 * |  | ||||||
| 	 * @param array $data The data array to map to db-fields |  | ||||||
| 	 * |  | ||||||
| 	 * @return array the mapped data array |  | ||||||
| 	 */ |  | ||||||
| 	protected function mapFields(array $data) |  | ||||||
| 	{ |  | ||||||
| 		return $data; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	public function getOriginalData() | 	public function getOriginalData() | ||||||
| 	{ | 	{ | ||||||
| 		return $this->mapFields($this->originalData); | 		return $this->originalData; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public function resetOriginalData() | 	public function resetOriginalData() | ||||||
|  | @ -129,16 +115,9 @@ abstract class BaseModel | ||||||
| 		$this->data[$name] = $value; | 		$this->data[$name] = $value; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	public function toArray() | ||||||
| 	 * Returns the values of the current model as an array |  | ||||||
| 	 * |  | ||||||
| 	 * @param bool $dbOnly True, if just the db-relevant fields should be returned |  | ||||||
| 	 * |  | ||||||
| 	 * @return array The values of the current model |  | ||||||
| 	 */ |  | ||||||
| 	public function toArray(bool $dbOnly = false) |  | ||||||
| 	{ | 	{ | ||||||
| 		return $dbOnly ? $this->mapFields($this->data) : $this->data; | 		return $this->data; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	protected function checkValid() | 	protected function checkValid() | ||||||
|  |  | ||||||
							
								
								
									
										17
									
								
								src/Collection/Api/Notifications.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/Collection/Api/Notifications.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Friendica\Collection\Api; | ||||||
|  | 
 | ||||||
|  | use Friendica\BaseCollection; | ||||||
|  | use Friendica\Object\Api\Friendica\Notification; | ||||||
|  | 
 | ||||||
|  | class Notifications extends BaseCollection | ||||||
|  | { | ||||||
|  | 	/** | ||||||
|  | 	 * @return Notification | ||||||
|  | 	 */ | ||||||
|  | 	public function current() | ||||||
|  | 	{ | ||||||
|  | 		return parent::current(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								src/DI.php
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								src/DI.php
									
										
									
									
									
								
							|  | @ -280,14 +280,6 @@ abstract class DI | ||||||
| 		return self::$dice->create(Model\User\Cookie::class); | 		return self::$dice->create(Model\User\Cookie::class); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** |  | ||||||
| 	 * @return Repository\Notify |  | ||||||
| 	 */ |  | ||||||
| 	public static function notify() |  | ||||||
| 	{ |  | ||||||
| 		return self::$dice->create(Repository\Notify::class); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return Model\Storage\IStorage | 	 * @return Model\Storage\IStorage | ||||||
| 	 */ | 	 */ | ||||||
|  | @ -324,6 +316,14 @@ abstract class DI | ||||||
| 		return self::$dice->create(Repository\ProfileField::class); | 		return self::$dice->create(Repository\ProfileField::class); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * @return Repository\Notify | ||||||
|  | 	 */ | ||||||
|  | 	public static function notify() | ||||||
|  | 	{ | ||||||
|  | 		return self::$dice->create(Repository\Notify::class); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	//
 | 	//
 | ||||||
| 	// "Protocol" namespace instances
 | 	// "Protocol" namespace instances
 | ||||||
| 	//
 | 	//
 | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ use Exception; | ||||||
| use Friendica\App; | use Friendica\App; | ||||||
| use Friendica\App\BaseURL; | use Friendica\App\BaseURL; | ||||||
| use Friendica\BaseFactory; | use Friendica\BaseFactory; | ||||||
|  | use Friendica\Collection\Api\Notifications as ApiNotifications; | ||||||
| use Friendica\Content\Text\BBCode; | use Friendica\Content\Text\BBCode; | ||||||
| use Friendica\Core\L10n; | use Friendica\Core\L10n; | ||||||
| use Friendica\Core\PConfig\IPConfig; | use Friendica\Core\PConfig\IPConfig; | ||||||
|  | @ -15,6 +16,7 @@ use Friendica\Database\Database; | ||||||
| use Friendica\Model\Item; | use Friendica\Model\Item; | ||||||
| use Friendica\Module\BaseNotifications; | use Friendica\Module\BaseNotifications; | ||||||
| use Friendica\Network\HTTPException\InternalServerErrorException; | use Friendica\Network\HTTPException\InternalServerErrorException; | ||||||
|  | use Friendica\Object\Api\Friendica\Notification as ApiNotification; | ||||||
| use Friendica\Protocol\Activity; | use Friendica\Protocol\Activity; | ||||||
| use Friendica\Repository; | use Friendica\Repository; | ||||||
| use Friendica\Util\DateTimeFormat; | use Friendica\Util\DateTimeFormat; | ||||||
|  | @ -352,4 +354,26 @@ class Notification extends BaseFactory | ||||||
| 
 | 
 | ||||||
| 		return $formattedNotifications; | 		return $formattedNotifications; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * @param int   $uid    The user id of the API call | ||||||
|  | 	 * @param array $params Additional parameters | ||||||
|  | 	 * | ||||||
|  | 	 * @return ApiNotifications | ||||||
|  | 	 * | ||||||
|  | 	 * @throws Exception | ||||||
|  | 	 */ | ||||||
|  | 	public function getApiList(int $uid, array $params = ['order' => ['seen' => 'ASC', 'date' => 'DESC'], 'limit' => 50]) | ||||||
|  | 	{ | ||||||
|  | 		$notifies = $this->notification->select(['uid' => $uid], $params); | ||||||
|  | 
 | ||||||
|  | 		/** @var ApiNotification[] $notifications */ | ||||||
|  | 		$notifications = []; | ||||||
|  | 
 | ||||||
|  | 		foreach ($notifies as $notify) { | ||||||
|  | 			$notifications[] = new ApiNotification($notify); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return new ApiNotifications($notifications); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -5,19 +5,12 @@ namespace Friendica\Model; | ||||||
| use Exception; | use Exception; | ||||||
| use Friendica\BaseModel; | use Friendica\BaseModel; | ||||||
| use Friendica\Content\Text\BBCode; | use Friendica\Content\Text\BBCode; | ||||||
| use Friendica\Content\Text\HTML; |  | ||||||
| use Friendica\Database\Database; | use Friendica\Database\Database; | ||||||
| use Friendica\Network\HTTPException\InternalServerErrorException; | use Friendica\Network\HTTPException\InternalServerErrorException; | ||||||
| use Friendica\Util\DateTimeFormat; |  | ||||||
| use Friendica\Util\Temporal; |  | ||||||
| use Psr\Log\LoggerInterface; | use Psr\Log\LoggerInterface; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Model for an entry in the notify table |  * Model for an entry in the notify table | ||||||
|  * - Including additional, calculated properties |  | ||||||
|  * |  | ||||||
|  * Is used either for frontend interactions or for API-based interaction |  | ||||||
|  * @see https://github.com/friendica/friendica/blob/develop/doc/API-Entities.md#notification
 |  | ||||||
|  * |  * | ||||||
|  * @property string  hash |  * @property string  hash | ||||||
|  * @property integer type |  * @property integer type | ||||||
|  | @ -36,11 +29,6 @@ use Psr\Log\LoggerInterface; | ||||||
|  * |  * | ||||||
|  * @property-read string name_cache Full name of the contact subject |  * @property-read string name_cache Full name of the contact subject | ||||||
|  * @property-read string msg_cache  Plaintext version of the notification text with a placeholder (`{0}`) for the subject contact's name. |  * @property-read string msg_cache  Plaintext version of the notification text with a placeholder (`{0}`) for the subject contact's name. | ||||||
|  * |  | ||||||
|  * @property-read integer timestamp  Unix timestamp |  | ||||||
|  * @property-read string  dateRel  	 Time since the note was posted, eg "1 hour ago" |  | ||||||
|  * @property-read string  $msg_html |  | ||||||
|  * @property-read string  $msg_plain |  | ||||||
|  */ |  */ | ||||||
| class Notify extends BaseModel | class Notify extends BaseModel | ||||||
| { | { | ||||||
|  | @ -59,8 +47,7 @@ class Notify extends BaseModel | ||||||
| 		$this->repo = $repo; | 		$this->repo = $repo; | ||||||
| 
 | 
 | ||||||
| 		$this->setNameCache(); | 		$this->setNameCache(); | ||||||
| 		$this->setTimestamp(); | 		$this->setMsgCache(); | ||||||
| 		$this->setMsg(); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -81,41 +68,23 @@ class Notify extends BaseModel | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** |  | ||||||
| 	 * Set some extra properties to the notification from db: |  | ||||||
| 	 *  - timestamp as int in default TZ |  | ||||||
| 	 *  - date_rel : relative date string |  | ||||||
| 	 */ |  | ||||||
| 	private function setTimestamp() |  | ||||||
| 	{ |  | ||||||
| 		try { |  | ||||||
| 			$this->timestamp = strtotime(DateTimeFormat::local($this->date)); |  | ||||||
| 		} catch (Exception $e) { |  | ||||||
| 		} |  | ||||||
| 		$this->dateRel = Temporal::getRelativeDate($this->date); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Sets the pre-formatted name (caching) | 	 * Sets the pre-formatted name (caching) | ||||||
| 	 * |  | ||||||
| 	 * @throws InternalServerErrorException |  | ||||||
| 	 */ | 	 */ | ||||||
| 	private function setNameCache() | 	private function setNameCache() | ||||||
| 	{ | 	{ | ||||||
|  | 		try { | ||||||
| 			$this->name_cache = strip_tags(BBCode::convert($this->source_name ?? '')); | 			$this->name_cache = strip_tags(BBCode::convert($this->source_name ?? '')); | ||||||
|  | 		} catch (InternalServerErrorException $e) { | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Set some extra properties to the notification from db: | 	 * Sets the pre-formatted msg (caching) | ||||||
| 	 *  - msg_html: message as html string |  | ||||||
| 	 *  - msg_plain: message as plain text string |  | ||||||
| 	 *  - msg_cache: The pre-formatted message (caching) |  | ||||||
| 	 */ | 	 */ | ||||||
| 	private function setMsg() | 	private function setMsgCache() | ||||||
| 	{ | 	{ | ||||||
| 		try { | 		try { | ||||||
| 			$this->msg_html  = BBCode::convert($this->msg, false); |  | ||||||
| 			$this->msg_plain = explode("\n", trim(HTML::toPlaintext($this->msg_html, 0)))[0]; |  | ||||||
| 			$this->msg_cache = self::formatMessage($this->name_cache, strip_tags(BBCode::convert($this->msg))); | 			$this->msg_cache = self::formatMessage($this->name_cache, strip_tags(BBCode::convert($this->msg))); | ||||||
| 		} catch (InternalServerErrorException $e) { | 		} catch (InternalServerErrorException $e) { | ||||||
| 		} | 		} | ||||||
|  | @ -125,12 +94,8 @@ class Notify extends BaseModel | ||||||
| 	{ | 	{ | ||||||
| 		parent::__set($name, $value); | 		parent::__set($name, $value); | ||||||
| 
 | 
 | ||||||
| 		if ($name == 'date') { |  | ||||||
| 			$this->setTimestamp(); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if ($name == 'msg') { | 		if ($name == 'msg') { | ||||||
| 			$this->setMsg(); | 			$this->setMsgCache(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if ($name == 'source_name') { | 		if ($name == 'source_name') { | ||||||
|  | @ -163,29 +128,4 @@ class Notify extends BaseModel | ||||||
| 
 | 
 | ||||||
| 		return $message; | 		return $message; | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * {@inheritDoc} |  | ||||||
| 	 */ |  | ||||||
| 	protected function mapFields(array $data) |  | ||||||
| 	{ |  | ||||||
| 		return [ |  | ||||||
| 			'hash'       => $data['hash'] ?? '', |  | ||||||
| 			'type'       => $data['type'] ?? 0, |  | ||||||
| 			'name'       => $data['name'] ?? '', |  | ||||||
| 			'url'        => $data['url'] ?? '', |  | ||||||
| 			'photo'      => $data['photo'] ?? '', |  | ||||||
| 			'date'       => $data['date'] ?? DateTimeFormat::utcNow(), |  | ||||||
| 			'msg'        => $data['msg'] ?? '', |  | ||||||
| 			'uid'        => $data['uid'] ?? 0, |  | ||||||
| 			'link'       => $data['link'] ?? '', |  | ||||||
| 			'iid'        => $data['iid'] ?? 0, |  | ||||||
| 			'parent'     => $data['parent'] ?? 0, |  | ||||||
| 			'seen'       => $data['seen'] ?? false, |  | ||||||
| 			'verb'       => $data['verb'] ?? '', |  | ||||||
| 			'otype'      => $data['otype'] ?? '', |  | ||||||
| 			'name_cache' => $data['name_cache'] ?? null, |  | ||||||
| 			'msg_cache'  => $data['msg_cache'] ?? null, |  | ||||||
| 		]; |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										79
									
								
								src/Object/Api/Friendica/Notification.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/Object/Api/Friendica/Notification.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,79 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Friendica\Object\Api\Friendica; | ||||||
|  | 
 | ||||||
|  | use Friendica\BaseEntity; | ||||||
|  | use Friendica\Content\Text\BBCode; | ||||||
|  | use Friendica\Content\Text\HTML; | ||||||
|  | use Friendica\Model\Notify; | ||||||
|  | use Friendica\Util\DateTimeFormat; | ||||||
|  | use Friendica\Util\Temporal; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Friendica Notification | ||||||
|  |  * | ||||||
|  |  * @see https://github.com/friendica/friendica/blob/develop/doc/API-Entities.md#notification
 | ||||||
|  |  */ | ||||||
|  | class Notification extends BaseEntity | ||||||
|  | { | ||||||
|  | 	/** @var integer */ | ||||||
|  | 	protected $id; | ||||||
|  | 	/** @var string */ | ||||||
|  | 	protected $hash; | ||||||
|  | 	/** @var integer */ | ||||||
|  | 	protected $type; | ||||||
|  | 	/** @var string Full name of the contact subject */ | ||||||
|  | 	protected $name; | ||||||
|  | 	/** @var string Profile page URL of the contact subject */ | ||||||
|  | 	protected $url; | ||||||
|  | 	/** @var string Profile photo URL of the contact subject */ | ||||||
|  | 	protected $photo; | ||||||
|  | 	/** @var string YYYY-MM-DD hh:mm:ss local server time */ | ||||||
|  | 	protected $date; | ||||||
|  | 	/** @var string The message (BBCode) */ | ||||||
|  | 	protected $msg; | ||||||
|  | 	/** @var integer Owner User Id */ | ||||||
|  | 	protected $uid; | ||||||
|  | 	/** @var string Notification URL */ | ||||||
|  | 	protected $link; | ||||||
|  | 	/** @var integer Item Id */ | ||||||
|  | 	protected $iid; | ||||||
|  | 	/** @var integer Parent Item Id */ | ||||||
|  | 	protected $parent; | ||||||
|  | 	/** @var boolean  Whether the notification was read or not. */ | ||||||
|  | 	protected $seen; | ||||||
|  | 	/** @var string Verb URL @see http://activitystrea.ms */ | ||||||
|  | 	protected $verb; | ||||||
|  | 	/** @var string Subject type (`item`, `intro` or `mail`) */ | ||||||
|  | 	protected $otype; | ||||||
|  | 	/** @var string Full name of the contact subject (HTML) */ | ||||||
|  | 	protected $name_cache; | ||||||
|  | 	/** @var string Plaintext version of the notification text with a placeholder (`{0}`) for the subject contact's name. (Plaintext) */ | ||||||
|  | 	protected $msg_cache; | ||||||
|  | 	/** @var integer  Unix timestamp */ | ||||||
|  | 	protected $timestamp; | ||||||
|  | 	/** @var string Time since the note was posted, eg "1 hour ago" */ | ||||||
|  | 	protected $date_rel; | ||||||
|  | 	/** @var string Message (HTML) */ | ||||||
|  | 	protected $msg_html; | ||||||
|  | 	/** @var string Message (Plaintext) */ | ||||||
|  | 	protected $msg_plain; | ||||||
|  | 
 | ||||||
|  | 	public function __construct(Notify $notify) | ||||||
|  | 	{ | ||||||
|  | 		// map each notify attribute to the entity
 | ||||||
|  | 		foreach ($notify->toArray() as $key => $value) { | ||||||
|  | 			$this->{$key} = $value; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// add additional attributes for the API
 | ||||||
|  | 		try { | ||||||
|  | 			$this->timestamp = strtotime(DateTimeFormat::local($this->date)); | ||||||
|  | 			$this->msg_html  = BBCode::convert($this->msg, false); | ||||||
|  | 			$this->msg_plain = explode("\n", trim(HTML::toPlaintext($this->msg_html, 0)))[0]; | ||||||
|  | 		} catch (\Exception $e) { | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		$this->date_rel = Temporal::getRelativeDate($this->date); | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue