Есть ли в PHP ORM позволяющая забирать из базы данные со сложной структурой?

Поясню что я имею в виду.
Допустим есть таблица с объявлениями. У каждого объявления есть связанные с ним данные:
1) Теги
1.1) Категория тега
2) Номера телефонов
3) Изображения
4) Автор

Структура примерно такая
5a865985762ed002990257.png
SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for advert
-- ----------------------------
DROP TABLE IF EXISTS `advert`;
CREATE TABLE `advert` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `author_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `author_id` (`author_id`),
  CONSTRAINT `advert_ibfk_1` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for author
-- ----------------------------
DROP TABLE IF EXISTS `author`;
CREATE TABLE `author` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `login` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for category
-- ----------------------------
DROP TABLE IF EXISTS `category`;
CREATE TABLE `category` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for image
-- ----------------------------
DROP TABLE IF EXISTS `image`;
CREATE TABLE `image` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `advert_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `advert_id` (`advert_id`),
  CONSTRAINT `image_ibfk_1` FOREIGN KEY (`advert_id`) REFERENCES `advert` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for link_advert_phone
-- ----------------------------
DROP TABLE IF EXISTS `link_advert_phone`;
CREATE TABLE `link_advert_phone` (
  `phone_id` int(10) unsigned NOT NULL,
  `advert_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`advert_id`,`phone_id`),
  KEY `phone_id` (`phone_id`),
  CONSTRAINT `link_advert_phone_ibfk_1` FOREIGN KEY (`phone_id`) REFERENCES `phone` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `link_advert_phone_ibfk_2` FOREIGN KEY (`advert_id`) REFERENCES `advert` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for link_advert_tag
-- ----------------------------
DROP TABLE IF EXISTS `link_advert_tag`;
CREATE TABLE `link_advert_tag` (
  `tag_id` int(10) unsigned NOT NULL,
  `advert_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`tag_id`,`advert_id`),
  KEY `advert_id` (`advert_id`),
  CONSTRAINT `link_advert_tag_ibfk_1` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `link_advert_tag_ibfk_2` FOREIGN KEY (`advert_id`) REFERENCES `advert` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for phone
-- ----------------------------
DROP TABLE IF EXISTS `phone`;
CREATE TABLE `phone` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `value` varchar(16) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for tag
-- ----------------------------
DROP TABLE IF EXISTS `tag`;
CREATE TABLE `tag` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `category_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `category_id` (`category_id`),
  CONSTRAINT `tag_ibfk_1` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS=1;



Необходимо вытащить все связанные с объявлениями данные.
База весит примерно 4Гб. Сейчас всё это дело вытягивает самопис который строит запрос основываясь на структуре базы. Происходит это примерно так:
$result = $db->getTable('advert')
	->select()
	->limit(180)
	->offset(0)
	->cache(5)
	->link('author')
	->link('image')
	->link('link_advert_phone.phone')
	->link('link_advert_tag.tag.category')
	->query()
;


В результате получаем такой массив:
$result = [
	[
		'id' => 1,
		'title' => '....',
		'author_id' => 1,
		'author_id.author.id' => [
			'id' => 1,
			'login' => 'user name',
		],
		'id.image.advert_id' => [
			[
				'id' => 1,
				'advert_id' => 1,
			],
			[
				'id' => 2,
				'advert_id' => 1,
			],
			// ....
		],
		'id.link_advert_phone.advert_id' => [
			[
				'advert_id' => 1,
				'phone_id' => 1,
				'phone_id.phone.id' => [
					'id' => 1,
					'value' => '+996......',
				]
			],
			// ....
		],
		'id.link_advert_tag.advert_id' => [
			[
				'advert_id' => 1,
				'tag_id' => 1,
				'tag_id.tag.id' => [
					'id' => 1,
					'name' => 'Тег',
					'category_id' => 1,
					'category_id.category.id' => [
						'id' => 1,
						'name' => 'Категоряия',
					]
				]
			],
			// ....
		],
	],
	// ...
];


Самопис при необходимости строит временные таблицы с ключами и составляет сложные запросы вытягивающие вот такие структуры произвольной вложенности. Плюс можно писать условия к вложенным таблицам которые будут влиять на результат. Писать такие запросы в ручную можно но очень проблематично и сложно. Сейчас в планах переписать весь сайт и хотелось бы этот самопис заменить сторонним решением. Пробовал doctrine, он увеличивает время с 200 мс примерно до 3-х секунд, плюс сложность написания запросов возрастает на порядок.
  • Вопрос задан
  • 623 просмотра
Пригласить эксперта
Ответы на вопрос 3
OnYourLips
@OnYourLips
Это не сложная структура. Более того, с ORM она станет проще: не будет отдельных сущностей для ваших link_ таблиц.

Два самых популярных варианта - Eloquent (на базе антипаттерна Active Record) и Doctrine (Data Mapper).

Пробовал doctrine, он увеличивает время с 200 мс примерно до 3-х секунд,
Время запроса? Если это так, то вы где-то ошиблись: запросы там самые обычные генерируюся.
Скорее всего вы не заставили джойнить связанные данные, которые хотите получить.

плюс сложность написания запросов возрастает на порядок.
Сложность вхождения возрастает, новичкам сложней. Сложность повседневной работы падает. А сложность поддержки (работа с длительными проектами) падает на несколько порядков.
Ответ написан
@dmitriylanets
propel2
Ответ написан
Isolution666
@Isolution666
творческая личность
Попробуйте фреймворк Yii2 - там есть ORM. Готовые модели, работающие через функции, всё просто, прописываете в контроллере, что хотите видеть во вьюшке через экшен, и готово! Выводит информацию любой сложности. Я до сих пор не жалею, что выбрал этот фреймворк. Он гибкий, способен реализовывать много разных задач. Под Yii2 написано много разных решений с обработкой данных. Сэкономите время на разработку. Отпадут подобные вопросы. Есть много уроков на youtube, если знаете php, MySQL, sql, то без труда всё настроите, установите и упакуете. В коробке есть базовые решения, можно бесплатно добавлять разработки сторонних разработчиков. И не только.

А ещё количество таблиц можно сократить php.net/manual/ru/function.implode.php
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через TM ID
Похожие вопросы
Мокрый нос Новосибирск
от 60 000 до 150 000 руб.
Инлайн Санкт-Петербург
от 60 000 до 80 000 руб.
A3F Group Москва
До 160 000 руб.
14 авг. 2018, в 22:43
350 руб./за проект
14 авг. 2018, в 19:03
10000 руб./за проект
14 авг. 2018, в 18:10
1000 руб./в час