vorst.ru - Статьи о задачах возникающих при создании сайта и их решении

Делаем демо для загрузки фото

Загрузка жестко определенного количества файлов

Чтобы показать, как работает загрузка изображений, нужно разрешить загружать изображения на свой сайт. Но, в этом случае, дисковое пространство может быть быстро исчерпано и нужно как-то удалять оставленный посетителями "мусор".

Обычно загруженные файлы удаляются автоматически спустя время, но можно ограничить количество файлов - демо.


Редактирование и валидация модальной формы

Использование pop-up формы

Бывает, что количество полей в таблице не слишком велико и редактировать в модальном окне проще и нагляднее. Что необходимо, чтобы организовать стандартный набор операций - CReate, Update, Delete?


Как работает аутентификация OAuth2

OAuth2 аутентификация на примере Google

Если у вас есть аккаунт в Google, то вы наверняка пользовались документами. Например, электронными таблицами.

Доступ к таблицам разрешен только вам и тем, кому вы предоставите такое право. Причем доступ возможен не только из Google.

Можно просматривать список таблиц и редактировать выбранную таблицу оставаясь в рамках своего приложения. Примерно так - http://sample.vorst.ru/googl


Как устроена структура данных Nested Set

Как сделать рубрикатор

Рубрикатор, как средство поиска интересных статей, имеет свои недостатки - трудно придумать иерархию, названия рубрик, трудно потом решить к какой конкретно рубрике относится статья. "Но, так принято" - скажите вы и будете правы.


Цепочки статей в блоге

Можно ли сделать блог удобнее?

Для группировки статей существует возможность помечать статьи метками или прикреплять к наперед заданной рубрике. Кроме того, в конце статьи есть навигация - предыдущая, следующая статья, ну и меню конечно. Вроде все удобно.



Поиск



Делаем демо для загрузки фото

Загрузка жестко определенного количества файлов

Чтобы показать, как работает загрузка изображений, нужно разрешить загружать изображения на свой сайт. Но, в этом случае, дисковое пространство может быть быстро исчерпано и нужно как-то удалять оставленный посетителями "мусор".

Обычно загруженные файлы удаляются автоматически спустя время, но можно ограничить количество файлов - демо.


    Поделиться

Если ограничить количество загружаемых файлов небольшой цифрой, то очень скоро каждый следующий посетитель будет вынужден удалять файлы предшественников, прежде, чем сам сможет загрузить файлы.

Для загрузки будет использовано расширение yii2-uploader. Это расширение, которое хранит информацию обо всех загруженных в приложении файлах, в одной модели - OneFile.

Model

В модели, которой нужна загрузка файлов, не создается поле с типом file, а "подмешивается" поведение, которое сохраняет информацию о загруженных файлах.

Создадим модель app\models\Photo.php категорий фотографий. В каждую категорию можно грузить несколько, например 5 фотографий.

namespace app\models;
use yii\base\Model;
use sergmoro1\uploader\behaviors\HaveFileBehavior;
class Photo extends Model
{
    public $id;
    public $category;

Модель не связана с таблицей базы данных. Она будет существовать только в памяти. Этого достаточно, ведь информация о загруженных файлах будет хранится в "реальной" модели. Подмешаем эту модель.

    public function behaviors()
    {
        return [
            [
                'class' => HaveFileBehavior::className(),
                'file_path' => '/photo/',
                'sizes' => [
                    'original' => ['width' => 1200, 'height' => 900, 'catalog' => 'original'],
                    'main'     => ['width' => 800, 'height'  => 600, 'catalog' => ''],
                    'thumb'    => ['width' => 120, 'height'  => 90,  'catalog' => 'thumb'],
                ],
            ]
        ];
    }
    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'category' => \Yii::t('app', 'Category'),
        ];
    }
    /**
     * Search for a model by ID
     * This method is required for the extension to work.
     * 
     * @param integer $id
     * @return yii\base\Model
     */
    public function findOne($id)
    {
        return new Photo(['id' => $id]);
    }
}

Параметр $sizes задает подкаталоги и размеры в которых будет сохраняться загруженное изображение, file_path определяет основной каталог для хранения файлов модели.

Controller

Будем считать, что категории фотографий неизменны и их количество фиксировано. Пусть их всего будет 4. Проще всего задавать их в виде массива app\controllers\PhotoController.php.

namespace app\controllers;
use Yii;
use yii\web\Controller;
use yii\data\ArrayDataProvider;
use app\models\Photo;
class PhotoController extends Controller
{
    public $models = [
        ['id' => 1, 'category' => 'Street'],
        ['id' => 2, 'category' => 'Office'],
        ['id' => 3, 'category' => 'Factory'],
        ['id' => 4, 'category' => 'Nature'],
    ];
    public $_model;

Теперь легко вывести список категорий и определить действия для замены и просмотра фото.

    public function actionIndex()
    {
        $dataProvider = new ArrayDataProvider([
            'allModels' => $this->models,
        ]);
        return $this->render('index', [
            'dataProvider' => $dataProvider,
        ]);
    }
    public function actionView($id)
    {
        return $this->renderAjax('view', [
            'model' => $this->getModel($id),
        ]);
    }
    public function actionUpdate($id)
    {
        return $this->render('update', [
            'model' => $this->getModel($id),
        ]);
    }
    public function getModel($id)
    {
        if($this->_model === null)
        {
            $data = $this->models[$id - 1];
            $this->_model = new Photo($data);
        }
        return $this->_model;
    }
}

View

Вывод списка категорий app\views\photo\index.php требует достаточно много кода, но становится понятно, как все работает.

<?php
/**
* @var dataProvider array data provider
*/
use yii\helpers\Html;
use yii\helpers\Url;
use yii\bootstrap\Modal;
use yii\grid\GridView;
use app\models\Photo;
use sergmoro1\uploader\models\OneFile;
$this->title = "Photo uploader example"; 
$this->params['breadcrumbs'] = [$this->title];
echo Modal::widget([
    'id' => 'photo-win',
    'toggleButton' => false,
    'header' => Yii::t('app', 'View box'),
    'footer' => '<button type="button" class="btn btn-default" data-dismiss="modal">' . Yii::t('app', 'Cancel') . '</button>',
]);
?>
<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'layout' => "{items}\n{summary}\n{pager}",
    'columns' => [
        'id',
        [
            'header' => Yii::t('app', 'Image'),
            'format' => 'html',
            'options' => ['style' => 'width:120px'],
            'value' => function($data) {
                $model = new Photo($data);
                return $model->fileCount == 0 
                    ? '<span class="glyphicon glyphicon-picture"></span>'
                    : Html::img($model->getImage('thumb'));
            }
        ],
        [
            'header' => Yii::t('app', 'Description'),
            'value' => function($data) {
                $model = new Photo($data);
                $model->image;
                return $model->getFileDescription();
            }
        ],
        [
            'header' => Yii::t('app', 'Count'),
            'options' => ['style' => 'width:40px'],
            'value' => function($data) {
                $model = new Photo($data);
                return $model->fileCount;
            }
        ],
        'category',
        [
            'class' => 'yii\grid\ActionColumn',
            'template' => '{view} {update}',
            'buttons' => [
                'view' => function ($url, $data) {
                    $model = new Photo($data);
                    return $model->fileCount == 0 ? '' : Html::a(
                        '<span class="glyphicon glyphicon-eye-open"></span>', 
                        ['view', 'id' => $data['id']], [
                            'data-toggle' => 'modal',
                            'data-target' => '#photo-win',
                            'onclick' => "$('#photo-win .modal-dialog .modal-content .modal-body').load($(this).attr('href'))",
                        ]
                    );
                },
                'update' => function ($url, $data) {
                    return Html::a('<span class="glyphicon glyphicon-pencil"></span>', ['update', 'id' => $data['id']]);
                },
            ],
        ],
    ],
]); ?>

Файл app\views\photo\view.php значительно короче.

<?php
/* @var $this yii\web\View */
/* @var $model app\models\Photo */
use yii\bootstrap\Carousel;
?>
<?= Carousel::widget([
    'items' => $model->prepareSlider('div', [], ['class' => 'img-responsive'], true), 
    'options' => ['data-interval' => ''],
    'controls' => [
        '<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>',
        '<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>',
    ]
]) ?>

И совсем небольшой файл app\views\photo\appendix.php для ввода и редактирования описания к фото.

<?php
/**
 * @var $file - oneFile model record
 */
?>
<span id='description'>
    <?php echo isset($file->vars->description) ? $file->vars->description : ''; ?>
</span>

Осталось организовать загрузку изображений.

Как будут загружаться изображения?

В представлении app/views/photo/update.php вызовем виджет Uploader.

<?php
use sergmoro1\uploader\widgets\Uploader;
?>
<?= Uploader::widget([
    'model' => $model,
    'secure' => false,
    'limit' => 5,
    'appendixView' => '/photo/appendix',
    'cropAllowed' => true,
    'draggable' => true,
]) ?>

В контроллере app/controller/PhotoController.php уже добавлено соответствующее действие update.

Configuration

Наконец нужно подключить модуль (например в app/config/web.php) и определить каталог для загружаемых файлов. В каталоге (в примере ниже files) создать подкаталог photo и дать право на запись.

<?php
return [
    'aliases' => [
        '@absolute' => '/root/dir/yoursite',
        '@uploader' => '/web/files',
    ],
    'modules' => [
        'uploader' => ['class' => 'sergmoro1\uploader\Module'],
    ],

Заключение

При подключении расширения yii2-uploader нет необходимости определять поле file в модели, обрабатывать submit и даже определять form. Полная документация, демо.

Comments

  • Напишите, пожалуйста, статью, как массово загружать изображения через ajax с возможностью сортировки перетаскиванием, прикрепляя их к другой модели. Нигде ничего путного не найти. Например я хочу сделать изображения для объявления перетаскиванием в объявление(dropzone) (то есть уже должен быть ID у модели объявления, к которому привязать все изображения.) Кроме того пользователь должен иметь возможность тут же сортировать изображения, перетаскивая мышкой. Спасибо Василий
  • -- Попробую. Спасибо! SergeyMorozov
  • And I thought I was the sensible one. Thanks for setting me startghi. Jenibelle
  • -- Thanks ) SergeyMorozov

Оставьте комментарий

Только зарегистрированные пользователи могут оставлять комментарии. Пожалуйста войдите или пройдите регистрацию.