"item" is replaced by "post-view" / postupdate check added
[friendica.git/.git] / src / Content / Widget / TagCloud.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2020, Friendica
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Content\Widget;
23
24 use Friendica\Core\Renderer;
25 use Friendica\Database\DBA;
26 use Friendica\DI;
27 use Friendica\Model\Item;
28 use Friendica\Model\Tag;
29
30 /**
31  * TagCloud widget
32  *
33  * @author Rabuzarus
34  */
35 class TagCloud
36 {
37         /**
38          * Construct a tag/term cloud block for an user.
39          *
40          * @param int    $uid      The user ID.
41          * @param int    $count    Max number of displayed tags/terms.
42          * @param int    $owner_id The contact ID of the owner of the tagged items.
43          * @param string $flags    Special item flags.
44          * @param int    $type     The tag/term type.
45          *
46          * @return string       HTML formatted output.
47          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
48          */
49         public static function getHTML($uid, $count = 0, $owner_id = 0, $flags = '', $type = Tag::HASHTAG)
50         {
51                 $o = '';
52                 $r = self::tagadelic($uid, $count, $owner_id, $flags, $type);
53                 if (count($r)) {
54                         $contact = DBA::selectFirst('contact', ['url'], ['uid' => $uid, 'self' => true]);
55                         $url = DI::baseUrl()->remove($contact['url']);
56
57                         $tags = [];
58                         foreach ($r as $rr) {
59                                 $tag['level'] = $rr[2];
60                                 $tag['url'] = $url . '?tag=' . urlencode($rr[0]);
61                                 $tag['name'] = $rr[0];
62
63                                 $tags[] = $tag;
64                         }
65
66                         $tpl = Renderer::getMarkupTemplate('widget/tagcloud.tpl');
67                         $o = Renderer::replaceMacros($tpl, [
68                                 '$title' => DI::l10n()->t('Tags'),
69                                 '$tags' => $tags
70                         ]);
71                 }
72                 return $o;
73         }
74
75         /**
76          * Get alphabetical sorted array of used tags/terms of an user including
77          * a weighting by frequency of use.
78          *
79          * @param int    $uid      The user ID.
80          * @param int    $count    Max number of displayed tags/terms.
81          * @param int    $owner_id The contact id of the owner of the tagged items.
82          * @param string $flags    Special item flags.
83          * @param int    $type     The tag/term type.
84          *
85          * @return array        Alphabetical sorted array of used tags of an user.
86          * @throws \Exception
87          */
88         private static function tagadelic($uid, $count = 0, $owner_id = 0, $flags = '', $type = Tag::HASHTAG)
89         {
90                 $sql_options = Item::getPermissionsSQLByUserId($uid);
91                 $limit = $count ? sprintf('LIMIT %d', intval($count)) : '';
92
93                 if ($flags) {
94                         if ($flags === 'wall') {
95                                 $sql_options .= ' AND `post-view`.`wall` ';
96                         }
97                 }
98
99                 if ($owner_id) {
100                         $sql_options .= ' AND `post-view`.`owner-id` = ' . intval($owner_id) . ' ';
101                 }
102
103                 // Fetch tags
104                 $tag_stmt = DBA::p("SELECT `name`, COUNT(`name`) AS `total` FROM `tag-search-view`
105                         LEFT JOIN `post-view` ON `tag-search-view`.`uri-id` = `post-view`.`uri-id`
106                         WHERE `tag-search-view`.`uid` = ?
107                         AND `post-view`.`visible` AND NOT `post-view`.`deleted` AND NOT `post-view`.`moderated`
108                         $sql_options
109                         GROUP BY `name` ORDER BY `total` DESC $limit",
110                         $uid
111                 );
112                 if (!DBA::isResult($tag_stmt)) {
113                         return [];
114                 }
115
116                 $r = DBA::toArray($tag_stmt);
117
118                 return self::tagCalc($r);
119         }
120
121         /**
122          * Calculate weighting of tags according to the frequency of use.
123          *
124          * @param array $arr Array of tags/terms with tag/term name and total count of use.
125          * @return array     Alphabetical sorted array of used tags/terms of an user.
126          */
127         private static function tagCalc(array $arr)
128         {
129                 $tags = [];
130                 $min = 1e9;
131                 $max = -1e9;
132                 $x = 0;
133
134                 if (!$arr) {
135                         return [];
136                 }
137
138                 foreach ($arr as $rr) {
139                         $tags[$x][0] = $rr['name'];
140                         $tags[$x][1] = log($rr['total']);
141                         $tags[$x][2] = 0;
142                         $min = min($min, $tags[$x][1]);
143                         $max = max($max, $tags[$x][1]);
144                         $x ++;
145                 }
146
147                 usort($tags, 'self::tagsSort');
148                 $range = max(.01, $max - $min) * 1.0001;
149
150                 for ($x = 0; $x < count($tags); $x ++) {
151                         $tags[$x][2] = 1 + floor(9 * ($tags[$x][1] - $min) / $range);
152                 }
153
154                 return $tags;
155         }
156
157         /**
158          * Compare function to sort tags/terms alphabetically.
159          *
160          * @param string $a
161          * @param string $b
162          *
163          * @return int
164          */
165         private static function tagsSort($a, $b)
166         {
167                 if (strtolower($a[0]) == strtolower($b[0])) {
168                         return 0;
169                 }
170                 return ((strtolower($a[0]) < strtolower($b[0])) ? -1 : 1);
171         }
172 }