таблица relation

WMix

герр M:)ller
Партнер клуба
начну сразу с примера:
допустим есть таблица картинок images: id, path
есть также другие таблицы к примеру, клиенты, продукты, документы,... где хочется иметь ссылку на картинки.

продукт 42, (1:N) картинки 1,3,6,12.

можно создать кучу промежуточных таблиц клиенты_картинки, продукты_картинки,.. но так и подмывает добавить в таблицу картинки 2 поля, имя_таблицы и ref_id.

те для примера с продуктами
id, таблица, ref_id, path
1, продукт, 42, path
3, продукт, 42, path
6, продукт, 42, path
12, продукт, 42, path

есть ли такой (anti)pattern, и как это называется?
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
Не знаю как на счет антипаттерна, но FK ты уже не воткнешь, как я понимаю.
 

AnrDaemon

Продвинутый новичок
Зачем так сложно?
Ты же не вытягиваешь из базы отдельно одну картинку от товара.
И не ищешь картинки в товарах по ID.
Привесь JSON со списком картинок на товар и спи спокойно.
 

WMix

герр M:)ller
Партнер клуба
Ты же не вытягиваешь из базы отдельно одну картинку от товара.
конечно да..

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

where table="product" and ref_id in (1,2,3,4,5,...) ,большая проблема что constraints не опишешь

Polymorphic association - спасибо ))
 

MiksIr

miksir@home:~$
В постгресе через наследование таблиц с партицированием мона сделать. Ну, правда, все-равно создаются наследники на каждую связь, но триггером это можно сделать прозрачно.
 

Активист

Активист
Команда форума
PHP:
<?php 
trait app_object_images
{
    /**
    * Содержит изобржения для объекта
    * @var app_images_image[]
    */
    protected $_images;
   
    /**
    * Метод возвращает директорию, куда необходимо сохранить файлы
    * @return string
    */
    public function getImagesUploadDirectory()
    {
       if (!$this->getId())
       {
           throw new app_exception("Вызов getImagesUploadDirectory() для не сохраненного объекта", 503);
       }
   
       $directory =  "upload/" . get_class( $this ) . "/" . (($this->getId() % 255 + 1))."/";
   
       if (file_exists($directory) && !is_dir($directory))
       {
           throw new app_exception("{$directory} не является директорией", 503);
       }
   
       if (!file_exists($directory) && !app_fs_mkdir::recursive($directory))
       {
           throw new app_exception("Не могу создать директорию {$directory} не является директорией", 503);
       }
   
       return $directory;
    }

    /**
    * Ratio
    * @return string
    */
    public function getImagesRatio()
    {
       return "200:200";
    }
   
    /**
    * Установка всех изображений
    * @param array $images
    * @return app_object_images
    */
    public function setImages(array $images)
    {
       $this->_images = $images;
       return $this;
    }
   
    /**
    * Получаем изображения из базы данных
    * @return app_images_images|multitype:app_images_array
    */
    public function getImages()
    {
       if (isset($this->_images)) {
   
           return new app_images_array($this->_images);
       }
   
       if (!$this->getId()) {
   
           return new app_images_array(array());
       }
   
       $this->_images = array();
   
       $db = (new app_db())->query("SELECT * FROM `app_images_image` WHERE `class` = '".get_class($this)."' && `object_id` = '".$this->getId()."' ORDER by `position`");
   
       while ($row = $db->fetch()) {
   
           $this->_images[] = (new app_images_image())->setAttributes($row);
       }
   
       return new app_images_array($this->_images);
    }
   
    /**
    * Универсальный метод, который необходимо вызывать при загрузки изображений на сервер с выбором area по x1,y1 и x2,y2.
    * @param unknown $_images
    * @return app_object_images
    */
    public function userInputImages($_images)
    {
       $this->getImages(); // Загрузим изображения из БД
       
        if (is_array($_images) && isset($_images['id'])) {
         
           $increment = 0;
           
            foreach (array_keys($_images['id']) as $_key) {
               
                if (!isset($_images['id'][$_key]) || !isset($_images['name'][$_key]) || !isset($_images['filename'][$_key]) || !isset($_images['primary'][$_key]) || !isset($_images['title'][$_key]) || !isset($_images['width']) || !isset($_images['height']) || !isset($_images['x1'][$_key]) || !isset($_images['y1'][$_key]) || !isset($_images['x2'][$_key]) || !isset($_images['y2'][$_key]) || !isset($_images['xThumb'][$_key]) || !$_images['name'][$_key]) {
                   
                    continue;
                }
               
                if (!$_images['id'][$_key]) {
                   
                   /*
                    * Загрузка нового изображения
                    */
                   
                   
                    if (!file_exists($_images['filename'][$_key]) || !is_readable($_images['filename'][$_key])) {
                       // Проверка изображения. Возможно, оно могло исчезнуть при чистке по крону
                       $this->addError("Файл {$_images['filename'][$_key]} не существует или не доступен для чтения");
                       continue;
                    }
                   
                    /*
                    * Повторная проверка на попытку загрузить нетипичное изображение. В нормальных условиях 
                    * никогда не должна сработать, поскольку первоначальный ресайз выполняется контроллером загрузки изобращений,
                    * и проверка качества изображения выполняется там
                    */
                    $image_info = getimagesize($_images['filename'][$_key]);
                   
                    if (!$image_info || !$image_info[0] || !$image_info[1]) {
                   
                       $this->addError("Изображение не допустимого формата (#1)");
                       continue;
                    }
                   
                    $this->_images[] = (new app_images_image())
                    ->setClass(get_class($this))
                    ->setObjectId($this->getId())
                    ->setName($_images['name'][$_key])
                    ->setFilename($_images['filename'][$_key])
                    ->setWidth($image_info[0])
                    ->setHeight($image_info[1])
                    ->setRatio( $this->getImagesRatio() )
                    ->setPrimary($_images['primary'][$_key])
                    ->setTitle($_images['title'][$_key])
                    ->setX1($_images['x1'][$_key])
                    ->setY1($_images['y1'][$_key])
                    ->setX2($_images['x2'][$_key])
                    ->setY2($_images['y2'][$_key])
                    ->setXThumb($_images['xThumb'][$_key])
                    ->setPosition($increment++)
                    ;                   
                   
                } else {
                   
                   /** Обновление данных существующего изображения*/
                    foreach ($this->getImages() as $image) {
                       
                       if ($image->getId() &&  $image->getId() == $_images['id'][$_key]) {
                           
                            $image
                            ->setTitle($_images['title'][$_key])
                            ->setPrimary($_images['primary'][$_key])
                            ->setX1($_images['x1'][$_key])
                            ->setY1($_images['y1'][$_key])
                            ->setX2($_images['x2'][$_key])
                            ->setY2($_images['y2'][$_key])
                            ->setPosition($increment++)
                            ;
                       }
                    }
                }
            }
        }
   
        return $this;
    }
   
    /**
    * Метод сохранения изображений. Основное назначение, обработать массив изображений, 
    * и перенести загруженные изображения из временных директорий в стационарные
    * @throws app_exception
    * @return app_object_images
    */
    public function storeAndSaveImages()
    {
        if (!isset($this->_images) || !is_array($this->_images)) {
           
            return $this;
        }
       
        if (!$this->getImagesUploadDirectory()) {
           
            throw app_exception("Метод сохранения изображений не может получить директорию для записи", 503);
        }
       
        foreach ($this->_images as $image) {
           
            if (!$image->getId()) {
               
                if (!$this->getId()) {
                   
                    throw new app_exception("Ой.. Не смог скопировать изображения. Не определен id объекта", 503);
                }
               
                if (!$image->getFilename()) {
                   
                    throw new app_exception("Ой.. Не смог скопировать изображения. Не определен getTempFailename()", 503);
                }
               
                $src = $image->getFilename();
               
                $dst = $this->getImagesUploadDirectory().(substr($this->getImagesUploadDirectory(), -1, 1) != DIRECTORY_SEPARATOR ? "/" : null) . basename($image->getFilename());
               
                if (!file_exists($src) || !is_file($src) || !is_readable($src)) {
                   
                    throw new app_exception("Ой.. Файл {$src} не существует или не доступн для чтения", 503);
                   
                }
               
                if (!file_exists(dirname($dst)) || !is_dir(dirname($dst)) || !is_writable(dirname($dst))) {
                   
                    throw new app_exception("Ой.. Директория ".dirname($dst)." не существует или не доступна для записи", 503);
                } 
               
                if (!copy($src, $dst)) {
                   
                    throw new app_exception("Ой.. Не смог скопировать {$src} в {$dst} не существует или не доступна для записи", 503);
                }
               
                $image
                ->setObjectId( $this->getId() )
                ->setFilename( basename( $dst ))
                ->setDirectory( dirname($dst) )
                ->save()
                ;
               
            } else  {
               
                $image->save();
            }
        }
    }   
}
Код:
CREATE TABLE `app_images_image` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `class` varchar(50) NOT NULL,
  `object_id` int(10) unsigned DEFAULT NULL,
  `primary` smallint(6) DEFAULT NULL,
  `title` tinytext,
  `name` tinytext,
  `directory` tinytext NOT NULL,
  `filename` tinytext NOT NULL,
  `width` int(10) unsigned DEFAULT NULL,
  `height` int(10) unsigned DEFAULT NULL,
  `ratio` tinytext,
  `x1` int(10) unsigned DEFAULT NULL,
  `y1` int(10) unsigned DEFAULT NULL,
  `x2` int(10) unsigned DEFAULT NULL,
  `y2` int(10) unsigned DEFAULT NULL,
  `position` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `class` (`class`,`object_id`,`position`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 

WMix

герр M:)ller
Партнер клуба
Активист, ну да както так, гдето и подобное твоему имеется, просто велосипед писать не хотел, чувствовал что это уже 100 раз написано. вот и спрашивал про имя
 

WMix

герр M:)ller
Партнер клуба
Активист, кстати после "Ой.." , слова "сцуко" не хватает, ошибка сразу воспринимается иначе, нет связи с народом чтоль..
 

Активист

Активист
Команда форума
Активист, кстати после "Ой.." , слова "сцуко" не хватает, ошибка сразу воспринимается иначе, нет связи с народом чтоль..
Да в нормальных условиях эти ошибки не возникают, если только с хостом у клиента нет проблем ;))
 
Сверху