]> git.immae.eu Git - github/wallabag/wallabag.git/blob - src/Wallabag/CoreBundle/Entity/Entry.php
Merge pull request #3271 from wallabag/store-resolved-url
[github/wallabag/wallabag.git] / src / Wallabag / CoreBundle / Entity / Entry.php
1 <?php
2
3 namespace Wallabag\CoreBundle\Entity;
4
5 use Doctrine\Common\Collections\ArrayCollection;
6 use Doctrine\ORM\Mapping as ORM;
7 use Hateoas\Configuration\Annotation as Hateoas;
8 use JMS\Serializer\Annotation\Exclude;
9 use JMS\Serializer\Annotation\Groups;
10 use JMS\Serializer\Annotation\SerializedName;
11 use JMS\Serializer\Annotation\VirtualProperty;
12 use JMS\Serializer\Annotation\XmlRoot;
13 use Symfony\Component\Validator\Constraints as Assert;
14 use Wallabag\AnnotationBundle\Entity\Annotation;
15 use Wallabag\CoreBundle\Helper\EntityTimestampsTrait;
16 use Wallabag\CoreBundle\Helper\UrlHasher;
17 use Wallabag\UserBundle\Entity\User;
18
19 /**
20 * Entry.
21 *
22 * @XmlRoot("entry")
23 * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\EntryRepository")
24 * @ORM\Table(
25 * name="`entry`",
26 * options={"collate"="utf8mb4_unicode_ci", "charset"="utf8mb4"},
27 * indexes={
28 * @ORM\Index(name="created_at", columns={"created_at"}),
29 * @ORM\Index(name="uid", columns={"uid"}),
30 * @ORM\Index(name="hashed_url_user_id", columns={"user_id", "hashed_url"}, options={"lengths"={null, 40}}),
31 * @ORM\Index(name="hashed_given_url_user_id", columns={"user_id", "hashed_given_url"}, options={"lengths"={null, 40}})
32 * }
33 * )
34 * @ORM\HasLifecycleCallbacks()
35 * @Hateoas\Relation("self", href = "expr('/api/entries/' ~ object.getId())")
36 */
37 class Entry
38 {
39 use EntityTimestampsTrait;
40
41 /** @Serializer\XmlAttribute */
42 /**
43 * @var int
44 *
45 * @ORM\Column(name="id", type="integer")
46 * @ORM\Id
47 * @ORM\GeneratedValue(strategy="AUTO")
48 *
49 * @Groups({"entries_for_user", "export_all"})
50 */
51 private $id;
52
53 /**
54 * @var string
55 *
56 * @ORM\Column(name="uid", type="string", length=23, nullable=true)
57 *
58 * @Groups({"entries_for_user", "export_all"})
59 */
60 private $uid;
61
62 /**
63 * @var string
64 *
65 * @ORM\Column(name="title", type="text", nullable=true)
66 *
67 * @Groups({"entries_for_user", "export_all"})
68 */
69 private $title;
70
71 /**
72 * Define the url fetched by wallabag (the final url after potential redirections).
73 *
74 * @var string
75 *
76 * @Assert\NotBlank()
77 * @ORM\Column(name="url", type="text", nullable=true)
78 *
79 * @Groups({"entries_for_user", "export_all"})
80 */
81 private $url;
82
83 /**
84 * @var string
85 *
86 * @ORM\Column(name="hashed_url", type="string", length=40, nullable=true)
87 */
88 private $hashedUrl;
89
90 /**
91 * From where user retrieved/found the url (an other article, a twitter, or the given_url if non are provided).
92 *
93 * @var string
94 *
95 * @ORM\Column(name="origin_url", type="text", nullable=true)
96 *
97 * @Groups({"entries_for_user", "export_all"})
98 */
99 private $originUrl;
100
101 /**
102 * Define the url entered by the user (without redirections).
103 *
104 * @var string
105 *
106 * @ORM\Column(name="given_url", type="text", nullable=true)
107 *
108 * @Groups({"entries_for_user", "export_all"})
109 */
110 private $givenUrl;
111
112 /**
113 * @var string
114 *
115 * @ORM\Column(name="hashed_given_url", type="string", length=40, nullable=true)
116 */
117 private $hashedGivenUrl;
118
119 /**
120 * @var bool
121 *
122 * @Exclude
123 *
124 * @ORM\Column(name="is_archived", type="boolean")
125 *
126 * @Groups({"entries_for_user", "export_all"})
127 */
128 private $isArchived = false;
129
130 /**
131 * @var \DateTime
132 *
133 * @ORM\Column(name="archived_at", type="datetime", nullable=true)
134 *
135 * @Groups({"entries_for_user", "export_all"})
136 */
137 private $archivedAt = null;
138
139 /**
140 * @var bool
141 *
142 * @Exclude
143 *
144 * @ORM\Column(name="is_starred", type="boolean")
145 *
146 * @Groups({"entries_for_user", "export_all"})
147 */
148 private $isStarred = false;
149
150 /**
151 * @var string
152 *
153 * @ORM\Column(name="content", type="text", nullable=true)
154 *
155 * @Groups({"entries_for_user", "export_all"})
156 */
157 private $content;
158
159 /**
160 * @var \DateTime
161 *
162 * @ORM\Column(name="created_at", type="datetime")
163 *
164 * @Groups({"entries_for_user", "export_all"})
165 */
166 private $createdAt;
167
168 /**
169 * @var \DateTime
170 *
171 * @ORM\Column(name="updated_at", type="datetime")
172 *
173 * @Groups({"entries_for_user", "export_all"})
174 */
175 private $updatedAt;
176
177 /**
178 * @var \DateTime
179 *
180 * @ORM\Column(name="published_at", type="datetime", nullable=true)
181 *
182 * @Groups({"entries_for_user", "export_all"})
183 */
184 private $publishedAt;
185
186 /**
187 * @var array
188 *
189 * @ORM\Column(name="published_by", type="array", nullable=true)
190 *
191 * @Groups({"entries_for_user", "export_all"})
192 */
193 private $publishedBy;
194
195 /**
196 * @var \DateTime
197 *
198 * @ORM\Column(name="starred_at", type="datetime", nullable=true)
199 *
200 * @Groups({"entries_for_user", "export_all"})
201 */
202 private $starredAt = null;
203
204 /**
205 * @ORM\OneToMany(targetEntity="Wallabag\AnnotationBundle\Entity\Annotation", mappedBy="entry", cascade={"persist", "remove"})
206 * @ORM\JoinTable
207 *
208 * @Groups({"entries_for_user", "export_all"})
209 */
210 private $annotations;
211
212 /**
213 * @var string
214 *
215 * @ORM\Column(name="mimetype", type="text", nullable=true)
216 *
217 * @Groups({"entries_for_user", "export_all"})
218 */
219 private $mimetype;
220
221 /**
222 * @var string
223 *
224 * @ORM\Column(name="language", type="text", nullable=true)
225 *
226 * @Groups({"entries_for_user", "export_all"})
227 */
228 private $language;
229
230 /**
231 * @var int
232 *
233 * @ORM\Column(name="reading_time", type="integer", nullable=false)
234 *
235 * @Groups({"entries_for_user", "export_all"})
236 */
237 private $readingTime = 0;
238
239 /**
240 * @var string
241 *
242 * @ORM\Column(name="domain_name", type="text", nullable=true)
243 *
244 * @Groups({"entries_for_user", "export_all"})
245 */
246 private $domainName;
247
248 /**
249 * @var string
250 *
251 * @ORM\Column(name="preview_picture", type="text", nullable=true)
252 *
253 * @Groups({"entries_for_user", "export_all"})
254 */
255 private $previewPicture;
256
257 /**
258 * @var string
259 *
260 * @ORM\Column(name="http_status", type="string", length=3, nullable=true)
261 *
262 * @Groups({"entries_for_user", "export_all"})
263 */
264 private $httpStatus;
265
266 /**
267 * @var array
268 *
269 * @ORM\Column(name="headers", type="array", nullable=true)
270 *
271 * @Groups({"entries_for_user", "export_all"})
272 */
273 private $headers;
274
275 /**
276 * @Exclude
277 *
278 * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="entries")
279 *
280 * @Groups({"export_all"})
281 */
282 private $user;
283
284 /**
285 * @ORM\ManyToMany(targetEntity="Tag", inversedBy="entries", cascade={"persist"})
286 * @ORM\JoinTable(
287 * name="entry_tag",
288 * joinColumns={
289 * @ORM\JoinColumn(name="entry_id", referencedColumnName="id", onDelete="cascade")
290 * },
291 * inverseJoinColumns={
292 * @ORM\JoinColumn(name="tag_id", referencedColumnName="id", onDelete="cascade")
293 * }
294 * )
295 */
296 private $tags;
297
298 /*
299 * @param User $user
300 */
301 public function __construct(User $user)
302 {
303 $this->user = $user;
304 $this->tags = new ArrayCollection();
305 }
306
307 /**
308 * Get id.
309 *
310 * @return int
311 */
312 public function getId()
313 {
314 return $this->id;
315 }
316
317 /**
318 * Set title.
319 *
320 * @param string $title
321 *
322 * @return Entry
323 */
324 public function setTitle($title)
325 {
326 $this->title = $title;
327
328 return $this;
329 }
330
331 /**
332 * Get title.
333 *
334 * @return string
335 */
336 public function getTitle()
337 {
338 return $this->title;
339 }
340
341 /**
342 * Set url.
343 *
344 * @param string $url
345 *
346 * @return Entry
347 */
348 public function setUrl($url)
349 {
350 $this->url = $url;
351 $this->hashedUrl = UrlHasher::hashUrl($url);
352
353 return $this;
354 }
355
356 /**
357 * Get url.
358 *
359 * @return string
360 */
361 public function getUrl()
362 {
363 return $this->url;
364 }
365
366 /**
367 * Set isArchived.
368 *
369 * @param bool $isArchived
370 *
371 * @return Entry
372 */
373 public function setArchived($isArchived)
374 {
375 $this->isArchived = $isArchived;
376
377 return $this;
378 }
379
380 /**
381 * update isArchived and archive_at fields.
382 *
383 * @param bool $isArchived
384 *
385 * @return Entry
386 */
387 public function updateArchived($isArchived = false)
388 {
389 $this->setArchived($isArchived);
390 $this->setArchivedAt(null);
391 if ($this->isArchived()) {
392 $this->setArchivedAt(new \DateTime());
393 }
394
395 return $this;
396 }
397
398 /**
399 * @return \DateTime|null
400 */
401 public function getArchivedAt()
402 {
403 return $this->archivedAt;
404 }
405
406 /**
407 * @param \DateTime|null $archivedAt
408 *
409 * @return Entry
410 */
411 public function setArchivedAt($archivedAt = null)
412 {
413 $this->archivedAt = $archivedAt;
414
415 return $this;
416 }
417
418 /**
419 * Get isArchived.
420 *
421 * @return bool
422 */
423 public function isArchived()
424 {
425 return $this->isArchived;
426 }
427
428 /**
429 * @VirtualProperty
430 * @SerializedName("is_archived")
431 * @Groups({"entries_for_user", "export_all"})
432 */
433 public function is_Archived()
434 {
435 return (int) $this->isArchived();
436 }
437
438 public function toggleArchive()
439 {
440 $this->updateArchived($this->isArchived() ^ 1);
441
442 return $this;
443 }
444
445 /**
446 * Set isStarred.
447 *
448 * @param bool $isStarred
449 *
450 * @return Entry
451 */
452 public function setStarred($isStarred)
453 {
454 $this->isStarred = $isStarred;
455
456 return $this;
457 }
458
459 /**
460 * Get isStarred.
461 *
462 * @return bool
463 */
464 public function isStarred()
465 {
466 return $this->isStarred;
467 }
468
469 /**
470 * @VirtualProperty
471 * @SerializedName("is_starred")
472 * @Groups({"entries_for_user", "export_all"})
473 */
474 public function is_Starred()
475 {
476 return (int) $this->isStarred();
477 }
478
479 public function toggleStar()
480 {
481 $this->isStarred = $this->isStarred() ^ 1;
482
483 return $this;
484 }
485
486 /**
487 * Set content.
488 *
489 * @param string $content
490 *
491 * @return Entry
492 */
493 public function setContent($content)
494 {
495 $this->content = $content;
496
497 return $this;
498 }
499
500 /**
501 * Get content.
502 *
503 * @return string
504 */
505 public function getContent()
506 {
507 return $this->content;
508 }
509
510 /**
511 * @return User
512 */
513 public function getUser()
514 {
515 return $this->user;
516 }
517
518 /**
519 * @VirtualProperty
520 * @SerializedName("user_name")
521 */
522 public function getUserName()
523 {
524 return $this->user->getUserName();
525 }
526
527 /**
528 * @VirtualProperty
529 * @SerializedName("user_email")
530 */
531 public function getUserEmail()
532 {
533 return $this->user->getEmail();
534 }
535
536 /**
537 * @VirtualProperty
538 * @SerializedName("user_id")
539 */
540 public function getUserId()
541 {
542 return $this->user->getId();
543 }
544
545 /**
546 * Set created_at.
547 * Only used when importing data from an other service.
548 *
549 * @param \DateTime $createdAt
550 *
551 * @return Entry
552 */
553 public function setCreatedAt(\DateTime $createdAt)
554 {
555 $this->createdAt = $createdAt;
556
557 return $this;
558 }
559
560 /**
561 * @return \DateTime
562 */
563 public function getCreatedAt()
564 {
565 return $this->createdAt;
566 }
567
568 /**
569 * @return \DateTime
570 */
571 public function getUpdatedAt()
572 {
573 return $this->updatedAt;
574 }
575
576 /**
577 * @return \DateTime|null
578 */
579 public function getStarredAt()
580 {
581 return $this->starredAt;
582 }
583
584 /**
585 * @param \DateTime|null $starredAt
586 *
587 * @return Entry
588 */
589 public function setStarredAt($starredAt = null)
590 {
591 $this->starredAt = $starredAt;
592
593 return $this;
594 }
595
596 /**
597 * update isStarred and starred_at fields.
598 *
599 * @param bool $isStarred
600 *
601 * @return Entry
602 */
603 public function updateStar($isStarred = false)
604 {
605 $this->setStarred($isStarred);
606 $this->setStarredAt(null);
607 if ($this->isStarred()) {
608 $this->setStarredAt(new \DateTime());
609 }
610
611 return $this;
612 }
613
614 /**
615 * @return ArrayCollection<Annotation>
616 */
617 public function getAnnotations()
618 {
619 return $this->annotations;
620 }
621
622 /**
623 * @param Annotation $annotation
624 */
625 public function setAnnotation(Annotation $annotation)
626 {
627 $this->annotations[] = $annotation;
628 }
629
630 /**
631 * @return string
632 */
633 public function getMimetype()
634 {
635 return $this->mimetype;
636 }
637
638 /**
639 * @param string $mimetype
640 */
641 public function setMimetype($mimetype)
642 {
643 $this->mimetype = $mimetype;
644 }
645
646 /**
647 * @return int
648 */
649 public function getReadingTime()
650 {
651 return $this->readingTime;
652 }
653
654 /**
655 * @param int $readingTime
656 */
657 public function setReadingTime($readingTime)
658 {
659 $this->readingTime = $readingTime;
660 }
661
662 /**
663 * @return string
664 */
665 public function getDomainName()
666 {
667 return $this->domainName;
668 }
669
670 /**
671 * @param string $domainName
672 */
673 public function setDomainName($domainName)
674 {
675 $this->domainName = $domainName;
676 }
677
678 /**
679 * @return ArrayCollection
680 */
681 public function getTags()
682 {
683 return $this->tags;
684 }
685
686 /**
687 * @VirtualProperty
688 * @SerializedName("tags")
689 * @Groups({"entries_for_user", "export_all"})
690 */
691 public function getSerializedTags()
692 {
693 $data = [];
694 foreach ($this->tags as $tag) {
695 $data[] = $tag->getLabel();
696 }
697
698 return $data;
699 }
700
701 /**
702 * @param Tag $tag
703 */
704 public function addTag(Tag $tag)
705 {
706 if ($this->tags->contains($tag)) {
707 return;
708 }
709
710 // check if tag already exist but has not yet be persisted
711 // it seems that the previous condition with `contains()` doesn't check that case
712 foreach ($this->tags as $existingTag) {
713 if ($existingTag->getLabel() === $tag->getLabel()) {
714 return;
715 }
716 }
717
718 $this->tags->add($tag);
719 $tag->addEntry($this);
720 }
721
722 /**
723 * Remove the given tag from the entry (if the tag is associated).
724 *
725 * @param Tag $tag
726 */
727 public function removeTag(Tag $tag)
728 {
729 if (!$this->tags->contains($tag)) {
730 return;
731 }
732
733 $this->tags->removeElement($tag);
734 $tag->removeEntry($this);
735 }
736
737 /**
738 * Remove all assigned tags from the entry.
739 */
740 public function removeAllTags()
741 {
742 foreach ($this->tags as $tag) {
743 $this->tags->removeElement($tag);
744 $tag->removeEntry($this);
745 }
746 }
747
748 /**
749 * Set previewPicture.
750 *
751 * @param string $previewPicture
752 *
753 * @return Entry
754 */
755 public function setPreviewPicture($previewPicture)
756 {
757 $this->previewPicture = $previewPicture;
758
759 return $this;
760 }
761
762 /**
763 * Get previewPicture.
764 *
765 * @return string
766 */
767 public function getPreviewPicture()
768 {
769 return $this->previewPicture;
770 }
771
772 /**
773 * Set language.
774 *
775 * @param string $language
776 *
777 * @return Entry
778 */
779 public function setLanguage($language)
780 {
781 $this->language = $language;
782
783 return $this;
784 }
785
786 /**
787 * Get language.
788 *
789 * @return string
790 */
791 public function getLanguage()
792 {
793 return $this->language;
794 }
795
796 /**
797 * @return string|null
798 */
799 public function getUid()
800 {
801 return $this->uid;
802 }
803
804 /**
805 * @param string $uid
806 *
807 * @return Entry
808 */
809 public function setUid($uid)
810 {
811 $this->uid = $uid;
812
813 return $this;
814 }
815
816 public function generateUid()
817 {
818 if (null === $this->uid) {
819 // @see http://blog.kevingomez.fr/til/2015/07/26/why-is-uniqid-slow/ for true parameter
820 $this->uid = uniqid('', true);
821 }
822 }
823
824 public function cleanUid()
825 {
826 $this->uid = null;
827 }
828
829 /**
830 * Used in the entries filter so it's more explicit for the end user than the uid.
831 * Also used in the API.
832 *
833 * @VirtualProperty
834 * @SerializedName("is_public")
835 * @Groups({"entries_for_user"})
836 *
837 * @return bool
838 */
839 public function isPublic()
840 {
841 return null !== $this->uid;
842 }
843
844 /**
845 * @return string
846 */
847 public function getHttpStatus()
848 {
849 return $this->httpStatus;
850 }
851
852 /**
853 * @param string $httpStatus
854 *
855 * @return Entry
856 */
857 public function setHttpStatus($httpStatus)
858 {
859 $this->httpStatus = $httpStatus;
860
861 return $this;
862 }
863
864 /**
865 * @return \Datetime
866 */
867 public function getPublishedAt()
868 {
869 return $this->publishedAt;
870 }
871
872 /**
873 * @param \Datetime $publishedAt
874 *
875 * @return Entry
876 */
877 public function setPublishedAt(\Datetime $publishedAt)
878 {
879 $this->publishedAt = $publishedAt;
880
881 return $this;
882 }
883
884 /**
885 * @return array
886 */
887 public function getPublishedBy()
888 {
889 return $this->publishedBy;
890 }
891
892 /**
893 * @param array $publishedBy
894 *
895 * @return Entry
896 */
897 public function setPublishedBy($publishedBy)
898 {
899 $this->publishedBy = $publishedBy;
900
901 return $this;
902 }
903
904 /**
905 * @return array
906 */
907 public function getHeaders()
908 {
909 return $this->headers;
910 }
911
912 /**
913 * @param array $headers
914 *
915 * @return Entry
916 */
917 public function setHeaders($headers)
918 {
919 $this->headers = $headers;
920
921 return $this;
922 }
923
924 /**
925 * Set origin url.
926 *
927 * @param string $originUrl
928 *
929 * @return Entry
930 */
931 public function setOriginUrl($originUrl)
932 {
933 $this->originUrl = $originUrl;
934
935 return $this;
936 }
937
938 /**
939 * Get origin url.
940 *
941 * @return string
942 */
943 public function getOriginUrl()
944 {
945 return $this->originUrl;
946 }
947
948 /**
949 * Set given url.
950 *
951 * @param string $givenUrl
952 *
953 * @return Entry
954 */
955 public function setGivenUrl($givenUrl)
956 {
957 $this->givenUrl = $givenUrl;
958 $this->hashedGivenUrl = UrlHasher::hashUrl($givenUrl);
959
960 return $this;
961 }
962
963 /**
964 * Get given url.
965 *
966 * @return string
967 */
968 public function getGivenUrl()
969 {
970 return $this->givenUrl;
971 }
972
973 /**
974 * @return string
975 */
976 public function getHashedUrl()
977 {
978 return $this->hashedUrl;
979 }
980
981 /**
982 * @param mixed $hashedUrl
983 *
984 * @return Entry
985 */
986 public function setHashedUrl($hashedUrl)
987 {
988 $this->hashedUrl = $hashedUrl;
989
990 return $this;
991 }
992 }