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