Overview

Packages

  • application
    • commands
    • components
      • actions
      • filters
      • leftWidget
      • permissions
      • sortableWidget
      • util
      • webupdater
      • x2flow
        • actions
        • triggers
      • X2GridView
      • X2Settings
    • controllers
    • models
      • embedded
    • modules
      • accounts
        • controllers
        • models
      • actions
        • controllers
        • models
      • calendar
        • controllers
        • models
      • charts
        • models
      • contacts
        • controllers
        • models
      • docs
        • components
        • controllers
        • models
      • groups
        • controllers
        • models
      • marketing
        • components
        • controllers
        • models
      • media
        • controllers
        • models
      • mobile
        • components
      • opportunities
        • controllers
        • models
      • products
        • controllers
        • models
      • quotes
        • controllers
        • models
      • services
        • controllers
        • models
      • template
        • models
      • users
        • controllers
        • models
      • workflow
        • controllers
        • models
      • x2Leads
        • controllers
        • models
  • None
  • system
    • base
    • caching
    • console
    • db
      • ar
      • schema
    • validators
    • web
      • actions
      • auth
      • helpers
      • widgets
        • captcha
        • pagers
  • zii
    • widgets
      • grid

Classes

  • Media
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /*****************************************************************************************
  3:  * X2Engine Open Source Edition is a customer relationship management program developed by
  4:  * X2Engine, Inc. Copyright (C) 2011-2016 X2Engine Inc.
  5:  * 
  6:  * This program is free software; you can redistribute it and/or modify it under
  7:  * the terms of the GNU Affero General Public License version 3 as published by the
  8:  * Free Software Foundation with the addition of the following permission added
  9:  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
 10:  * IN WHICH THE COPYRIGHT IS OWNED BY X2ENGINE, X2ENGINE DISCLAIMS THE WARRANTY
 11:  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 12:  * 
 13:  * This program is distributed in the hope that it will be useful, but WITHOUT
 14:  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 15:  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
 16:  * details.
 17:  * 
 18:  * You should have received a copy of the GNU Affero General Public License along with
 19:  * this program; if not, see http://www.gnu.org/licenses or write to the Free
 20:  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 21:  * 02110-1301 USA.
 22:  * 
 23:  * You can contact X2Engine, Inc. P.O. Box 66752, Scotts Valley,
 24:  * California 95067, USA. or at email address contact@x2engine.com.
 25:  * 
 26:  * The interactive user interfaces in modified source and object code versions
 27:  * of this program must display Appropriate Legal Notices, as required under
 28:  * Section 5 of the GNU Affero General Public License version 3.
 29:  * 
 30:  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
 31:  * these Appropriate Legal Notices must retain the display of the "Powered by
 32:  * X2Engine" logo. If the display of the logo is not reasonably feasible for
 33:  * technical reasons, the Appropriate Legal Notices must display the words
 34:  * "Powered by X2Engine".
 35:  *****************************************************************************************/
 36: 
 37: /**
 38:  * This is the model class for table "x2_media".
 39:  *
 40:  * @package application.modules.media.models
 41:  * @property integer $id
 42:  * @property string $associationType
 43:  * @property integer $associationId
 44:  * @property string $fileName
 45:  * @property string $uploadedBy
 46:  * @property string $createDate
 47:  */
 48: class Media extends X2Model {
 49: 
 50:     public $supportsWorkflow = false;
 51:     public $_path;
 52:     public $_url;
 53:     protected $fieldFormatterClass = 'MediaFieldFormatter';
 54: 
 55:     /**
 56:      * Returns the static model of the specified AR class.
 57:      * @return Media the static model class
 58:      */
 59:     public static function model($className = __CLASS__) {
 60:         return parent::model($className);
 61:     }
 62: 
 63:      
 64: 
 65:     private static $_menuLogo;
 66:     public static function getMenuLogo () {
 67:         if (!isset (self::$_menuLogo)) {
 68:             $logo = Media::model()->findByAttributes(array(
 69:                 'associationId' => 1,
 70:                 'associationType' => 'logo'
 71:             ));
 72:             self::$_menuLogo = $logo;
 73:         }
 74:         return self::$_menuLogo;
 75:     }
 76: 
 77:     /**
 78:      * @return string the associated database table name
 79:      */
 80:     public function tableName() {
 81:         return 'x2_media';
 82:     }
 83: 
 84:     /**
 85:      * Called after removing media or changing the filename field. Checks for existing references
 86:      * to filename and deletes file if none exist.
 87:      */
 88:     private function collectGarbage (array $exclude = array ()) {
 89:         if (!in_array ($this->getPath (), $exclude) && file_exists($this->getPath())) {
 90:             $media = Media::model()->findByAttributes(array(
 91:                 'uploadedBy' => $this->uploadedBy,
 92:                 'fileName' => $this->fileName
 93:             ));
 94: 
 95:             // Only delete the file if it is the last media object
 96:             // To use it. 
 97:             if (!$media) {
 98:                 unlink($this->getPath());
 99:             }
100:         }
101:     }
102: 
103:     public function afterDelete() {
104:         parent::afterDelete();
105:         // Reset path if name was changed:
106:         $this->_path = null;
107:         $this->collectGarbage ();
108: 
109:         // if theme is deleted which is default, unset default theme setting
110:         if ($this->id === Yii::app()->settings->defaultTheme) {
111:             Yii::app()->settings->defaultTheme = null;
112:             Yii::app()->settings->enforceDefaultTheme = false;
113:             Yii::app()->settings->save();
114:         }
115:     }
116: 
117:     public function resolveNameConflicts () {
118:         $found = (int) Media::model()->countByAttributes (array('fileName' => $this->fileName));
119: 
120:         // rename file if there name conflicts by suffixing "(n)"
121:         if ($found) {
122:             $count = 1;
123:             $newName = $this->fileName;
124:             $ext = CFileHelper::getExtension ($newName);
125:             $base = preg_replace ('/\.'.preg_quote ($ext).'$/', '', $newName);
126:             while ($found) {
127:                 $newName = "$base($count).$ext";
128:                 $found = (int) Media::model()->countByAttributes(array('fileName' => $newName));
129:                 $count++;
130:             }
131:             $this->fileName = $newName;
132:         }
133:     }
134: 
135:     public function beforeSave() {
136:         if (empty($this->associationType)) {
137:             $this->associationType = 'none';
138:         }
139: 
140:         if (empty($this->uploadedBy)) {
141:             $this->uploadedBy = Yii::app()->user->name;
142:         }
143: 
144:         if (empty($this->name)) {
145:             $this->name = $this->fileName;
146:         }
147:         if ($this->isNewRecord && $this->associationType !== 'theme' && empty($this->accessKey)) {
148:             $this->accessKey = bin2hex(openssl_random_pseudo_bytes(32));
149:         }
150: 
151:         $this->getPath();
152: 
153:         return parent::beforeSave();
154:     }
155: 
156:     public function behaviors() {
157:         $behaviors = array_merge(parent::behaviors(), array(
158:             'X2LinkableBehavior' => array(
159:                 'class' => 'X2LinkableBehavior',
160:                 'module' => 'media',
161:                 'autoCompleteSource' => null
162:             ),
163:             'ERememberFiltersBehavior' => array(
164:                 'class' => 'application.components.ERememberFiltersBehavior',
165:                 'defaults' => array(),
166:                 'defaultStickOnClear' => false
167:             )
168:         ));
169:         unset($behaviors['changelog']);
170:         return $behaviors;
171:     }
172: 
173:     /**
174:      * @return array validation rules for model attributes.
175:      */
176:     public function rules() {
177:         // NOTE: you should only define rules for those attributes that
178:         // will receive user inputs.
179: 
180:         return array_merge (
181:             $this->getBehaviorRules (),
182:             array(
183:                 array('fileName', 'unique', 'on' => 'themeCreate'),
184:                 array('fileName', 'length', 'max' => 100),
185:             )
186:         );
187:     }
188: 
189:     /**
190:      * @return array relational rules.
191:      */
192:     public function relations() {
193:         // NOTE: you may need to adjust the relation name and the related
194:         // class name for the relations automatically generated below.
195:         return array(
196:             'campainAttachments' => array(self::HAS_MANY, 'CampaignAttachment', 'media'),
197:         );
198:     }
199: 
200:     /**
201:      * @return array customized attribute labels (name=>label)
202:      */
203:     /*  public function attributeLabels() {
204:       return array(
205:       'id' => 'ID',
206:       'associationType' => 'Association Type',
207:       'associationId' => 'Association',
208:       'fileName' => 'File Name',
209:       'uploadedBy' => 'Uploaded By',
210:       'createDate' => 'Create Date',
211:       );
212:       } */
213: 
214:     /**
215:      * Retrieves a list of models based on the current search/filter conditions.
216:      * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
217:      */
218:     public function search() {
219:         // Warning: Please modify the following code to remove attributes that
220:         // should not be searched.
221: 
222:         $criteria = new CDbCriteria;
223:         $username = Yii::app()->user->name;
224:         if (!Yii::app()->params->isAdmin)
225:             $criteria->addCondition("t.uploadedBy='$username' OR t.private=0 OR t.private=null");
226:         $criteria->addCondition("t.associationType != 'theme'");
227:         return $this->searchBase($criteria);
228:     }
229: 
230:     public function isImage() {
231:         return strpos($this->resolveType(), 'image/') === 0;
232:     }
233: 
234:     /**
235:      * Return true if $filename has an image extension. Image extensions include:
236:      * jpg, gif, png, bmp, jpeg, jpe
237:      *
238:      * @param $filename the file name that has the extension
239:      * @return true if $filename has an image extension, false otherwise
240:      */
241:     public static function isImageExt($filename) {
242:         return (bool) preg_match('/\.(jpg|gif|png|bmp|jpeg|jpe)$/i', $filename);
243:     }
244: 
245:     // return an img tag of this file
246:     // return '' if file is not an image
247:     public function getImage($link = false, array $htmlOptions=array ()) {
248:         if (!$this->fileExists() || !$this->isImage()) {
249:             return '';
250:         }
251: 
252:         if ($this->drive) {
253:             return $this->googlePreview;
254:         }
255: 
256:         $img = CHtml::image(
257:             $this->getPublicUrl(), '', X2Html::mergeHtmlOptions (array(
258:                 'class' => 'attachment-img',
259:             ), $htmlOptions)
260:         );
261: 
262:         if (!$link) {
263:             return $img;
264:         }
265: 
266:         return X2Html::link($img, $this->getPublicUrl());
267:     }
268: 
269:     public function getGooglePreview() {
270:         return X2Html::tag('iframe', array(
271:                     'src' => $this->url . '/preview',
272:                     'class' => 'google-drive'
273:                         ), '');
274:     }
275: 
276: 
277:     public function renderAttribute(
278:         $fieldName, $makeLinks = true, $textOnly = true, $encode = true) {
279: 
280:         switch ($fieldName) {
281:             case 'image': 
282:                 $imageLink = $this->getImage (true);
283:                 return 
284:                     '<div class="media-image">
285:                         <div class="full-size-screen">'.
286:                             X2Html::fa('expand').Yii::t('media', 'View Full Size').'
287:                         </div>
288:                         '. $imageLink .'
289:                     </div>';
290:                 break;
291:         }
292: 
293:         return call_user_func_array ('parent::'.__FUNCTION__, func_get_args ());    
294:     }
295: 
296:     /**
297:      * Magic path getter
298:      *
299:      * Obtains the full, absolute path to a file.
300:      * @return String|NULL Returns a path to the file or NULL if the file does not exist.
301:      */
302:     public function getPath() {
303:         if (!isset($this->_path)) {
304:             if ($this->associationType === 'logo') { // an exception for logos, fileName equals path name
305:                 $this->_path = $this->fileName;
306:             } else {
307:                 $pathFmt = array(
308:                     implode(DIRECTORY_SEPARATOR, array('{bp}', 'uploads', 'protected', 'media', '{uploadedBy}', '{fileName}')),
309:                     implode(DIRECTORY_SEPARATOR, array('{bp}', 'uploads', 'protected', '{fileName}')),
310:                 );
311:                 $basePath = realpath(Yii::app()->basePath . DIRECTORY_SEPARATOR . '..');
312:                 $params = array(
313:                     '{bp}' => $basePath,
314:                     '{uploadedBy}' => $this->uploadedBy,
315:                     '{fileName}' => $this->fileName
316:                 );
317:                 foreach ($pathFmt as $pfmt) {
318:                     $path = realpath(strtr($pfmt, $params));
319:                     if ((bool) $path) {
320:                         $this->_path = $path;
321:                         break;
322:                     } else {
323:                         // The file does not exist.
324:                         $this->_path = null;
325:                     }
326:                 }
327:             }
328:         }
329: 
330:         return $this->_path;
331:     }
332: 
333:     /**
334:      * Gets file size
335:      *
336:      * Obtains and returns the file size. If it hasn't been saved in the
337:      * database, this method does so.
338:      *
339:      * @return type
340:      */
341:     public function resolveSize() {
342: 
343:         if (empty($this->filesize)) {
344:             if (file_exists($this->path)) {
345:                 $this->filesize = filesize($this->path);
346:                 if (!$this->isNewRecord) {
347:                     $this->saveAttributes(array('filesize'));
348:                 }
349:             } else {
350:                 $this->filesize = null;
351:             }
352:         }
353:         return $this->filesize;
354:     }
355: 
356:     /**
357:      * Gets dimensions of the file, if it is an image.
358:      *
359:      * @return type
360:      */
361:     public function resolveDimensions() {
362:         if (!$this->drive && $this->isImage()) {
363:             if (empty($this->dimensions) && extension_loaded('gd') && !empty($this->path)) {
364:                 $sizeArr = getimagesize($this->path);
365:                 $this->dimensions = CJSON::encode(array(
366:                             'width' => $sizeArr[0],
367:                             'height' => $sizeArr[1],
368:                 ));
369:                 if (!$this->isNewRecord)
370:                     $this->saveAttributes(array('dimensions'));
371:             }
372:         }
373:         return $this->dimensions;
374:     }
375: 
376:     /**
377:      * Magic getter for human-readable file size.
378:      *
379:      * @return type
380:      */
381:     public function getFmtSize() {
382:         return FileUtil::formatSize($this->resolveSize());
383:     }
384: 
385:     public function getFmtDimensions() {
386:         if ($this->isImage()) {
387:             $dim = CJSON::decode($this->resolveDimensions());
388:             if (isset($dim['width'], $dim['height']))
389:                 return "{$dim['width']} x {$dim['height']}";
390:             else
391:                 return null;
392:         } else
393:             return null;
394:     }
395: 
396:     /**
397:      * Gets file type info
398:      *
399:      * Examines the file and gets MIME info; saves it in the record if it's not
400:      * there already.
401:      *
402:      * @return type
403:      */
404:     public function resolveType() {
405:         if (empty($this->mimetype)) {
406:             if (file_exists($this->path)) {
407:                 if ($finfo = FileUtil::finfo())
408:                     $this->mimetype = finfo_file($finfo, $this->path, FILEINFO_MIME);
409:                 else
410:                     $this->mimetype = null;
411:                 if (!$this->isNewRecord)
412:                     $this->saveAttributes(array('mimetype'));
413:             } else {
414:                 $this->mimetype = null;
415:             }
416:         }
417:         return $this->mimetype;
418:     }
419: 
420:     public static function getFilePath($uploadedBy, $fileName) {
421:         $possiblePaths = array(
422:             "uploads/protected/media/{$uploadedBy}/{$fileName}",
423:             "uploads/protected/{$fileName}",
424:         );
425:         foreach($possiblePaths as $path){
426:             if (file_exists(implode(DIRECTORY_SEPARATOR, array(Yii::app()->basePath, "..", $path)))) {
427:                 return $path;
428:             }
429:         }        
430: 
431:         return null;
432:     }
433: 
434:     /**
435:      * Magic uploaded file URL getter method
436:      * @return type
437:      */
438:     public function getUrl() {
439:         if (!isset($this->_url)) {
440:             $relPath = self::getFilePath($this->uploadedBy, $this->fileName);
441: 
442:             if ($this->drive) {
443:                 $this->_url = "https://drive.google.com/file/d/" . $this->fileName;
444:             } else if (file_exists(implode(DIRECTORY_SEPARATOR, array(Yii::app()->basePath, "..", $relPath)))) { // ensure file exists
445:                 $this->_url = Yii::app()->request->baseUrl . "/$relPath";
446:             } else {
447:                 $this->_url = null;
448:             }
449:         }
450:         return $this->_url;
451:     }
452: 
453:     public static function getFileUrl($path) {
454:         if ($path) // ensure file exists
455:             return Yii::app()->request->baseUrl . "/$path";
456:         return null;
457:     }
458: 
459:     // get the full url (including e.g. example.com) to a file
460:     // return null if file doesn't exist
461:     public function getFullUrl() {
462:         if ($path = self::getFilePath($this->uploadedBy, $this->fileName)) // ensure file exists
463:             return Yii::app()->getBaseUrl(true) . "/$path";
464: 
465:         return null;
466:     }
467: 
468:     public static function getFullFileUrl($path) {
469:         if ($path) // ensure file exists
470:             return Yii::app()->getBaseUrl(true) . "/$path";
471: 
472:         return null;
473:     }
474: 
475:     // return a link to the Media Module view for this file
476:     public function getMediaLink() {
477:         if ($this->drive) {
478:             $name = $this->name;
479:             // return CHtml::link($this->name, "https://drive.google.com/file/d/".$this->fileName, array('target' => '_blank'));
480:         } else {
481:             $name = $this->fileName;
482:         }
483:         return CHtml::link(
484:             $this->fileName, Yii::app()->controller->createUrl('/media/', array('view' => $this->id)));
485:     }
486:     
487:     //
488:     public function fileExists() {
489:         if (file_exists(implode(DIRECTORY_SEPARATOR, array(Yii::app()->basePath, "..", "uploads", "protected", "media", $this->uploadedBy, $this->fileName)))) // try new format
490:             return true;
491:         else if (file_exists(implode(DIRECTORY_SEPARATOR, array(Yii::app()->basePath, "..", "uploads", "protected", $this->fileName)))) // try old format
492:             return true;
493:         else if ($this->drive)
494:             return true;
495: 
496:         return false;
497:     }
498: 
499:     // convert a string (eg '10MB') to bytes
500:     private static function toBytes($size) {
501:         if (!ctype_alpha(substr($size, -1))) {
502:             // No suffix, size must already be in bytes
503:             return $size;
504:         }
505:         if (strtolower(substr($size, -1)) === 'b') {
506:             // Remove a trailing 'b'
507:             $size = substr($size, 0, -1);
508:         }
509:         $type = strtolower(substr($size, -1)); // last char
510:         $num = substr($size, 0, -1); // number
511:         switch ($type) {
512:             case 'p':
513:                 $num *= 1024;
514:             case 't':
515:                 $num *= 1024;
516:             case 'g':
517:                 $num *= 1024;
518:             case 'm':
519:                 $num *= 1024;
520:             case 'k':
521:                 $num *= 1024;
522:                 break;
523:         }
524: 
525:         return $num;
526:     }
527: 
528:     // return the max file size the server will except for upload files
529:     public static function getServerMaxUploadSize() {
530:         $max_post = Media::toBytes(ini_get('post_max_size'));
531:         $max_upload_file = Media::toBytes(ini_get('upload_max_filesize'));
532:         $max_upload_size = min($max_post, $max_upload_file);
533:         $max_upload_size /= (1024 * 1024); // convert bytes to megabytes
534:         $max_upload_size = round($max_upload_size, 2); // round to two decimal places
535: 
536:         return $max_upload_size;
537:     }
538: 
539:     public static function forbiddenFileTypes() {
540:         return "exe, bat, dmg, js, jar, swf, php, pl, cgi, htaccess, py, rb";
541:     }
542: 
543:     private static function getImageText($str, $makeLink, $makeImage, $media) {
544:         $fileExists = $media->fileExists();
545: 
546:         if ($fileExists == false)
547:             return $str . ' ' . Yii::t('media', '(deleted)');
548: 
549:         if ($makeLink && !Yii::app()->params->isMobileApp)
550:             $str .= $media->getMediaLink();
551:         else
552:             $str .= "";
553: 
554:         if ($makeImage && $media->isImage()) { // to render an image, first check file extension
555:             $str .= '<br>'.$media->getImage();
556:         }
557: 
558:         return $str;
559:     }
560: 
561:     /**
562:      * @param string $str
563:      * @param boolean $makeLink
564:      * @param boolean $makeImage
565:      * @return string
566:      */
567:     public static function attachmentSocialText($str, $makeLink = false, $makeImage = false) {
568:         // $a = '<a href="/x2merge/index.php/media/16">footer.png</a>';
569:         // echo ,preg_match('/^<a href=".+(media\/[0-9]+)" target="_blank">.+<\/a>$/i',$description
570:         $matches = array();
571:         // die(CHtml::encode($description));
572:         if (preg_match('/^<a href=".+media\/view\/([0-9]+)">.+<\/a>$/i', $str, $matches)) {
573:             if (count($matches) == 2 && is_numeric($matches[1])) {
574: 
575:                 $media = X2Model::model('Media')->findByPk($matches[1]);
576:                 if (isset($media)) {
577:                     $str = Yii::t('media', 'File:') . ' ';
578: 
579:                     return self::getImageText($str, $makeLink, $makeImage, $media);
580:                 }
581:             }
582:         } elseif (preg_match('/^<a target="_blank" href="https:\/\/drive.google.com\/file\/d\/(.+)">.+<\/a>$/i', $str, $matches)) {
583:             if (count($matches) == 2) {
584:                 $media = X2Model::model('Media')->findByAttributes(array('fileName' => $matches[1]));
585:                 if (isset($media)) {
586:                     $str = Yii::t('media', 'Google Drive:') . ' ';
587: 
588:                     return self::getImageText($str, $makeLink, $makeImage, $media);
589:                 }
590:             }
591:         }
592:         return x2base::convertUrls($str);
593:     }
594: 
595:     public function getDownloadLink($text = null, $htmlOptions = array()) {
596:         $text = !isset($text) ? '[' . CHtml::encode(Yii::t('media', 'Download')) . ']' : $text;
597:          
598:             $url = Yii::app()->createUrl ('/media/media/download', array ('id' => $this->id));
599:          
600:         return CHtml::link ($text, $url, $htmlOptions);
601:     }
602: 
603:     public function renderFile() {
604:         $filePath = $this->getPath();
605:         if ($filePath != null) {
606:             $file = Yii::app()->file->set($filePath);
607:         } else {
608:             throw new CHttpException(404);
609:         }
610:         if ($file->exists) {
611:             header('Content-type: ' . $file->mimeType);
612:             echo $file->getContents();
613:         }
614:     }
615: 
616:     public function getAccessKey() {
617:         if(empty($this->accessKey)){
618:             $this->accessKey = bin2hex(openssl_random_pseudo_bytes(32));
619:             Yii::app()->db->createCommand()->update(
620:                 'x2_media', 
621:                 array('accessKey' => $this->accessKey),
622:                 'id=:id',
623:                 array(':id' => $this->id));
624:         }
625:         return $this->accessKey;
626:     }
627: 
628:     public function getPublicUrl($key = true) {
629:         return Yii::app()->createExternalUrl('/media/media/getFile', array(
630:                 'id' => $this->id,
631:                 'key' => $key?$this->getAccessKey():'',
632:             ));
633:     }
634: 
635:     /**
636:      * Generates a description message with a link and optional preview image
637:      * for media items.
638:      *
639:      * @param string $actionDescription
640:      * @param boolean $makeLink
641:      * @param boolean $makeImage
642:      * @return string
643:      */
644:     public static function attachmentActionText($actionDescription, $makeLink = false, $makeImage = false) {
645: 
646:         $data = explode(':', $actionDescription);
647:         $media = null;
648:         if (count($data) == 2 && is_numeric($data[1])) // ensure data is formatted properly
649:             $media = X2Model::model('Media')->findByPK($data[1]); // look for an entry in the media table
650: 
651:         if ($media) { // did we find an entry in the media table?
652:             if ($media->drive) {
653:                 $str = Yii::t('media', 'Google Drive:') . ' ';
654:             } else {
655:                 $str = Yii::t('media', 'File:') . ' ';
656:             }
657: 
658:             $fileExists = $media->fileExists();
659: 
660:             if ($fileExists == false)
661:                 return $str . $data[0] . ' ' . Yii::t('media', '(deleted)');
662: 
663:             if ($makeLink) {
664:                 $str .= $media->getMediaLink();
665:                 if (!$media->drive) {
666:                     $str .= " | " . CHtml::link('[Download]', array('/media/media/download', 'id' => $media->id));
667:                 }
668:             } else
669:                 $str .= $data[0];
670: 
671:             if ($makeImage && $media->isImage()) // to render an image, first check file extension
672:                 $str .= $media->getImage();
673: 
674:             return $str;
675:         } else
676:             return $actionDescription;
677:     }
678: 
679: }
680: 
X2CRM Documentation API documentation generated by ApiGen 2.8.0