8

У меня есть страница, где должны выводиться:

  • заявки в друзья
  • уже подтверждённые друзья в таком виде: id - Username

Как реализовать такую систему на PHP:

  1. какой должна быть структура БД?
  2. как определить, что пользователь дружит или только отправил заявку?

3 ответа 3

6

Сделайте отдельную таблицу для заявок, к примеру reguests. Пускай она будет примерно так:

   | id | sender | taker | accept |

Первые три поля понятны, а вот accept пускай имеет значения 1 или 0 в зависимости подтверждения заявки. То есть 1, если подтвердил, 0 если еще нет.

Чтобы реализовать систему друзей, то сделайте таблицу frinends (к примеру) и пускай она имеет примерно такой вид:

   | id | id1 | id2 |

В поля id1 и id2 вписываете двух человек, которые подружились. Потом просто проверяете наличие пары нужных ид в таблице.

Вот. Коротко и думаю ясно) Недавно сам ломал голову над такой системой, так что буду рад помочь.

5
  • А одной таблицей обойтись нельзя? Допустим всё поместить во вторую, friends. И ещё такой вопрос, как я понял в поле id идёт пара двух id (id1 + id2)?
    – Anton
    6 окт 2012 в 17:55
  • @ka5itoshka , в поле id - идет ид самой строки (ну вдруг пригодится параметр. id людей в этом столбце не учавтсвуют). А если помещать всё в одну таблицу, то там придется использовать explode и больше циклов - а это грузит память. Так что две таблицы вполне достаточно ;) 6 окт 2012 в 19:21
  • @Эмиль Сабитов, я просто не могу понять как в вашей реализации вывести нужную мне информацию )) т.е. пользователь, друзей которого мы хотим вывести может быть в кое каких случаях id1 или же id2 (Допустим первый случай - я отправил заявку Вам, второй я получил заявку от Вас и в обеих случаях заявки подтверждены, да?. А тут есть пользователь который вообще не принял заявку (игнорирует) и нам такого не нужно выводить (т.е. выведем только тех с кем 100% подружились)))
    – Anton
    6 окт 2012 в 19:29
  • 1
    SELECT тут что нужно выбрать FROM reguests WHERE (id='нужныйчел' OR id2='нужныйчел) AND accept`=1 6 окт 2012 в 19:36
  • @Эмиль Сабитов, спасибо большое! Выручил:)
    – Anton
    6 окт 2012 в 19:39
5

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

Таблица users_status:

  • user_inviter (id юзера, который пригласил)
  • user_invited (id приглашенного юзера)
  • stat_val_id (текущий статус - ключ к полю stat_id в таблице ниже)

Таблица status_value

  • stat_id
  • stat_val (пригласил, отклонил, принял, игнорировал etc.)

UPD

Смотреть запрос в работе или так:

SELECT * FROM 
  `userlist` 
WHERE 
  `user_id` 
IN (
  SELECT 
    IF(`user_invited` = '3', `user_inviter`, `user_invited`)
  FROM 
    `users_status` 
  WHERE 
    `stat_val_id` = '2'
  )
  • user_invited = '3' - "3" - id пользователя, у которого ищем друзей
  • stat_val_id = '2' - "2" - статус, означающий "дружат"
9
  • В принципе всё понятно, вот только вот что: допустим мы хотим вывести друзей определенного человека. Что нужно в таком случаи указать в SELECT?
    – Anton
    6 окт 2012 в 17:58
  • Если статус "друг" имеет id = 100500, то получаем id-шники всех друзей: SELECT user_invited FROM users_status WHERE user_inviter = '$user_id' AND stat_val_id = '100500'
    – Deonis
    6 окт 2012 в 18:10
  • @Deonis, вы меня не правильно поняли. Есть страница человека с id=390. Как вывести на ней всех добавленных (взаимно) друзей. т.е. человек может быть user_inviter или user_invited и если это всё взаимно, записи должны выводиться. Вот это и есть суть проблемы.
    – Anton
    6 окт 2012 в 18:45
  • @Deonis , Ваш способ, на мой взгляд - чуть хуже, чем я описал в предыдущем ответе. @ka5itoshka и так просил одной таблицей сделать, у Вас уже 3. Может еще по-другому можно сделать? 6 окт 2012 в 19:17
  • 1
    Эмиль Сабитов, по поводу таблицы со значениями - это, как я сказал, "если нужно" и абсолютно не обязательно. Вам достаточно знать их значения, например, 1 -> пригласил, 2 -> принял, 3 -> отклонил. А по поводу второго замечания, то тут нужен просто правильно составленный запрос. Смотрите вариант по этой ссылке, но я в запросах не так силён, как, допустим, @Yura Ivanov, поэтому не против, чтоб он оптимизировал его.P.S. Проапдейтил так же и свой ответ.
    – Deonis
    6 окт 2012 в 19:37
3

Тут можно обойтись и одной таблицей со полями userId1, userId2, status. Рассмотрим пример вконтактика - там если отправляешь заявку добавления в друзья, то становишься подписчиком, а когда заявку подтверждают, то друзьями. Здесь поле статуса отвечает как раз за определение типа связи, а их смена должна быть определена в триггерах. На уровень приложения смену статуса выносить не стоит.

Пример. Пользователь делает заявку на добавление в друзья, при этом выполняется запрос:

insert into friends_rels (userId1, userId2) values ($id1, $id2);

А уже триггер должен определить является ли это заявкой, или же подтверждением. Определяет путем запроса к таблице:

select userId1, userId2 from friends_rels where userId1 = $id2 and userId2 = $id1;

Если находит, значит это подтверждение заявки: модифицирует строку NEW.status = 'friends' и выполняет update на заявку, где также присваивает статус того, что они - друзья. Если же запись селектом не была найдена, то значит это заявка на добавление в друзья и нужно лишь модифицировать статус: NEW.status = 'subscribe'.

Первичный ключ для строки не стоит делать - он попросту не нужен, а нужно только повешать уникальность на сочетание двух полей.

Таким образом вся логика сосредоточена в одном только триггере на уровне БД, т.е. на уровне хранения данных. Отсутствуют лишние Joinы для определения типа связи. Также не нужно обрабатывать кучу частных ситуаций типа той, когда одной пользователь сделал заявку второму, а второй пользователь сделал заявку на добавление в друзья первого - здесь все пройдет верно, а в других реализациях возможно отклонение от требуемого поведения.

2
  • По сути та же схема была в первом ответе, только с первичным ключом) А так хорошо расписано! 8 окт 2012 в 15:21
  • @Эмиль Сабитов, вот только Ваша схема мне показалась намного проще))
    – Anton
    9 окт 2012 в 12:24

Ваш ответ

By clicking “Отправить ответ”, you agree to our terms of service and acknowledge you have read our privacy policy.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками или задайте свой вопрос.