From 74f3a2f90c6b92aafdaa7be6dcfb672fa7757586 Mon Sep 17 00:00:00 2001
From: nupplaPhil <admin@philipp.info>
Date: Sat, 25 Jan 2020 20:00:58 +0100
Subject: [PATCH] Fix API result, add PHPDoc and cleanup object construction
 Fix missing getters fix data array fix missing "$" for template-variables
 Remove lazy-loaded parent notification instance (for now..)

---
 include/api.php                               |  11 +-
 .../Notification/IntroductionFactory.php      |   6 +
 .../Notification/NotificationFactory.php      | 162 +++++++++---------
 src/Model/Notification.php                    |  24 ---
 src/Module/Notifications/Introductions.php    | 130 +++++++-------
 src/Object/Notification/Introduction.php      |  68 ++++----
 src/Object/Notification/Notification.php      |  20 +--
 7 files changed, 203 insertions(+), 218 deletions(-)

diff --git a/include/api.php b/include/api.php
index cb0599d9a..4a55c2b91 100644
--- a/include/api.php
+++ b/include/api.php
@@ -5909,16 +5909,21 @@ function api_friendica_notification($type)
 	$notifications = DI::notification()->select([], ['order' => ['seen' => 'ASC', 'date' => 'DESC'], 'limit' => 50]);
 
 	if ($type == "xml") {
-		$xmlnotes = [];
+		$xmlnotes = false;
 		if (!empty($notifications)) {
 			foreach ($notifications as $notification) {
 				$xmlnotes[] = ["@attributes" => $notification->toArray()];
 			}
 		}
 
-		$notifications = $xmlnotes;
+		$result = $xmlnotes;
+	} elseif (count($notifications) > 0) {
+		$result = $notifications->getArrayCopy();
+	} else {
+		$result = false;
 	}
-	return api_format_data("notes", $type, ['note' => $notifications->getArrayCopy()]);
+
+	return api_format_data("notes", $type, ['note' => $result]);
 }
 
 /**
diff --git a/src/Factory/Notification/IntroductionFactory.php b/src/Factory/Notification/IntroductionFactory.php
index 73f288326..3f2bb563a 100644
--- a/src/Factory/Notification/IntroductionFactory.php
+++ b/src/Factory/Notification/IntroductionFactory.php
@@ -19,6 +19,12 @@ use Friendica\Object\Notification\Introduction;
 use Friendica\Util\Proxy;
 use Psr\Log\LoggerInterface;
 
+/**
+ * Factory for creating notification objects based on introductions
+ * Currently, there are two main types of introduction based notifications:
+ * - Friend suggestion
+ * - Friend/Follower request
+ */
 class IntroductionFactory extends BaseFactory
 {
 	/** @var Database */
diff --git a/src/Factory/Notification/NotificationFactory.php b/src/Factory/Notification/NotificationFactory.php
index 2516916d1..05dd200ad 100644
--- a/src/Factory/Notification/NotificationFactory.php
+++ b/src/Factory/Notification/NotificationFactory.php
@@ -23,6 +23,14 @@ use Friendica\Util\Temporal;
 use Friendica\Util\XML;
 use Psr\Log\LoggerInterface;
 
+/**
+ * Factory for creating notification objects based on items
+ * Currently, there are the following types of item based notifications:
+ * - network
+ * - system
+ * - home
+ * - personal
+ */
 class NotificationFactory extends BaseFactory
 {
 	/** @var Database */
@@ -93,97 +101,89 @@ class NotificationFactory extends BaseFactory
 		// Transform the different types of notification in an usable array
 		switch ($item['verb'] ?? '') {
 			case Activity::LIKE:
-				return new \Friendica\Object\Notification\Notification(
-					'like',
-					$this->baseUrl->get(true) . '/display/' . $item['parent-guid'],
-					Proxy::proxifyUrl($item['author-avatar'], false, Proxy::SIZE_MICRO),
-					$item['author-link'],
-					$this->l10n->t("%s liked %s's post", $item['author-name'], $item['parent-author-name']),
-					$item['when'] ?? '',
-					$item['ago'] ?? '',
-					$item['seen'] ?? false);
+				return new \Friendica\Object\Notification\Notification([
+					'label' => 'like',
+					'link'  => $this->baseUrl->get(true) . '/display/' . $item['parent-guid'],
+					'image' => Proxy::proxifyUrl($item['author-avatar'], false, Proxy::SIZE_MICRO),
+					'url'   => $item['author-link'],
+					'text'  => $this->l10n->t("%s liked %s's post", $item['author-name'], $item['parent-author-name']),
+					'when'  => $item['when'],
+					'ago'   => $item['ago'],
+					'seen'  => $item['seen']]);
 
 			case Activity::DISLIKE:
-				return new \Friendica\Object\Notification\Notification(
-					'dislike',
-					$this->baseUrl->get(true) . '/display/' . $item['parent-guid'],
-					Proxy::proxifyUrl($item['author-avatar'], false, Proxy::SIZE_MICRO),
-					$item['author-link'],
-					$this->l10n->t("%s disliked %s's post", $item['author-name'], $item['parent-author-name']),
-					$item['when'] ?? '',
-					$item['ago'] ?? '',
-					$item['seen'] ?? false);
+				return new \Friendica\Object\Notification\Notification([
+					'label' => 'dislike',
+					'link'  => $this->baseUrl->get(true) . '/display/' . $item['parent-guid'],
+					'image' => Proxy::proxifyUrl($item['author-avatar'], false, Proxy::SIZE_MICRO),
+					'url'   => $item['author-link'],
+					'text'  => $this->l10n->t("%s disliked %s's post", $item['author-name'], $item['parent-author-name']),
+					'when'  => $item['when'],
+					'ago'   => $item['ago'],
+					'seen'  => $item['seen']]);
 
 			case Activity::ATTEND:
-				return new \Friendica\Object\Notification\Notification(
-					'attend',
-					$this->baseUrl->get(true) . '/display/' . $item['parent-guid'],
-					Proxy::proxifyUrl($item['author-avatar'], false, Proxy::SIZE_MICRO),
-					$item['author-link'],
-					$this->l10n->t("%s is attending %s's event", $item['author-name'], $item['parent-author-name']),
-					$item['when'] ?? '',
-					$item['ago'] ?? '',
-					$item['seen'] ?? false);
+				return new \Friendica\Object\Notification\Notification([
+					'label' => 'attend',
+					'link'  => $this->baseUrl->get(true) . '/display/' . $item['parent-guid'],
+					'image' => Proxy::proxifyUrl($item['author-avatar'], false, Proxy::SIZE_MICRO),
+					'url'   => $item['author-link'],
+					'text'  => $this->l10n->t("%s is attending %s's event", $item['author-name'], $item['parent-author-name']),
+					'when'  => $item['when'],
+					'ago'   => $item['ago'],
+					'seen'  => $item['seen']]);
 
 			case Activity::ATTENDNO:
-				return new \Friendica\Object\Notification\Notification(
-					'attendno',
-					$this->baseUrl->get(true) . '/display/' . $item['parent-guid'],
-					Proxy::proxifyUrl($item['author-avatar'], false, Proxy::SIZE_MICRO),
-					$item['author-link'],
-					$this->l10n->t("%s is not attending %s's event", $item['author-name'], $item['parent-author-name']),
-					$item['when'] ?? '',
-					$item['ago'] ?? '',
-					$item['seen'] ?? false);
+				return new \Friendica\Object\Notification\Notification([
+					'label' => 'attendno',
+					'link'  => $this->baseUrl->get(true) . '/display/' . $item['parent-guid'],
+					'image' => Proxy::proxifyUrl($item['author-avatar'], false, Proxy::SIZE_MICRO),
+					'url'   => $item['author-link'],
+					'text'  => $this->l10n->t("%s is not attending %s's event", $item['author-name'], $item['parent-author-name']),
+					'when'  => $item['when'],
+					'ago'   => $item['ago'],
+					'seen'  => $item['seen']]);
 
 			case Activity::ATTENDMAYBE:
-				return new \Friendica\Object\Notification\Notification(
-					'attendmaybe',
-					$this->baseUrl->get(true) . '/display/' . $item['parent-guid'],
-					Proxy::proxifyUrl($item['author-avatar'], false, Proxy::SIZE_MICRO),
-					$item['author-link'],
-					$this->l10n->t("%s may attending %s's event", $item['author-name'], $item['parent-author-name']),
-					$item['when'] ?? '',
-					$item['ago'] ?? '',
-					$item['seen'] ?? false);
+				return new \Friendica\Object\Notification\Notification([
+					'label' => 'attendmaybe',
+					'link'  => $this->baseUrl->get(true) . '/display/' . $item['parent-guid'],
+					'image' => Proxy::proxifyUrl($item['author-avatar'], false, Proxy::SIZE_MICRO),
+					'url'   => $item['author-link'],
+					'text'  => $this->l10n->t("%s may attending %s's event", $item['author-name'], $item['parent-author-name']),
+					'when'  => $item['when'],
+					'ago'   => $item['ago'],
+					'seen'  => $item['seen']]);
 
 			case Activity::FRIEND:
 				if (!isset($item['object'])) {
-					return new \Friendica\Object\Notification\Notification(
-						'friend',
-						$item['link'],
-						$item['image'],
-						$item['url'],
-						$item['text'],
-						$item['when'] ?? '',
-						$item['ago'] ?? '',
-						$item['seen'] ?? false);
+					return new \Friendica\Object\Notification\Notification([
+						'label' => 'friend',
+						'link'  => $item['link'],
+						'image' => $item['image'],
+						'url'   => $item['url'],
+						'text'  => $item['text'],
+						'when'  => $item['when'],
+						'ago'   => $item['ago'],
+						'seen'  => $item['seen']]);
 				}
 
 				$xmlHead       = "<" . "?xml version='1.0' encoding='UTF-8' ?" . ">";
 				$obj           = XML::parseString($xmlHead . $item['object']);
 				$item['fname'] = $obj->title;
 
-				return new \Friendica\Object\Notification\Notification(
-					'friend',
-					$this->baseUrl->get(true) . '/display/' . $item['parent-guid'],
-					Proxy::proxifyUrl($item['author-avatar'], false, Proxy::SIZE_MICRO),
-					$item['author-link'],
-					$this->l10n->t("%s is now friends with %s", $item['author-name'], $item['fname']),
-					$item['when'] ?? '',
-					$item['ago'] ?? '',
-					$item['seen'] ?? false);
+				return new \Friendica\Object\Notification\Notification([
+					'label' => 'friend',
+					'link'  => $this->baseUrl->get(true) . '/display/' . $item['parent-guid'],
+					'image' => Proxy::proxifyUrl($item['author-avatar'], false, Proxy::SIZE_MICRO),
+					'url'   => $item['author-link'],
+					'text'  => $this->l10n->t("%s is now friends with %s", $item['author-name'], $item['fname']),
+					'when'  => $item['when'],
+					'ago'   => $item['ago'],
+					'seen'  => $item['seen']]);
 
 			default:
-				return new \Friendica\Object\Notification\Notification(
-					$item['label'],
-					$item['link'],
-					$item['image'],
-					$item['url'],
-					$item['text'],
-					$item['when'] ?? '',
-					$item['ago'] ?? '',
-					$item['seen'] ?? false);
+				return new \Friendica\Object\Notification\Notification($item);
 				break;
 		}
 	}
@@ -215,15 +215,15 @@ class NotificationFactory extends BaseFactory
 			$notifications = $this->notification->select($conditions, $params);
 
 			foreach ($notifications as $notification) {
-				$formattedNotifications[] = new \Friendica\Object\Notification\Notification(
-					'notification',
-					$this->baseUrl->get(true) . '/notification/view/' . $notification->id,
-					Proxy::proxifyUrl($notification->photo, false, Proxy::SIZE_MICRO),
-					$notification->url,
-					strip_tags(BBCode::convert($notification->msg)),
-					DateTimeFormat::local($notification->date, 'r'),
-					Temporal::getRelativeDate($notification->date),
-					$notification->seen);
+				$formattedNotifications[] = new \Friendica\Object\Notification\Notification([
+					'label' => 'notification',
+					'link'  => $this->baseUrl->get(true) . '/notification/view/' . $notification->id,
+					'image' => Proxy::proxifyUrl($notification->photo, false, Proxy::SIZE_MICRO),
+					'url'   => $notification->url,
+					'text'  => strip_tags(BBCode::convert($notification->msg)),
+					'when'  => DateTimeFormat::local($notification->date, 'r'),
+					'ago'   => Temporal::getRelativeDate($notification->date),
+					'seen'  => $notification->seen]);
 			}
 		} catch (Exception $e) {
 			$this->logger->warning('Select failed.', ['conditions' => $conditions, 'exception' => $e]);
diff --git a/src/Model/Notification.php b/src/Model/Notification.php
index 11105d798..254aaf5f6 100644
--- a/src/Model/Notification.php
+++ b/src/Model/Notification.php
@@ -46,8 +46,6 @@ class Notification extends BaseModel
 {
 	/** @var \Friendica\Repository\Notification */
 	private $repo;
-	/** @var $this */
-	private $parentInst;
 
 	public function __construct(Database $dba, LoggerInterface $logger, \Friendica\Repository\Notification $repo, array $data = [])
 	{
@@ -118,28 +116,6 @@ class Notification extends BaseModel
 		}
 	}
 
-	public function __get($name)
-	{
-		$this->checkValid();
-
-		$return = null;
-
-		switch ($name) {
-			case 'parent':
-				if (!empty($this->parent)) {
-					$this->parentInst = $this->parentInst ?? $this->repo->getByID($this->parent);
-
-					$return = $this->parentInst;
-				}
-				break;
-			default:
-				$return = parent::__get($name);
-				break;
-		}
-
-		return $return;
-	}
-
 	public function __set($name, $value)
 	{
 		parent::__set($name, $value);
diff --git a/src/Module/Notifications/Introductions.php b/src/Module/Notifications/Introductions.php
index b0bdac0cb..8ded212c6 100644
--- a/src/Module/Notifications/Introductions.php
+++ b/src/Module/Notifications/Introductions.php
@@ -25,7 +25,7 @@ class Introductions extends BaseNotifications
 		$all = DI::args()->get(2) == 'all';
 
 		$notifications = [
-			'ident'        => 'introductions',
+			'ident'         => 'introductions',
 			'notifications' => DI::factNotIntro()->getIntroList($all, self::$firstItemNum, self::ITEMS_PER_PAGE, $id),
 		];
 
@@ -64,32 +64,32 @@ class Introductions extends BaseNotifications
 
 			// There are two kind of introduction. Contacts suggested by other contacts and normal connection requests.
 			// We have to distinguish between these two because they use different data.
-			switch ($notification['label']) {
+			switch ($notification->getLabel()) {
 				case 'friend_suggestion':
 					$notificationContent[] = Renderer::replaceMacros($notificationSuggestions, [
-						'$type'                 => $notification->getLabel(),
-						'str_notification_type' => DI::l10n()->t('Notification type:'),
-						'str_type'              => $notification->getType(),
-						'$intro_id'             => $notification->getIntroId(),
-						'$lbl_madeby'           => DI::l10n()->t('Suggested by:'),
-						'$madeby'               => $notification->getMadeBy(),
-						'$madeby_url'           => $notification->getMadeByUrl(),
-						'$madeby_zrl'           => $notification->getMadeByZrl(),
-						'$madeby_addr'          => $notification->getMadeByAddr(),
-						'$contact_id'           => $notification->getContactId(),
-						'$photo'                => $notification->getPhoto(),
-						'$fullname'             => $notification->getName(),
-						'$url'                  => $notification->getUrl(),
-						'$zrl'                  => $notification->getZrl(),
-						'$lbl_url'              => DI::l10n()->t('Profile URL'),
-						'$addr'                 => $notification->getAddr(),
-						'$hidden'               => ['hidden', DI::l10n()->t('Hide this contact from others'), $notification->isHidden(), ''],
-						'$knowyou'              => $notification->getKnowYou(),
-						'$approve'              => DI::l10n()->t('Approve'),
-						'$note'                 => $notification->getNote(),
-						'$request'              => $notification->getRequest(),
-						'$ignore'               => DI::l10n()->t('Ignore'),
-						'$discard'              => DI::l10n()->t('Discard'),
+						'$type'                  => $notification->getLabel(),
+						'$str_notification_type' => DI::l10n()->t('Notification type:'),
+						'$str_type'              => $notification->getType(),
+						'$intro_id'              => $notification->getIntroId(),
+						'$lbl_madeby'            => DI::l10n()->t('Suggested by:'),
+						'$madeby'                => $notification->getMadeBy(),
+						'$madeby_url'            => $notification->getMadeByUrl(),
+						'$madeby_zrl'            => $notification->getMadeByZrl(),
+						'$madeby_addr'           => $notification->getMadeByAddr(),
+						'$contact_id'            => $notification->getContactId(),
+						'$photo'                 => $notification->getPhoto(),
+						'$fullname'              => $notification->getName(),
+						'$url'                   => $notification->getUrl(),
+						'$zrl'                   => $notification->getZrl(),
+						'$lbl_url'               => DI::l10n()->t('Profile URL'),
+						'$addr'                  => $notification->getAddr(),
+						'$hidden'                => ['hidden', DI::l10n()->t('Hide this contact from others'), $notification->isHidden(), ''],
+						'$knowyou'               => $notification->getKnowYou(),
+						'$approve'               => DI::l10n()->t('Approve'),
+						'$note'                  => $notification->getNote(),
+						'$request'               => $notification->getRequest(),
+						'$ignore'                => DI::l10n()->t('Ignore'),
+						'$discard'               => DI::l10n()->t('Discard'),
 					]);
 					break;
 
@@ -108,12 +108,12 @@ class Introductions extends BaseNotifications
 						$lbl_knowyou = DI::l10n()->t('Claims to be known to you: ');
 						$knowyou     = ($notification->getKnowYou() ? DI::l10n()->t('yes') : DI::l10n()->t('no'));
 						$helptext    = DI::l10n()->t('Shall your connection be bidirectional or not?');
-						$helptext2   = DI::l10n()->t('Accepting %s as a friend allows %s to subscribe to your posts, and you will also receive updates from them in your news feed.', $notification['name'], $notification['name']);
-						$helptext3   = DI::l10n()->t('Accepting %s as a subscriber allows them to subscribe to your posts, but you will not receive updates from them in your news feed.', $notification['name']);
+						$helptext2   = DI::l10n()->t('Accepting %s as a friend allows %s to subscribe to your posts, and you will also receive updates from them in your news feed.', $notification->getName(), $notification->getName());
+						$helptext3   = DI::l10n()->t('Accepting %s as a subscriber allows them to subscribe to your posts, but you will not receive updates from them in your news feed.', $notification->getName());
 					} elseif ($notification->getNetwork() === Protocol::DIASPORA) {
 						$helptext  = DI::l10n()->t('Shall your connection be bidirectional or not?');
-						$helptext2 = DI::l10n()->t('Accepting %s as a friend allows %s to subscribe to your posts, and you will also receive updates from them in your news feed.', $notification['name'], $notification['name']);
-						$helptext3 = DI::l10n()->t('Accepting %s as a sharer allows them to subscribe to your posts, but you will not receive updates from them in your news feed.', $notification['name']);
+						$helptext2 = DI::l10n()->t('Accepting %s as a friend allows %s to subscribe to your posts, and you will also receive updates from them in your news feed.', $notification->getName(), $notification->getName());
+						$helptext3 = DI::l10n()->t('Accepting %s as a sharer allows them to subscribe to your posts, but you will not receive updates from them in your news feed.', $notification->getName());
 					}
 
 					$dfrn_tpl  = Renderer::getMarkupTemplate('notifications/netfriend.tpl');
@@ -136,10 +136,10 @@ class Introductions extends BaseNotifications
 						$action = 'dfrn_confirm';
 					}
 
-					$header = $notification['name'];
+					$header = $notification->getName();
 
-					if ($notification['addr'] != '') {
-						$header .= ' <' . $notification['addr'] . '>';
+					if ($notification->getAddr() != '') {
+						$header .= ' <' . $notification->getAddr() . '>';
 					}
 
 					$header .= ' (' . ContactSelector::networkToName($notification->getNetwork(), $notification->getUrl()) . ')';
@@ -151,39 +151,39 @@ class Introductions extends BaseNotifications
 					}
 
 					$notificationContent[] = Renderer::replaceMacros($notificationTemplate, [
-						'$type'                 => $notification->getLabel(),
-						'$header'               => $header,
-						'str_notification_type' => DI::l10n()->t('Notification type:'),
-						'str_type'              => $notification->getType(),
-						'$dfrn_text'            => $dfrn_text,
-						'$dfrn_id'              => $notification->getDfrnId(),
-						'$uid'                  => $notification->getUid(),
-						'$intro_id'             => $notification->getIntroId(),
-						'$contact_id'           => $notification->getContactId(),
-						'$photo'                => $notification->getPhoto(),
-						'$fullname'             => $notification->getName(),
-						'$location'             => $notification->getLocation(),
-						'$lbl_location'         => DI::l10n()->t('Location:'),
-						'$about'                => $notification->getAbout(),
-						'$lbl_about'            => DI::l10n()->t('About:'),
-						'$keywords'             => $notification->getKeywords(),
-						'$lbl_keywords'         => DI::l10n()->t('Tags:'),
-						'$gender'               => $notification->getGender(),
-						'$lbl_gender'           => DI::l10n()->t('Gender:'),
-						'$hidden'               => ['hidden', DI::l10n()->t('Hide this contact from others'), ($notification['hidden'] == 1), ''],
-						'$url'                  => $notification->getUrl(),
-						'$zrl'                  => $notification->getZrl(),
-						'$lbl_url'              => DI::l10n()->t('Profile URL'),
-						'$addr'                 => $notification->getAddr(),
-						'$lbl_knowyou'          => $lbl_knowyou,
-						'$lbl_network'          => DI::l10n()->t('Network:'),
-						'$network'              => ContactSelector::networkToName($notification->getNetwork(), $notification->getUrl()),
-						'$knowyou'              => $knowyou,
-						'$approve'              => DI::l10n()->t('Approve'),
-						'$note'                 => $notification->getNote(),
-						'$ignore'               => DI::l10n()->t('Ignore'),
-						'$discard'              => $discard,
-						'$action'               => $action,
+						'$type'                  => $notification->getLabel(),
+						'$header'                => $header,
+						'$str_notification_type' => DI::l10n()->t('Notification type:'),
+						'$str_type'              => $notification->getType(),
+						'$dfrn_text'             => $dfrn_text,
+						'$dfrn_id'               => $notification->getDfrnId(),
+						'$uid'                   => $notification->getUid(),
+						'$intro_id'              => $notification->getIntroId(),
+						'$contact_id'            => $notification->getContactId(),
+						'$photo'                 => $notification->getPhoto(),
+						'$fullname'              => $notification->getName(),
+						'$location'              => $notification->getLocation(),
+						'$lbl_location'          => DI::l10n()->t('Location:'),
+						'$about'                 => $notification->getAbout(),
+						'$lbl_about'             => DI::l10n()->t('About:'),
+						'$keywords'              => $notification->getKeywords(),
+						'$lbl_keywords'          => DI::l10n()->t('Tags:'),
+						'$gender'                => $notification->getGender(),
+						'$lbl_gender'            => DI::l10n()->t('Gender:'),
+						'$hidden'                => ['hidden', DI::l10n()->t('Hide this contact from others'), $notification->isHidden(), ''],
+						'$url'                   => $notification->getUrl(),
+						'$zrl'                   => $notification->getZrl(),
+						'$lbl_url'               => DI::l10n()->t('Profile URL'),
+						'$addr'                  => $notification->getAddr(),
+						'$lbl_knowyou'           => $lbl_knowyou,
+						'$lbl_network'           => DI::l10n()->t('Network:'),
+						'$network'               => ContactSelector::networkToName($notification->getNetwork(), $notification->getUrl()),
+						'$knowyou'               => $knowyou,
+						'$approve'               => DI::l10n()->t('Approve'),
+						'$note'                  => $notification->getNote(),
+						'$ignore'                => DI::l10n()->t('Ignore'),
+						'$discard'               => $discard,
+						'$action'                => $action,
 					]);
 					break;
 			}
diff --git a/src/Object/Notification/Introduction.php b/src/Object/Notification/Introduction.php
index 4972863ca..19fda4c15 100644
--- a/src/Object/Notification/Introduction.php
+++ b/src/Object/Notification/Introduction.php
@@ -12,7 +12,7 @@ class Introduction implements \JsonSerializable
 	/** @var string */
 	private $type = '';
 	/** @var integer */
-	private $intro_id = 0;
+	private $intro_id = -1;
 	/** @var string */
 	private $madeBy = '';
 	/** @var string */
@@ -22,7 +22,7 @@ class Introduction implements \JsonSerializable
 	/** @var string */
 	private $madeByAddr = '';
 	/** @var integer */
-	private $contactId = 0;
+	private $contactId = -1;
 	/** @var string */
 	private $photo = '';
 	/** @var string */
@@ -34,29 +34,29 @@ class Introduction implements \JsonSerializable
 	/** @var boolean */
 	private $hidden = false;
 	/** @var integer */
-	private $postNewFriend = 0;
-	/** @var string */
-	private $knowYou = '';
+	private $postNewFriend = -1;
+	/** @var boolean */
+	private $knowYou = false;
 	/** @var string */
 	private $note = '';
 	/** @var string */
 	private $request = '';
-	/** @var string */
-	private $dfrnId;
-	/** @var string */
-	private $addr;
-	/** @var string */
-	private $network;
 	/** @var int */
-	private $uid;
+	private $dfrnId = -1;
 	/** @var string */
-	private $keywords;
+	private $addr = '';
 	/** @var string */
-	private $gender;
+	private $network = '';
+	/** @var int */
+	private $uid = -1;
 	/** @var string */
-	private $location;
+	private $keywords = '';
 	/** @var string */
-	private $about;
+	private $gender = '';
+	/** @var string */
+	private $location = '';
+	/** @var string */
+	private $about = '';
 
 	/**
 	 * @return string
@@ -261,26 +261,26 @@ class Introduction implements \JsonSerializable
 	public function __construct(array $data = [])
 	{
 		$this->label         = $data['label'] ?? '';
-		$this->type          = $data['str_$type'] ?? '';
-		$this->intro_id      = $data['$intro_id'] ?? '';
-		$this->madeBy        = $data['$madeBy'] ?? '';
-		$this->madeByUrl     = $data['$madeByUrl'] ?? '';
-		$this->madeByZrl     = $data['$madeByZrl'] ?? '';
-		$this->madeByAddr    = $data['$madeByAddr'] ?? '';
-		$this->contactId     = $data['$contactId'] ?? '';
-		$this->photo         = $data['$photo'] ?? '';
-		$this->name          = $data['$name'] ?? '';
-		$this->url           = $data['$url'] ?? '';
-		$this->zrl           = $data['$zrl'] ?? '';
-		$this->hidden        = $data['$hidden'] ?? '';
-		$this->postNewFriend = $data['$postNewFriend'] ?? '';
-		$this->knowYou       = $data['$knowYou'] ?? '';
-		$this->note          = $data['$note'] ?? '';
-		$this->request       = $data['$request'] ?? '';
-		$this->dfrnId        = $data['dfrn_id'] ?? '';
+		$this->type          = $data['str_type'] ?? '';
+		$this->intro_id      = $data['$intro_id'] ?? -1;
+		$this->madeBy        = $data['madeBy'] ?? '';
+		$this->madeByUrl     = $data['madeByUrl'] ?? '';
+		$this->madeByZrl     = $data['madeByZrl'] ?? '';
+		$this->madeByAddr    = $data['madeByAddr'] ?? '';
+		$this->contactId     = $data['contactId'] ?? '';
+		$this->photo         = $data['photo'] ?? '';
+		$this->name          = $data['name'] ?? '';
+		$this->url           = $data['url'] ?? '';
+		$this->zrl           = $data['zrl'] ?? '';
+		$this->hidden        = $data['hidden'] ?? false;
+		$this->postNewFriend = $data['postNewFriend'] ?? '';
+		$this->knowYou       = $data['knowYou'] ?? false;
+		$this->note          = $data['note'] ?? '';
+		$this->request       = $data['request'] ?? '';
+		$this->dfrnId        = $data['dfrn_id'] ?? -1;
 		$this->addr          = $data['addr'] ?? '';
 		$this->network       = $data['network'] ?? '';
-		$this->uid           = $data['uid'] ?? '';
+		$this->uid           = $data['uid'] ?? -1;
 		$this->keywords      = $data['keywords'] ?? '';
 		$this->gender        = $data['gender'] ?? '';
 		$this->location      = $data['location'] ?? '';
diff --git a/src/Object/Notification/Notification.php b/src/Object/Notification/Notification.php
index 925927d84..bb29fd0af 100644
--- a/src/Object/Notification/Notification.php
+++ b/src/Object/Notification/Notification.php
@@ -94,18 +94,16 @@ class Notification implements \JsonSerializable
 		return $this->seen;
 	}
 
-	public function __construct(string $label = '', string $link = '', string $image = '',
-	                            string $url = '', string $text = '',
-	                            string $when = '', string $ago = '', bool $seen = false)
+	public function __construct(array $data)
 	{
-		$this->label = $label;
-		$this->link  = $link;
-		$this->image = $image;
-		$this->url   = $url;
-		$this->text  = $text;
-		$this->when  = $when;
-		$this->ago   = $ago;
-		$this->seen  = $seen;
+		$this->label = $data['label'] ?? '';
+		$this->link  = $data['link'] ?? '';
+		$this->image = $data['image'] ?? '';
+		$this->url   = $data['url'] ?? '';
+		$this->text  = $data['text'] ?? '';
+		$this->when  = $data['when'] ?? '';
+		$this->ago   = $data['ago'] ?? '';
+		$this->seen  = $data['seen'] ?? false;
 	}
 
 	/**