Уважаемые пользователи Голос!
Сайт доступен в режиме «чтение» до сентября 2020 года. Операции с токенами Golos, Cyber можно проводить, используя альтернативные клиенты или через эксплорер Cyberway. Подробности здесь: https://golos.io/@goloscore/operacii-s-tokenami-golos-cyber-1594822432061
С уважением, команда “Голос”
GOLOS
RU
EN
UA
rusldv
7 лет назад

PHP Урок 22. Данные пользователя.

PHP Урок 22. Профиль пользователя.



Предыдущие уроки:


Программируем на PHP - Введение

PHP - Запросы от браузера к серверу

PHP - Как работает сервер

PHP - Урок 4. PHP - интерпретатор

PHP - Урок 5. Переменные сервера и глобальные переменные

PHP - Урок 6. Конструкции print и echo. Кавычки одинарные и двойные и конкатенация строк

PHP - Урок 7. Переменные, константы и условия

PHP - Урок 8. Точка входа в приложение. Настройка mod_rewrite и файл .htaccess

PHP - Урок 9. Массивы и switch. Кодим основной каркас

PHP - Урок 10. COOKIE

PHP - Урок 11. Функции. Добавляем ядро системы core.php

PHP - Урок 12. Обзор модели MVC. Добавляем шаблоны страниц в наше приложение

PHP - Урок 13. Введение в базы данных и SQL. СУБД MySQL. Подключаемся к БД из нашего приложения

PHP - Урок 14. Регистрация пользователей на сайте

PHP Урок 15. Авторизация пользователей

PHP. Урок 16. Проверка авторизации. Функция check().

PHP Урок 17. Добавляем CSS фреймворк Bootstrap и jQuery

PHP Урок 18. Загрузка файлов на сервер

PHP Урок 19. Добавляем меню навигации

PHP Урок 21. Циклы for, while, foreach


Теория

До этого момента в нашей базе данных имеется только таблица users. Она хранит основные данные, которые необходимы для авторизации пользователей (такие как пароль, емейл и.т.п). Легко заметить, что в ней нет таких столбцов, как например имя и фамилия пользователя. В нашем приложении данные такого типа хранятся в таблице profiles.
CREATE TABLE IF NOT EXISTS 'profiles' (
  'user_id' bigint(20) unsigned NOT NULL,
  'first_name' varchar(120) NOT NULL,
  'last_name' varchar(120) NOT NULL,
  'about' varchar(255) DEFAULT NULL,
  PRIMARY KEY ('user_id'),
  KEY 'first_name' ('first_name','last_name')
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

У архитекторов баз данных есть такое слово - нормализация. Это когда одну таблицу разбивают на две или больше. И еще есть всякие правильные (и неправильные) формы, в которых должна находится база.
Выяснение в какой форме должна быть БД происходит абсолютно без философии.
Просто перебирают все варианты и смотрят в каком состоянии быстрее работает БД (т.е время выборки, отклика и.т.п).
Где данных много стараются делать табличек по-больше, но по-короче (правильная форма больше третьей). Но опять же зависит от различных факторов. В частность движка СУБД или всего ее ПО вместе.

В нашем случае разделение данных пользователя обусловлено простой логикой: к этим двум таблицам приходит больше всего запросов на выборку. Причем по данным разных критериев.
Вот по этим критериям я и разделил на 2 таблицы данные пользователя. К тому же здесь можно подвязать такую логику - в users данные технического характера, а в profiles относящиеся к личности пользователя.

Есть и еще один критерий, о котором я уже говорил, и которому я следую при разработке своих приложений.
В компонентах любой системы всегда важна взаимосвязь.
Например: У меня есть таблица в базе данных, ее название соответствует названию шаблона, в котором отображаются данные из этой таблицы (вместо шаблона может быть компонент или чанк - кусок HTML-страницы, но у нас шаблон страницы целиком), а также у нас есть АПИ, для обращения к нему из JavaScript я также добавляю в папку /js проекта файл также соответствующий имя страницы.js.
То есть когда у таблицы БД, шаблона страницы и скрипта JS одинаковые имена - гораздо проще работать, так как видно связь (логику).

Так вот. Можно считать, что users - это общая (главная) таблица, а profiles - относится к шаблону профиля (или как говорят некоторые психолого - профайла) пользователя.

Практика


Структура таблицы БД profiles я уже выше написал. Столбец user_id имеет тип bigint - видимо у меня что-то наследственное от создателей 128-битного протокола IPv6 :)
Сам он хоть и PRIMARY KEY, но не AUTO_INCREMENT. Просто это таблица как бы продолжение users. Все новые пользователи добавляются именно в users, а в эту тоько дописываются данные уже добавленных пользователей.
Далее идут три столбца - имя, фамилия и о себе.
Здесь может заинтересовать индекс KEY 'first_name' ('first_name','last_name').
Сам индекс может состоять как из одного, так и нескольких полей.
Когда мы думаем ставить ли индекс на столбец или нет, мы просто думаем - будет ли поиск по нему или нет.
Понятное дело что искать человека можно как только по имени, так и по имени и фамилии.
Вот для того чтобы СУБД не мучилась мы создаем такие индексы в несколько столбцов.

В index.php в переключателе добавляем

case 'user':
            if(!$this_id) header('location: /');
            $title = "Данные пользователя";
            $avafile = 'content/'.$this_id.'/s_ava.jpg';
            //var_dump(file_exists($avafile));
            if(!file_exists($avafile)) $avafile = '/content/default/s_ava.jpg';
            else $avafile = '/content/'.$this_id.'/s_ava.jpg';
            $user = getUserData($pdo, $this_id);
            $postsCount = getUserPostsCount($pdo, $this_id);
            $posts = getUserPosts($pdo, $this_id, 0, 20);
            //$contents = getContentsUser($pdo, $this_id);
            $mctCount = getInsUserMctsCount($pdo, $this_id);
            $ins_mcts = getInsUserMcts($pdo, $this_id, 0, 20);
            //var_dump($user);
            //var_dump($posts);
            $tpl = 'user';
            break;

Здесь на самом деле ничего сложного.
Выполняется проверка есть ли у пользователя фотка на аватарку (то есть загружал ли он ее) и если есть то в переменную записывается ссылка на нее, иначе записываем ссылку на аваторку по умолчанию (с какой нибудь собакой или вопросиком).
Потом выполняются запросы к различным функциям из нашего core.php.
Таким образом мы инициализируем переменные, которые затем будем использовать в шаблоне.

В шаблоне самом следует отметить две вещи.
Во-первых у нас в переменных может быть массив строк из базы данных.
Они обрабатываются в цикле foreach о которых я писал в предыдущем уроке.
Выглядеть это будет так:

<div id="posts">
<?//var_dump($posts);?>
<div class="row">
<? $i = 0; foreach($posts as $post){ ?>
<?if($i == 4){?></div><div class="row toppost"><? $i=0; } $i++;?>
<div class="col-md-3">
<?if($post['content_id']){?>
<a href="/post/<?=$post['id']?>"><im* class="img-responsive img-thumbnail" src="/content/<?=$post['user_id']?>/s_<?=$post['content_time']?>.jpg" alt="" /></a>
<?}else{?>
<a href="/post/<?=$post['id']?>"><im* class="img-responsive img-thumbnail" src="/content/default/s_mediamo.jpg" alt="" /></a>
<?}?>
<div><a href="/post/<?=$post['id']?>"><?=annotationStr($post['text'])?></a></div>
<small><?=$post['post_time']?></small><br />
<?//var_dump($post);?>
</div>
<?}?>
</div>
</div>
* img - тег не рендерется почему то 

Сначала мы смотрим как выглядет массив, потом перебираем его элементы в цикле, одновременно раскидывая на 4 колонки, чтобы смотрелось как на новостном сайте.

Второе, что нам интересно - это взаимодействие с АПИ. Рассмотрим настройки данных пользователя:

<form action="" method="post" onsubmit="return false;">
<div class="col-md-3">
<p>Имя:<br /><input class="form-control" type="text" id="first_name" name="first_name" value="<?=$user['first_name']?>" /></p>
<p>Фамилия:<br /><input class="form-control" type="text" id="last_name" name="last_name" value="<?=$user['last_name']?>" /></p>
<p>City ID:<br /><input class="form-control" type="text" id="city_id" name="city_id" value="<?=$user['city_id']?>" /></p>
</div>
<div class="col-md-9">
<p>О себе:<br /><textarea class="form-control" id="about" name="about" rows="5" cols="80"><?=$user['about']?></textarea></p>
<p><input class="btn btn-default" type="submit" id="user_update" value="Сохранить" /></p>
</div>
</form>

Здесь у каждого элемента формы есть атрибут id, например, у кнопки - user_update.
Мы их используем для получения доступа к элементам (их свойствам и значению), а также можем повесить на элемент слушатель события.
Рассмотрим как мы работаем с этой формой из js:

$("#user_update").on("click", function(){
    var first_name = $("#first_name").val();
    var last_name = $("#last_name").val();
    var city_id = $("#city_id").val();
    var about = $("#about").val();
    //alert('first_name: ' + first_name + ' last_name: ' + last_name + ' city_id: ' + city_id + ' about: ' + about);
    $.post( // get неправильно форматирует запрос!
        '/api/updateUser',
        {
            "user_id": this_id,
            "user_hash": this_hash,
            "first_name": first_name,
            "last_name": last_name,
            "city_id": city_id,
            "about": about,
        },
        function(data){
            //alert(data.response);
            location.reload(true);
        }
    );
});

Опять же не без помощи библиотеки jQuery получаем значения элементов input и textarea и с помощью $.post передаем их сервеверу.
API о котором шла речь в уроке 20 находит функцию updateUser которая у нас в coreapi.php:

    // Функции работы с данными user'abs
    function updateUser($pdo){
        
        $user_id = clearInt($_POST['user_id']);
        $user_hash = clearStr($_POST['user_hash']);
        // TODO: validate min 1 chars
        $first_name = clearStr($_POST['first_name']);
        $last_name = clearStr($_POST['last_name']);
        $city_id = clearStr($_POST['city_id']);
        $about = clearStr($_POST['about']);
        
        header('Content-Type: application/json');
        if(check($pdo, $user_id, $user_hash)){
            //print_r($_POST);
            
            if(setProfileData($pdo, $user_id, $first_name, $last_name, $city_id, $about)){
                print '{"response":1}';
            }else{
                print '{"response":0, "error":"No updated user data"}';
            }
        }else{
            print '{"response":0, "error":"No avtorized user"}';
        }
    }

Это АПИ я устроил так, что проверка авторизации check() в каждой функции свое (хотя следовало бы вынести в отдельный сегмент кода, так как оно почти всегда похоже).
После проверки вызывается функция core.php setProfileData():

function setProfileData($pdo, $user_id, $first_name, $last_name, $city_id, $about){
        $user_id = $pdo->quote($user_id);
        $first_name = $pdo->quote($first_name);
        $last_name = $pdo->quote($last_name);
        $city_id = $pdo->quote($city_id);
        $about = $pdo->quote($about);
        
        $sql_update = "UPDATE mc_profile SET first_name=$first_name, last_name=$last_name, city_id=$city_id, about=$about WHERE user_id=$user_id";
        //print $sql_update;
        
        if($pdo->exec($sql_update)){
            return true;
        }else{
            return false;
        }
        
    }

Что собственно в итоге и приводит к обновлению данных профиля пользователя.


В следующем уроке обсудим реализацию пунктов подписки и подписчики.
53
152.181 GOLOS
На Golos с November 2016
Комментарии (0)
Сортировать по:
Сначала старые