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