Yii 1.1: yush

YUSH (Yii Upload Structure Helper) helps manage paths and URLs for uploaded resources
12 followers

Yush Logo

YUSH (Yii Upload Structure Helper) helps you to maintain resource paths and URLs. It is commonly used by controllers to generate automatic resource paths and by views to retrieve the resource. Please note, YUSH does not perform any uploading functionality. It is used by your application to manage the paths and urls of uploaded resources.

Please also note, although I've used this component in several live applications, there may be some bugs.

Bugs

Please report them here

Requirements

Yii 1.1 or above

Usage

Extract YUSH to your your extension directory and import the YUSH folder

'import' => array(
        ...
        'application.extensions.components.yush.*',
        ...
    ),

Initialize the Yush component

'components' => array(
    'yush' => array(
        'class' => 'application.library.components.yush.YushComponent'
    ),
    ...

Uploading Resources

YUSH is typically used by controllers when uploading resources.

public function actionCreate()
{
    ...
 
    $model = new Service;
 
    if (isset($_POST['Service']))
    {
        $model->attributes = $_POST['Service'];
        $image = CUploadedFile::getInstance($model, 'preview_image');
 
        if ($image)
        {
            // Clean up the filename
            $uglyName = strtolower($model->name);
            $mediocreName = preg_replace('/[^a-zA-Z0-9]+/', '_', $uglyName);
            $beautifulName = trim($mediocreName, '_') . "." . $image->extensionName;
 
            $model->image_name = $beautifulName;
        }
 
        // Note: the model must be saved first as YUSH will use it's ID by default.
        if ($model->save())
        {
            if ($image)
            {
                Yush::init($model); // this will build the nessesary structure
 
                // Nothing has been uploaded yet but YUSH will return a full path that can be used to save the resource
                $originalPath = Yush::getPath($model, Yush::SIZE_ORIGINAL, $model->image_name);
                $largePath = Yush::getPath($model, Yush::SIZE_LARGE, $model->image_name);
                $smallPath = Yush::getPath($model, Yush::SIZE_SMALL, $model->image_name);
                $thumbPath = Yush::getPath($model, Yush::SIZE_THUMB, $model->image_name);
 
                // Save the original resource to disk
                $image->saveAs($originalPath);
 
                // Create a large image
                $largeImage = Yii::app()->phpThumb->create($originalPath);
                $largeImage->resize(700, 400)->pad(800, 600, '#FFFFFF');
                $largeImage->save($largePath);
 
                // Create a small image
                $smallImage = Yii::app()->phpThumb->create($originalPath);
                $smallImage->resize(385, 220)->pad(400, 300, '#FFFFFF');
                $smallImage->save($smallPath);
 
                // Create a thumbnail
                $thumbImage = Yii::app()->phpThumb->create($originalPath);
                $thumbImage->resize(350, 200)->pad(350, 200, '#FFFFFF');
                $thumbImage->save($thumbPath);
            }
 
            $this->redirect(array('view', 'id' => $model->id));
        }
    }
 
    $this->render('create', array(
        'model' => $model,
    ));
}

Consuming Resources

Then, in your views, you can use YUSH to retrieve the URL of the uploaded resource.

// You specify the format you'd like returned by passing a string to the 2nd parameter (Yush::SIZE_THUMB).
echo CHtml::image(Yush::getUrl($model, Yush::SIZE_THUMB, $model->image_name), $model->name);

YUSH is also useful for deleting resources and directories. In the following example, we can use Yush::getDirectoriesAtLevel to return an array of directory paths at a certain level. Why an array? Because you can extend YUSH to use your own templates. For example, you might want the following directory structure:

  • uploads/service/1/2013-04-30/thumb/image.jpg
  • uploads/service/1/2013-04-30/small/image.jpg
  • uploads/service/1/2013-04-30/large/image.jpg
  • uploads/service/1/2013-04-30/original/image.jpg
  • uploads/service/1/2013-05-01/thumb/image.jpg
  • uploads/service/1/2013-05-01/small/image.jpg
  • uploads/service/1/2013-05-01/large/image.jpg
  • uploads/service/1/2013-05-01/original/image.jpg

Yush::getDirectoriesAtLevel($model, 3) will return:

array(
[0] => 'full/path/to/uploads/service/1/2013-04-30',
[1] => 'full/path/to/uploads/service/1/2013-05-01'
)
 
public function beforeDelete()
{
 
    foreach (Yush::getDirectoriesAtLevel($this, 3) as $key => $path)
    {
        FileHelper::deleteDirectory($path);
    }
 
    return parent::beforeDelete();
}

Or, you can use it to delete all resources for a model type.

  • uploads/service/1/thumb/image.jpg
  • uploads/service/1/small/image.jpg
  • uploads/service/1/large/image.jpg
  • uploads/service/1/original/image.jpg
  • uploads/service/2/thumb/image.jpg
  • uploads/service/2/small/image.jpg
  • uploads/service/2/large/image.jpg
  • uploads/service/1/original/image.jpg
/*
* returns array(
*    [0] => 'full/path/to/uploads/service/1',
*    [1] => 'full/path/to/uploads/service/2',
*)
*/
foreach (Yush::getDirectoriesAtLevel($this, 2) as $key => $path)
{
    FileHelper::deleteDirectory($path);
}

Using Templates

You may specify templates in your application's main config. These templates are used to specify what directories will be created for a particular model.

My typical config file might look something like this. Note: this is the recommended way to use YUSH. If you do not specify templates for a model, YUSH will automatically create the folder structure as defined in YushComponent::template.

'components' => array(
    'yush' => array(
        'class' => 'application.library.components.yush.YushComponent',
        'baseDirectory' => 'uploads',
        'lowercase' => true,
        'template' => array(
            'Service' => array(
                'small' => '{model}{modelId}',
                'thumb' => '{model}{modelId}',
                'original' => '{model}{modelId}'
            ),
            'PortfolioImage' => array(
                'small' => '{model}{modelId}',
                'cropped' => '{model}{modelId}',
                'thumb' => '{model}{modelId}',
                'large' => '{model}{modelId}',
                'original' => '{model}{modelId}'
            ),
        ),
    ),

Extending Yush

Yush, by default, uses a model's name and ID as the base directory structure. You may wish to customize this by using a different property of your model. You can do this by adding a new 'transform' method to the bottom of YushComponent.php. Study the example below as this method will be called dynamically. The method name must start with the word "transform" and should be written in camelCaseIfYouKnowWhatIMean.

Please be careful not to use volatile properties such as updated_on, updated_by or anything else that might change over time as this would break the directory structure.

I rarely use this feature as I find {model}{modelId} is adequate. Please let me know if you run into any issues using this feature.

...
/**
* Matches the template {createdDate}
*/
public function transformCreatedDate()
{
    $createdDate = date("Y-m-d", strtotime($this->model->created_on));
    array_push($this->destination, $createdDate);
}

Total 2 comments

#13062 report it
waterloomatt at 2013/04/30 11:08pm
re: using templates

@selorm, try this

// Add these 2 methods to YushComponent.php (at bottom)
/**
* Matches the template {year}
*/
public function transformYear()
{
    $createdYear = date("Y", strtotime($this->model->created_on)); // adjust this to your model's property
    array_push($this->destination, $createdYear);
}
 
/**
* Matches the template {month}
*/
public function transformMonth()
{
    $createdMonth = date("F", strtotime($this->model->created_on)); // adjust this to your model's property
    array_push($this->destination, $createdMonth);
}
'components' => array(
    'yush' => array(
        'class' => 'application.library.components.yush.YushComponent',
        'baseDirectory' => 'uploads',
        'lowercase' => true,
        'template' => array(
            'ModelName' => array(
                'small' => '{year}{month}{model}{modelId}',
                'thumb' => '{year}{month}{model}{modelId}',
                'original' => '{year}{month}{model}{modelId}',
            )
        ),
    ),
#13054 report it
selorm at 2013/04/30 03:28pm
using templates

with regards to using the templates, i would like to automatically create folders by year/month just to organise it well like it is in worspress.How do i implement that into the template section since what you have there looks like its supposed to be hard coded.Thanks

Leave a comment

Please to leave your comment.

Create extension
Downloads