Profile_tag.php 11.7 KB
Newer Older
Evan Prodromou's avatar
Evan Prodromou committed
1 2 3 4 5
<?php
/**
 * Table Definition for profile_tag
 */

6
class Profile_tag extends Managed_DataObject
Evan Prodromou's avatar
Evan Prodromou committed
7 8 9 10 11 12 13
{
    public $__table = 'profile_tag';                     // table name
    public $tagger;                          // int(4)  primary_key not_null
    public $tagged;                          // int(4)  primary_key not_null
    public $tag;                             // varchar(64)  primary_key not_null
    public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP

14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
    public static function schemaDef()
    {
        return array(

            'fields' => array(
                'tagger' => array('type' => 'int', 'not null' => true, 'description' => 'user making the tag'),
                'tagged' => array('type' => 'int', 'not null' => true, 'description' => 'profile tagged'),
                'tag' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'hash tag associated with this notice'),
                'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date the tag was added'),
            ),
            'primary key' => array('tagger', 'tagged', 'tag'),
            'foreign keys' => array(
                'profile_tag_tagger_fkey' => array('profile', array('tagger' => 'id')),
                'profile_tag_tagged_fkey' => array('profile', array('tagged' => 'id')),
                'profile_tag_tag_fkey' => array('profile_list', array('tag' => 'tag')),
            ),
            'indexes' => array(
                'profile_tag_modified_idx' => array('modified'),
                'profile_tag_tagger_tag_idx' => array('tagger', 'tag'),
                'profile_tag_tagged_idx' => array('tagged'),
            ),
        );
    }

38 39 40 41 42 43 44 45 46 47
    function links()
    {
        return array('tagger,tag' => 'profile_list:tagger,tag');
    }

    function getMeta()
    {
        return Profile_list::pkeyGet(array('tagger' => $this->tagger, 'tag' => $this->tag));
    }

48 49 50 51 52 53 54 55 56 57
    static function getSelfTagsArray(Profile $target)
    {
        return self::getTagsArray($target->getID(), $target->getID(), $target);
    }

    static function setSelfTags(Profile $target, array $newtags, array $privacy=array())
    {
        return self::setTags($target->getID(), $target->getID(), $newtags, $privacy);
    }

58 59 60 61 62 63 64 65
    static function getTags($tagger, $tagged, $auth_user=null) {

        $profile_list = new Profile_list();
        $include_priv = 1;

        if (!($auth_user instanceof User ||
            $auth_user instanceof Profile) ||
            ($auth_user->id !== $tagger)) {
66

67 68 69 70 71 72 73 74 75
            $profile_list->private = false;
            $include_priv = 0;
        }

        $key = sprintf('profile_tag:tagger_tagged_privacy:%d-%d-%d', $tagger, $tagged, $include_priv);
        $tags = Profile_list::getCached($key);
        if ($tags !== false) {
            return $tags;
        }
76

77 78 79 80 81 82 83
        $qry = 'select profile_list.* from profile_list left join '.
               'profile_tag on (profile_list.tag = profile_tag.tag and '.
               'profile_list.tagger = profile_tag.tagger) where '.
               'profile_tag.tagger = %d and profile_tag.tagged = %d ';
        $qry = sprintf($qry, $tagger, $tagged);

        if (!$include_priv) {
Evan Prodromou's avatar
Evan Prodromou committed
84
            $qry .= ' and profile_list.private = 0';
85 86 87
        }

        $profile_list->query($qry);
88 89

        Profile_list::setCache($key, $profile_list);
90

91 92 93
        return $profile_list;
    }

94
    static function getTagsArray($tagger, $tagged, Profile $scoped=null)
95 96
    {
        $ptag = new Profile_tag();
97

Evan Prodromou's avatar
Evan Prodromou committed
98 99 100 101 102 103 104
        $qry = sprintf('select profile_tag.tag '.
                       'from profile_tag join profile_list '.
                       ' on (profile_tag.tagger = profile_list.tagger ' .
                       '     and profile_tag.tag = profile_list.tag) ' .
                       'where profile_tag.tagger = %d ' .
                       'and   profile_tag.tagged = %d ',
                       $tagger, $tagged);
105

106
        if (!$scoped instanceof Profile || $scoped->getID() !== $tagger) {
107
            $qry .= 'and profile_list.private = 0';
108
        }
109

110
        $tags = array();
111

Evan Prodromou's avatar
Evan Prodromou committed
112
        $ptag->query($qry);
113

114 115 116
        while ($ptag->fetch()) {
            $tags[] = $ptag->tag;
        }
117

118 119
        return $tags;
    }
120

121
    static function setTags($tagger, $tagged, array $newtags, array $privacy=array()) {
122

123
        $newtags = array_unique($newtags);
124
        $oldtags = self::getTagsArray($tagger, $tagged, Profile::getByID($tagger));
125 126

        $ptag = new Profile_tag();
127

128
        // Delete stuff that's in old and not in new
129

130
        $to_delete = array_diff($oldtags, $newtags);
131

132
        // Insert stuff that's in new and not in old
133

134
        $to_insert = array_diff($newtags, $oldtags);
135

136 137 138
        foreach ($to_delete as $deltag) {
            self::unTag($tagger, $tagged, $deltag);
        }
139

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
        foreach ($to_insert as $instag) {
            $private = isset($privacy[$instag]) ? $privacy[$instag] : false;
            self::setTag($tagger, $tagged, $instag, null, $private);
        }
        return true;
    }

    # set a single tag
    static function setTag($tagger, $tagged, $tag, $desc=null, $private=false) {

        $ptag = Profile_tag::pkeyGet(array('tagger' => $tagger,
                                           'tagged' => $tagged,
                                           'tag' => $tag));

        # if tag already exists, return it
155
        if ($ptag instanceof Profile_tag) {
156 157 158
            return $ptag;
        }

159 160
        $tagger_profile = Profile::getByID($tagger);
        $tagged_profile = Profile::getByID($tagged);
161 162 163 164

        if (Event::handle('StartTagProfile', array($tagger_profile, $tagged_profile, $tag))) {

            if (!$tagger_profile->canTag($tagged_profile)) {
165
                // TRANS: Client exception thrown trying to set a tag for a user that cannot be tagged.
166 167 168 169 170 171 172 173
                throw new ClientException(_('You cannot tag this user.'));
            }

            $tags = new Profile_list();
            $tags->tagger = $tagger;
            $count = (int) $tags->count('distinct tag');

            if ($count >= common_config('peopletag', 'maxtags')) {
174
                // TRANS: Client exception thrown trying to set more tags than allowed.
175 176 177 178 179 180 181 182 183 184 185 186
                throw new ClientException(sprintf(_('You already have created %d or more tags ' .
                                                    'which is the maximum allowed number of tags. ' .
                                                    'Try using or deleting some existing tags.'),
                                                    common_config('peopletag', 'maxtags')));
            }

            $plist = new Profile_list();
            $plist->query('BEGIN');

            $profile_list = Profile_list::ensureTag($tagger, $tag, $desc, $private);

            if ($profile_list->taggedCount() >= common_config('peopletag', 'maxpeople')) {
187 188
                // TRANS: Client exception thrown when trying to add more people than allowed to a list.
                throw new ClientException(sprintf(_('You already have %1$d or more people in list %2$s, ' .
189
                                                    'which is the maximum allowed number. ' .
190
                                                    'Try unlisting others first.'),
191 192 193 194 195 196 197 198 199 200
                                                    common_config('peopletag', 'maxpeople'), $tag));
            }

            $newtag = new Profile_tag();

            $newtag->tagger = $tagger;
            $newtag->tagged = $tagged;
            $newtag->tag = $tag;

            $result = $newtag->insert();
201

202
            if (!$result) {
203
                common_log_db_error($newtag, 'INSERT', __FILE__);
204
                $plist->query('ROLLBACK');
205 206 207 208 209 210 211 212 213 214
                return false;
            }

            try {
                $plist->query('COMMIT');
                Event::handle('EndTagProfile', array($newtag));
            } catch (Exception $e) {
                $newtag->delete();
                $profile_list->delete();
                throw $e;
215
            }
216 217 218

            $profile_list->taggedCount(true);
            self::blowCaches($tagger, $tagged);
219
        }
220

221 222 223 224 225 226 227 228 229 230 231 232 233 234
        return $newtag;
    }

    static function unTag($tagger, $tagged, $tag) {
        $ptag = Profile_tag::pkeyGet(array('tagger' => $tagger,
                                           'tagged' => $tagged,
                                           'tag'    => $tag));
        if (!$ptag) {
            return true;
        }

        if (Event::handle('StartUntagProfile', array($ptag))) {
            $orig = clone($ptag);
            $result = $ptag->delete();
235
            if ($result === false) {
236
                common_log_db_error($this, 'DELETE', __FILE__);
237 238
                return false;
            }
239
            Event::handle('EndUntagProfile', array($orig));
240 241 242
            $profile_list = Profile_list::pkeyGet(array('tag' => $tag, 'tagger' => $tagger));
            if (!empty($profile_list)) {
                $profile_list->taggedCount(true);
243
            }
244 245
            self::blowCaches($tagger, $tagged);
            return true;
246
        }
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
    }

    // @fixme: move this to Profile_list?
    static function cleanup($profile_list) {
        $ptag = new Profile_tag();
        $ptag->tagger = $profile_list->tagger;
        $ptag->tag = $profile_list->tag;
        $ptag->find();

        while($ptag->fetch()) {
            if (Event::handle('StartUntagProfile', array($ptag))) {
                $orig = clone($ptag);
                $result = $ptag->delete();
                if (!$result) {
                    common_log_db_error($this, 'DELETE', __FILE__);
                }
                Event::handle('EndUntagProfile', array($orig));
            }
        }
    }
267

268 269 270 271 272 273 274
    // move a tag!
    static function moveTag($orig, $new) {
        $tags = new Profile_tag();
        $qry = 'UPDATE profile_tag SET ' .
               'tag = "%s", tagger = "%s" ' .
               'WHERE tag = "%s" ' .
               'AND tagger = "%s"';
275 276 277 278 279
        $result = $tags->query(sprintf($qry,
                                       $tags->escape($new->tag),
                                       $tags->escape($new->tagger),
                                       $tags->escape($orig->tag),
                                       $tags->escape($orig->tagger)));
280

281
        if ($result === false) {
282
            common_log_db_error($tags, 'UPDATE', __FILE__);
283
            throw new Exception('Could not move Profile_tag, see db log for details.');
284
        }
285
        return $result;
286
    }
287

288 289 290
    static function blowCaches($tagger, $tagged) {
        foreach (array(0, 1) as $perm) {
            self::blow(sprintf('profile_tag:tagger_tagged_privacy:%d-%d-%d', $tagger, $tagged, $perm));
291
        }
292
        return true;
293
    }
294

295
    // Return profiles with a given tag
296 297 298 299 300
    static function getTagged($tagger, $tag) {
        $profile = new Profile();
        $profile->query('SELECT profile.* ' .
                        'FROM profile JOIN profile_tag ' .
                        'ON profile.id = profile_tag.tagged ' .
301 302
                        'WHERE profile_tag.tagger = ' . $profile->escape($tagger) . ' ' .
                        'AND profile_tag.tag = "' . $profile->escape($tag) . '" ');
303 304 305 306
        $tagged = array();
        while ($profile->fetch()) {
            $tagged[] = clone($profile);
        }
307
        return true;
308
    }
309 310 311 312 313 314 315 316 317 318 319 320

    function insert()
    {
        $result = parent::insert();
        if ($result) {
            self::blow('profile_list:tagged_count:%d:%s', 
                       $this->tagger,
                       $this->tag);
        }
        return $result;
    }

321
    function delete($useWhere=false)
322
    {
323 324
        $result = parent::delete($useWhere);
        if ($result !== false) {
325 326 327 328 329 330
            self::blow('profile_list:tagged_count:%d:%s', 
                       $this->tagger,
                       $this->tag);
        }
        return $result;
    }
Evan Prodromou's avatar
Evan Prodromou committed
331
}