Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
PHP. Практика создания Web-сайтов (второе издание). Авторы: Кузнецов М.В., Симдянов И.В. PHP 5/6. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Редактирование. Не отправляется в форму для редактирования
 
 автор: davidoff_72   (24.08.2014 в 04:11)   письмо автору
 
 

Пытаюсь отправить информацию на редактирование. Где то согрешил.
В форме для редактирования (edit.php) выводится первая запись с таблицы а не так которая выбрана.
Помогите. Наверное где в районе href ошибка.

$query = "SELECT `produkt`.id AS produkt, `produkt`.name, `message`.id AS message_id, `message`.id, `message`.text, `message`.telefon, `message`.email, `message`.site, `message`.vaks FROM `produkt`, `message` WHERE `message`.produkt = `produkt`.id";
$result = mysql_query($query);


echo '<table border="1" cellspacing="0" cellpadding="3" align="center">';
echo '<thead>';
echo '<tr>';
echo '<th>№</th>';
echo '<th>Работодатель:</th>';
echo '<th>Товарная группа:</th>';
echo '<th>Телефоны:</th>';
echo '<th>E-mail:</th>';
echo '<th>Сайт работодателя</th>';
echo '<th>Ссылка</th>';
echo '<th>Дата</th>';
echo '<th>Удалить</th>';
echo '</tr>';
echo '</thead>';
echo '<tbody>';

while ($row = mysql_fetch_array($result))
{
echo '<tr>';
echo "<td><a href='edit.php?id=", $row[0],"'>$row[id]</a></td>";
echo "<td><a href='edit.php?id=", $row[0],"'>$row[text]</a></td>";
echo "<td><a href='edit.php?id=", $row[0],"'>$row[1]</a></td>";
echo "<td><a href='edit.php?id=", $row[0],"'>$row[telefon]</a></td>";
echo "<td><a href='edit.php?id=", $row[0],"'>$row[email]</a></td>";
echo "<td><a href='edit.php?id=", $row[0],"'>$row[site]</a></td>";
echo "<td><a href='edit.php?id=", $row[0],"'>$row[vaks]</a></td>";

echo '</tr>';
}

  Ответить  
 
 автор: Yuriev   (24.08.2014 в 13:02)   письмо автору
 
   для: davidoff_72   (24.08.2014 в 04:11)
 

Может потому, что во всех ссылках
<a href='edit.php?id=", $row[0]
запрашивается первая строка?

  Ответить  
 
 автор: davidoff_72   (25.08.2014 в 15:20)   письмо автору
 
   для: Yuriev   (24.08.2014 в 13:02)
 

Пытался менять, не получается. Вопрос где то глубже.
Помогите, если можете.

Вся цепочка выглядит так:

add.php - форма для внесения информации в таблицу message + выпадающий список из таблицы produkt
save.php - фаил который сохраняет внесенную в форму информацию в таблие message
index.php - выводит в список поля из двух таблиц (основная часть кода этой страницы смотрите выше )
edit.php - форма для редактирования таблицы message + выпадающий список из таблицы produkt
update.php - фаил где сохранятеся информация

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


save.php

<?php
$connect = mysql_connect("localhost", "cddelop11659", "c5c3042db9");
mysql_query('SET NAMES utf8');
$select = mysql_select_db("cddelop11659", $connect);

$data = $_POST['text_body'];
$fon = $_POST['telefon'];
$email = $_POST['email'];
$koment = $_POST['koment'];
$site = $_POST['site'];
$vaks = $_POST['vaks'];
$produkt = $_POST['produkt'];

$sql = "INSERT INTO `message` (`id`, `text`, `telefon`, `email`, `produkt`, `koment`, `site`, `vaks`, `date`)VALUES (NULL, '$data','$fon', '$email', '$produkt', '$koment', '$site', '$vaks', NOW());";
$result = mysql_query($sql, $connect);
if ($result)
{
echo "<h3>Информация добавлена!!</h3>";
}
else
{
echo "<h3>Увы, но информация не добавлена!!</h3>";
}
echo "<a href='index.php'>Вернуться на главную</a>";

?>



edit.php

<?php
$connect = mysql_connect("localhost", "cddelop11659", "c5c3042db9");
mysql_query('SET NAMES utf8');
$select = mysql_select_db("cddelop11659", $connect);

$id = $_GET['id'];


//$sql = "SELECT * FROM message WHERE id=$id";
//$sql = "SELECT * FROM message INNER JOIN produkt USING (produkt)"; ???
//$sql = "SELECT message.produkt AS produkt.name FROM message, produkt WHERE message.produkt = produkt.name";
//$result = mysql_query("SELECT * FROM message", $connect);

$sql = "SELECT `produkt`.id AS produkt, `produkt`.name, `message`.id AS message_id, `message`.id, `message`.text, `message`.telefon, `message`.email, `message`.site, `message`.vaks FROM `produkt`, `message` WHERE `message`.produkt = `produkt`.id";
$result = mysql_query($sql, $connect);

$row = mysql_fetch_array($result);

echo "<table>";
echo "<form method='post' action='update.php?id=$id'>";

echo "<p>Дата внесения в базу: $row[3]</p>";


echo "<p>Название фирмы:<textarea rows='1' name='text' cols='40'>$row[1]</textarea></p>";

echo "<p>Телефоны: <textarea rows='1' name='telefon' cols='40'>$row[2]</textarea></p>";
echo "<p>E-mail: <textarea rows='1' name='email' cols='40'>$row[4]</textarea></p>";
echo "<p>Сайт работодателя <textarea rows='1' name='site' cols='40'>$row[7]</textarea></p>";
echo "<p>Ссылка: <textarea rows='1' name='vaks' cols='40'>$row[8]</textarea></p>";
echo "<p>Коментарии: <textarea rows='4' name='koment' cols='50'>$row[5]</textarea></p>";

$connect = mysql_connect("localhost", "cddelop11659", "c5c3042db9") or die ('не подключился');
mysql_query('SET NAMES utf8');
$select = mysql_select_db("cddelop11659", $connect) or die ('не выбрана база');
$query = mysql_query("SELECT * FROM produkt ORDER BY name") or die ('не выбарна таблица или столбцы');

echo 'Товарная группа..........';
echo "<select name=\"produkt\" style=\"width:260px\">";
while ($data = mysql_fetch_row($query))
{
echo "<option name=\"produkt\" >".$data[1]."</option>";
}
echo '</select>';

mysql_free_result($result);
mysql_close($connect);

echo "<input type='submit' value='Изменить запись'/>";
echo "</form>";
echo "</table>";
?>


Прошу о помощи. Помогите разобраться, если можете.

  Ответить  
 
 автор: KPETuH   (25.08.2014 в 15:30)   письмо автору
 
   для: davidoff_72   (25.08.2014 в 15:20)
 

Где в вашем запросе вы видите выборку по уникальному id (либо по другому какому уникальному полю)? Я его не вижу.

  Ответить  
 
 автор: davidoff_72   (25.08.2014 в 16:58)   письмо автору
 
   для: KPETuH   (25.08.2014 в 15:30)
 

Помогите. Я изучаю прогармирование 3 месяца.
Такая же схема при одной таблице работает. После того, как я добавил втроую таблицы `produkt` , не редактируется.

  Ответить  
 
 автор: moonfox   (25.08.2014 в 17:26)   письмо автору
 
   для: davidoff_72   (25.08.2014 в 16:58)
 

а что сложно вообще осмотреть что ваш массив содержит?

  Ответить  
 
 автор: davidoff_72   (25.08.2014 в 22:52)   письмо автору
 
   для: moonfox   (25.08.2014 в 17:26)
 

Моего уровня понимания не хватает. Если можете подскажите.

  Ответить  
 
 автор: confirm   (26.08.2014 в 01:33)   письмо автору
 
   для: davidoff_72   (25.08.2014 в 22:52)
 

Ну так вы учитесь хотя бы на том, что изучайте моменты на которые вам указывают.

1) Приучайте себя сразу к аккуратности. Как вы пишите - message, и тут же produkt, хотя на английском продукт это - product, но никак не смесь английского с транскрипцией русской. Забудьте о таком написании, на английском короче можно выразиться, да и не так сложно будет воспользоваться словарем, если что.

2) Если имена полей двух таблиц не повторяются, то пишите проще:

<?
$query 
"SELECT `product`*, `message`.* FROM `product`, `message` WHERE `message`.product = `product`.id";


Вот только возникает опять вопрос по именованию - это как понять `message`.product = `product`.id? Вообще-то по идее должны сравниваться два id, а не id c product. Нет ли тут ошибки, или же это опять "причуды" с именованием и все верно?

3) Если вы не используете в стилях, в клиентских скриптах теги таблицы <thead> и <tbody>, то не стоит их и упоминать. Прописывать устаревшие html атрибуты таблицы border, cellspacing, cellpadding, align тоже не стоит, пользуйтесь CSS.

4) Выводить по отдельности строки конструкцией echo не стоит, лучше в одну строку объединить:

<?
echo '<table><tr><th>№</th>...';


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

5) Заголовок вашей таблицы имеет 9 ячеек, а вот далее вы выводите строку таблицы в которой всего 7 ячеек. Это ошибка.

Если запрос возвращает одну строку записи в таблице (я это предполагаю по параметру запроса id), то цикл не нужен, как и не нужны опять многократные echo, и многократное повторение одного и того же выводимого содержания. Кроме этого использовать mysql_fetch_array(), а затем в разнобой то индексный, то ассоциативный ключ, это плохо, если для этого нет условий. А также вы используете какой-то гибрид при выводе конкатенацию и поиск переменных в строке:

echo "<td><a href='edit.php?id=", $row[0],"'>$row[id]</a></td>";
echo "<td><a href='edit.php?id=", $row[0],"'>$row[text]</a></td>";
echo "<td><a href='edit.php?id=", $row[0],"'>$row[1]</a></td>";
.....


Предположим, что у вас тут непорядок, с которым надо разобраться, и число возвращаемых запросом данных равно числу ячеек таблицы, тогда все это можно записать так:

<?php
$query 
"SELECT `product`*, `message`.* FROM `product`, `message` WHERE `message`.id = `product`.id";
$result mysql_query($query); //здесь необходима проверка, и если запрос удачен, то только тогда вывод
?>
<table>
   <tr>
     <th>№</th>
     <th>Работодатель:</th>
     <th>Товарная группа:</th>
     <th>Телефоны:</th>
     <th>E-mail:</th>
     <th>Сайт работодателя</th>
     <th>Ссылка</th>
     <th>Дата</th>
     <th>Удалить</th>
   </tr>
   <tr>
<?php
$row 
mysql_fetch_assoc($result);
echo 
'<td><a href="edit.php?id='.$row=['id'].'">' implode('</a></td><td><a href="edit.php?id='.$row=['id'].'">'$row) . '</a></td>'
?>
   </tr>
</table>


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

Исходя из предположения, что возвращается одна строка (хотя это не принципиально, можно и в цикле подобное делать) и количество возвращаемых значений равно числу ячеек строки таблицы, я просто соединил элементы массива $row через строковое значение, которое у вас постоянно (хотя это тоже вопрос - зачем на каждое поле ссылка).

Если же это не так, то по крайней мере можно определить переменную, которой присвоить постоянно повторяющееся, подставляя ее при выводе, а не монотонно писать одно и тоже. Например, так:

<?
$link 
'<td><a href="edit.php?id='.$row=['id'].'">'


6) Вроде бы как вам говорилось - когда вставляете код в свое сообщение, то обрамляйте его ВВ-тегами [сode]Тут ваш код[/сode], тогда он будет с подсветкой, так как у меня в примерах. Иначе читать ваш код трудно.

  Ответить  
 
 автор: davidoff_72   (26.08.2014 в 02:32)   письмо автору
 
   для: confirm   (26.08.2014 в 01:33)
 

Большое спасибо за труды! Учусь по всем направлениям.

1. К английским словам начну приучаться.
2. Работает так как надо имеенно такая комбинация -
 `message`.product = `product`.id 
- в одно поле `message` вносится из выпадающего списка одно из записей таблицы `product` (таблица `product создана для обслуживания таблицы `message`).
3. до css я пока что не дошел. Мне в первую очередь надо разобраться с фундаментальным - с базой данных. потом я начну оформлять.
4. согласен, у меня слишком много echo. у вас очень красиво написано. приму на вооружение, но после того , как разбирусь с проблемами с базой данных.

Я не програмист, мне приложение необходимо для рабооты. У меня два сатйа и crm - программа заказанная у програмистов и всё с комплексом недостатков, зтрачена куча денег. Поэтому решил понемногу сам изучить програмирование. Выводится в форму для редактирования только первая запись из таблицы.

Мой код работаел нормально, пока была одна таблица, как табавил `product`, то появилась проблема с редактированием.

  Ответить  
 
 автор: confirm   (26.08.2014 в 15:06)   письмо автору
 
   для: davidoff_72   (26.08.2014 в 02:32)
 

2) ID - это первые два символа от английского identifier, что означает идентификатор, который как атрибут HTML (в чем у вас тоже была ошибка) всегда уникален (его значение). В РНР эта аббревиатура тоже должна быть уникальна, хотя нет проблем именовать как id, не соблюдая уникальности. Но в этом случае пропадает всякий смысл именования.

Исходя из того, что ID уникален, а идентификаторы могут иметь любые описываемые в таблице сущности, нужно использовать этот атрибут в именовании этих сущностей. Это может быть как значение идущее после префикса, например, product_id, message_id, и т.п., либо просто добавление одной/нескольких символов впереди, например для пользователей (users) - uid, для продуктов (products) - pid, и т.п.

В базе данных уникальность обеспечивается полем с автоинкрементом, которое имеет уникальный ключ. Другими словами атрибут ID, это де-факто стандарт уникального значения. Поэтому, читая в параметрах запроса:

`message`.product_id = `product`.product_id


сразу понятно, что связывается по идентификаторам, а вот:

`message`.product = `product`.id


это не вызывает никакой ассоциации, и стороннему наблюдателю ни о чем не говорит. Но даже при `message`.product_id = `product`.product_id, ваш запрос наводит на размышление - неудачное хранение данных.

В программировании главное не язык РНР, SQL и др., главное это мышление. Если не можем домыслить подобающе задачу, бесполезно ее программировать, а в противном случае мысленно представленная структура данных задачи и ее решение закономерно будут описаны программным кодом.

А мыслить над задачей надо начинать не с конструкций языка, а вполне человеческими понятиями. Вернемся к вашему первому коду, в котором ошибка html-структуры таблицы. Представьте, что у вас 9 камушков, и 9 спичечных коробков. Вы решили разложить эти камушки в коробки, надписали коробки как "Камушек 1", "Камушек 2", "Камушек 3" ... Но по непонятным причинам два последних коробка не имеют вкладышей. Вопрос не имеющий отношения к программированию - сможете ли вы разложить все камушки в коробки? Конечно нет. Но тогда почему заголовок вашей таблицы имеет 9 полей ("Камушек 1", "Камушек 2", "Камушек 3" ...), а то что должно быть под заголовком, строка таблицы, всего 7 ячеек (коробков, то есть два коробка без вкладышей)?

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

Я задавал по этому поводу вам вопрос, но ответа так и не получил. Вот и получается, что это наводит на мысль о непродуманности структуры данных и как следствие совсем не та структура таблиц. А `message`.product = `product`.id и получение запросом одной строки только усугубляет такую уверенность.

Вы фермер, а не программист. У вас есть молочное стадо, аж 2 коровы: "Буренка" и "Сестренка". На случай пропажи и для статистики, вы описали характеристики их в таблице, в тетрадке

Имя         Приметы    Надои
Буренка     Черная     10
Сестренка   Белая      15


Все нормально, удобно. Но есть еще ветеринар, который тоже следит за вашими буренками и прописывает им микстуры. Значит добавляем и их в таблицу:

Имя         Приметы    Надои   Назначения
Буренка     Черная     10      Лекарство 1
Сестренка   Белая      15      Лекарство 1


Тоже нормально, но нормально до поры до времени - пока буренкам назначается одна и та же микстура "Лекарство 1". Как только одной из буренок или обеим кроме этого лекарства будут назначены и другие, и они могут постоянно меняться, такая таблица в тетрадке будет не удобна:

Имя         Приметы    Надои   Назначение_1    Назначение_2    Назначение_3
Буренка     Черная     10      Лекарство 1    -              Лекарство 5  
Сестренка   Белая      15      Лекарство 1    Лекарство 4    Лекарство 8


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

Имя         Назначения
Буренка     Лекарство 1
Буренка     Лекарство 5  
Сестренка   Лекарство 1    
Сестренка   Лекарство 4    
Сестренка   Лекарство 8


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

Еще в первом вашем посте, а теперь после `message`.product = `product`.id и получение результатом одной записи, у меня укрепляет уверенность в том, что ваш ветеринар назначает вашим буренкам всегда строго по одному лекарству "Лекарство 1" или "Лекарство 2", или "Лекарство 3" ... То есть таблица назначений вам не нужна, а вы ее упорно используете, и достаточно в основной таблице менять название лекарства.

4) Нет, чтобы не было проблем, думать надо стразу, и как будут чередоваться поля таблиц полей тоже сразу. Echo сто раз повторяющее нужно выбрасывать уже сейчас, а не потом когда разберетесь, ибо понять эту конструкцию сущий пустяк, база к ней отношения не имеет.

Вернемся к буренкам, уже имея некоторое представление о коде поэтому опишем в таблице наших буренок и список лекарств так:

--
-- Структура таблицы `cow`
--

CREATE TABLE IF NOT EXISTS `cow` (
  `cid` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Идентификатор',
  `name` varchar(15) NOT NULL COMMENT 'Имя',
  `yields` tinyint(3) unsigned NOT NULL COMMENT 'Надои',
  `signs` varchar(15) NOT NULL COMMENT 'Приметы',
  `description` text NOT NULL COMMENT 'Описание',
  `vet_date` datetime DEFAULT NULL COMMENT 'Дата последнего осмотра ветеринаром',
  `mid` tinyint(4) DEFAULT NULL COMMENT 'Лекарство',
  PRIMARY KEY (`cid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Буренки' AUTO_INCREMENT=3 ;

--
-- Дамп данных таблицы `cow`
--

INSERT INTO `cow` (`cid`, `name`, `yields`, `vet_date`, `signs`, `description`, `mid`) VALUES
(1, 'Буренка', 10, NULL, 'Черная', 'Очень буйная, хлещет хвостом.', NULL),
(2, 'Сестренка', 12, NULL, 'Белая', 'Спокойная, даже флегматичная корова.', NULL);


--
-- Структура таблицы `veterinary`
--

CREATE TABLE IF NOT EXISTS `veterinary` (
  `mid` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Идентификатор',
  `remedy` varchar(32) NOT NULL COMMENT 'Лекарство',
  PRIMARY KEY (`mid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Список лекарств' AUTO_INCREMENT=6 ;

--
-- Дамп данных таблицы `veterinary`
--

INSERT INTO `medicine` (`mid`, `remedy`) VALUES
(1, 'Лекарство 1'),
(2, 'Лекарство 2'),
(3, 'Лекарство 3'),
(4, 'Лекарство 4'),
(5, 'Лекарство 5');


Для того чтобы удобно было выводить не прописывая каждое из полей html-таблицы как отдельное строковое значение (не нужны не только многократное echo, но даже повторение одних и тех же строковых значений в одной конструкции echo), мы выбрали в таблице базы такое чередование полей, какое будет соответствовать выводимой html-таблице.

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

К примеру есть субъекты Вася Иванов и Коля Петров. Чтобы окликнуть одного из них достаточно ли будет назвать только имя или нужно называть и фамилию? В данном случае конечно нет, необходимость в фамилии возникнет только тогда, когда будет еще и третий субъект, имя которого может совпадать с одним из двух первых.

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

Чередование полей таблицы базы выбрано из расчета использования функции implode(). Это на тот случай, если в записи выбирается все. Но вывод списка для выбора на редактирование, это вывод только основных параметров буренок, все будут нужны только при редактировании, поэтому порядок нужных полей будет задавать параметр запроса. Но отсутствие необходимости каждому полю в html-таблице назначать ссылку не позволить объединить этой функцией в строку весь массив сразу, так как ссылка будет только на втором поле. Это не страшно, потому как можно извлечь по отдельности два первых элемента массива функций array_shift(), усекая исходный массив в начале, а к оставшимся применить implode()

Теперь будем выводить. Тут могут быть два варианта:
а) каждой буренке может назначаться только одно лекарство из списка;
б) каждой буренке может назначаться несколько лекарств из списка.

Вариант а:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style>
body {
    font: 12px Arial;
    background: #fff;
    color: #000;
}
table {
    font: 12px Arial;
    border-collapse: collapse;
}
th {
    background: #ddd;
    border: 1px solid #000;
    border-bottom: 0;
    padding: 8px;
}
td {
    border: 1px solid #000;
    padding: 8px;
}
em {
    font-weight: normal;
}
form {
    width: 500px;
}
label {
    display: block;
    width: 100%;
    margin-bottom: 10px;
}
textarea {
    width: 100%;
    margin-bottom: 10px;
}
</style>
</head>
<body>
<?php
//запрос от формы
//извлекаем id буренки, это последний элемент формы - кнопка
//усекая POST массив в конце - array_pop
//и если приведение к integer будет не равно 0, то запись в базу
if($_POST && $cid  = (int)array_pop($_POST)) { 
    
//получаем истинные имена полей таблицы - светить структуру таблиц баз, это не разумно
    //эти имена храним где-то в массиве
    //если версия РНР =>5.4, то объявлять массив можно проще $fields = [значения массива]
    
$fields = array('fld-1'=>'description''fld-2'=>'yields''fld-3'=>'mid');
    
//получаем имена полей и добавляем поле даты 
    
$fields array_intersect_key($fields$_POST)+array('vet_date');
    
//защита данных и добавление даты
    
$_POST array_map('mysql_real_escape_string'$_POST)+array(date('Y-m-d H:i'));
    
//формируем строку запроса
    
$sql 'UPDATE cow SET '.rtrim(implode(array_map(function($k$v) {
        return 
$k.'="'.$v.'",';
    }, 
$fields$_POST)), ',').' WHERE cid='.$cid;
    if(
mysql_query($sql)) echo 'Ошибка записи!'
}

//вывод списка
if(!$_GET || $_POST) {
   if(
$q mysql_query('SELECT cid, name, yields, (SELECT remedy FROM veterinary WHERE mid = t1.mid) remedy, DATE_FORMAT(vet_date, "%e.%c.%Y") FROM cow t1')) {
      if(
mysql_num_rows($q)) { 
?>
<table>
  <tr>
    <th>№</th>
    <th>Имя</th>
    <th>Надои<em>, л.</em></th>
    <th>Последний осмотр</th>
    <th>Назначение</th>
  </tr>
<?
            
while($r mysql_fetch_row($q)) { //знаем порядок полей, поэтому достаточно и индексов
                
$id array_shift($r);
                
$tbl .= '<tr><td>'.$id.'</td><td><a href="edit.php?id='.$id.'">'.htmlspecialchars(array_shift($r)).'</a><td>'.
                        
implode('</td><td>'array_map('htmlspecialchars'$r)).'</td></tr>';          
            }
            echo 
$tbl.'</table>';
        } else echo 
'В базе записей о буренках нет.';
    } else echo 
'Ошибка запроса!';      
}

//получение формы редактирования
if(!$_POST && $cid = (int)$_GET['id']) {
    
//если параметр запроса число и не равно нулю, вывод
    //получаем все характеристики запрашиваемой буренки
    
if($q mysql_query('SELECT *, DATE_FORMAT(vet_date, "%e.%c.%Y") vet_date FROM cow WHERE cid='.$cid)) {
        if(
mysql_num_rows($q)) { //есть такая буренка
            //получаем данные как объект, чтобы меньше кавычек и т.п..
            
$q mysql_fetch_object($q);
            if(
$q mysql_query($db'SELECT * FROM veterinary')) {
                
//вывод формы
                
$f '<form method="post">
                      <label>Имя: '
.htmlspecialchars($r->name).'</label>
                      <label>Приметы: '
.htmlspecialchars($r->signs).'</label>
                      <label>Описание:</label><textarea name="fld-1">'
.htmlspecialchars($r->description).'</textarea>
                      <label>Надои: <input name="fld-2" value="'
.$r->yields.'" />  л.</label>
                      <label>Дата последнего осмотра: '
.$r->vet_date.'</label>
                      <label>Лекарства: <select name="fld-3"><option value="">Выберите лекарство</option>'
;
                
//добавляем список
                
while($s mysql_fetch_object($q)) $f .= '<option value='.$s->mid.($s->mid==$r->mid ' selected' null).'>'.htmlspecialchars($s->remedy).'</option>';
                echo 
$f.'</select><br><br><button name="fld-4" value='.$cid.'>Отправить</button></form>';      
            } else echo 
'Ошибка запроса!';
        }
    } else echo 
'Ошибка запроса!';
}
?>
</body>
</html>


Здесь все в одном файле, edit.php - и вывод списка, и форма, и запись формы. Это не значит, что именно так и надо поступать, но можно и так, если несложная задача. Примененные функции кроме указанных ранее:

rtrim
array_pop
array_intersect_key
array_map
mysql_real_escape_string
mysql_num_rows
mysql_fetch_object
htmlspecialchars

не так сложны, чтобы не понять их. И важно помнить, что mysql_real_escape_string важна для строковых значений перед их записью, а htmlspecialchars при их выводе из базы.

Вариант б:

В этом случае одна таблица о буренках не может хранить все их параметры. В этом случае назначения ветеринара нужно хранить в отдельной таблице, как cid (id буренки) и mid (id лекарства), и эти два поля организуют единый уникальный ключ.

В этом случае при выводе потребуется не вложенный запрос как в варианте а), а объединение таблиц при запросе с помощью JOIN. И будет уже иной вывод html-таблицы, список лекарств должен иметь множественный выбор, и запись в базу будет уже иная.

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

  Ответить  
 
 автор: Valick   (26.08.2014 в 19:49)   письмо автору
 
   для: confirm   (26.08.2014 в 15:06)
 

а htmlspecialchars при их выводе из базы.
confirm, с вашего позволения уточню (естественно не для вас), "при выводе в браузер", не важно из базы, из файла, из сессии, из кук или ещё откуда, но всё то что вводиться пользователем, перед выводом в браузер пропускаем через эту функцию для защиты от XSS атак
___
я всё-таки надеюсь вы половину этого откуда-то скопипастили, набивать столько текста ручками лично у меня бы терпежу не хватило :)

  Ответить  
 
 автор: confirm   (26.08.2014 в 20:17)   письмо автору
 
   для: Valick   (26.08.2014 в 19:49)
 

Спасибо за ценное замечание. В данном случае речь идет о записи/выводе из базы, об этом и говорится. Что касается вывода вообще, это уже не мне учить, и ссылку не мне показывать, а ему, он в этом нуждается.

  Ответить  
 
 автор: davidoff_72   (26.08.2014 в 22:22)   письмо автору
 
   для: Valick   (26.08.2014 в 19:49)
 

Для меня пока что защита от атак это что то за гранью поннимания. Но спасибо!

  Ответить  
 
 автор: davidoff_72   (26.08.2014 в 22:19)   письмо автору
 
   для: confirm   (26.08.2014 в 15:06)
 

Большое спасибо добрй человек!
Сижу, вникаю... Если можно, буду писать вопросы, так как постоянно сталкиваюсь тем , что не понимаю...
Спасибо!

  Ответить  
 
 автор: davidoff_72   (27.08.2014 в 00:32)   письмо автору
 
   для: confirm   (26.08.2014 в 15:06)
 

Возможно мой вопрос покажется не корректным, но я не нахожу подключения? как код подключается к базе данных?

Свой SELECT я адаптировал с этой страницы. Наверное не лучший пример, но хватало на мои знания.
http://audio.probudget.ru/programmirovanie/mysql-i-php-vivod-dannich-iz-neskolkich-tablits
Подобное рекомендуется на авторитетном сате: http://www.php.su/articles/?cat=phpdb&page=008

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

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

Вопрос - а почему - MyISAM а не InnoDB? Вроде второй варинат используют для связи таблиц...

Большинство из вашего кода я ещё не понимаю. Просто не хватает знаний ещё.

Попытался вывести в браузер ваш код...выдало ошибку на эту строку:
$sql = 'UPDATE cow SET '.rtrim(implode(array_map(function($k, $v) { 



В своем старом варианте
`message`.product = `product`.id 
поменял
`message`.product = `product`.name 
- выдало всю таблицу. Но к сожалению в форму редактирования не выдало то что надо

Продолжаю изучать и смотрю в словорях.
Большое спасибо

  Ответить  
 
 автор: confirm   (27.08.2014 в 04:24)   письмо автору
 
   для: davidoff_72   (27.08.2014 в 00:32)
 

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

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

То есть каждой фирме присваивается товарная группа, которую она продает.

Я исходя из такой постановки вопроса и написал пример, и он работает так, как я и ставил вопрос. А ваш запрос:

"SELECT `produkt`.id AS produkt, `produkt`.name, `message`.id AS message_id, `message`.id, `message`.text, `message`.telefon, `message`.email, 
`message`.site, `message`.vaks FROM `produkt`, `message` WHERE `message`.produkt = `produkt`.id";


наводит на мысль, что в ваших размышлениях полная билиберда. Если этот запрос результат того, что вы по указанным ссылкам что-то там увидели, потом адаптировали, то значит либо вы не то увидели или не так адаптировали. Авторитетнее РНР источник быть не может, ибо это источник, тоже самое и по SQL, есть первоисточник.

MyISAM или InnoDB? Как это всегда и бывает, у каждого из них есть плюсы и минусы. Используйте то, что вам более подходит (если вы понимаете разницу и что именно подходит), но мне кажется, что на данном этапе для вас это не такое и принципиальное значение.

Главное, это у вас какая-то не состыковка, еще раз:

То есть каждой фирме присваивается товарная группа, которую она продает. - это означает, что из многих вариантов один, то есть вариант а) из буренок. Но вы пишите - Вроде второй варинат используют для связи таблиц.

Если этого не понять сразу, еще даже не думая ни о РНР, ни о SQL, это значит и не иметь представления даже о том, как все это описать карандашом в тетрадке (читайте примеры ранее), то бесполезно браться это облекать в программную форму.

Я же по всему что вы тут на форуме о своих клиентах написали, считаю, что у вас как раз вариант а).

Как выглядит мой запрос для получения списка буренок (ваших клиентов):

'SELECT cid, name, yields, (SELECT remedy FROM veterinary WHERE mid = t1.mid) remedy, DATE_FORMAT(vet_date, "%e.%c.%Y") FROM cow t1'


На словах, это будет так:

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

Если сравнить с этим ваш запрос, и если речь о варианте А, то ваш запрос этому не соответствует.

О большинстве кода которого вы не понимаете:

А вы хотели, чтобы я тоже писал как вы, многократным echo выводя по кусочку? Конечно же я так писать не буду, подстраиваться под начинающего и писать так как ему понятно тоже не буду, а тем более не буду говорить ему - РНР это набор циклов и echo.

Например, что далее при выводе я делаю - обрамляю тегами TD первый элемент (id буренки) полученного массива ($r = mysql_fetch_row($q) - $r, это массив полученный из строки ресурса), извлекая его функцией array_pop, при этом массив $r усекается на одно значение, из него удаляется первый элемент. Далее таким же образом извлекается первый элемент (теперь это будет уже имя буренки, так как ранее мы усекли массив на одно значение), но только кроме TD я обрамляю имя буренки еще и ссылкой. После этого массив $r будет содержать всего два значения - дату и название лекарства. И выгоднее эти элементы вывести с помощью implode. Особенно удобен такой подход в случаях, если объем извлеченных данных большой. Здесь же это ради примера как возможности поступать так.

Такое возможно потому, что ячейки таблицы не имеют особенностей, и кроме ячейки с именем содержащей ссылку, других особенностей нет, и значения выводятся без каких либо проверок/условий. В противном случае так вывести уже не получилось бы, необходимо было бы описывать каждую ячейку (выводимое значение) отдельно.

То есть, применение array_pop и implode, это не самоцель, а возможность сократить код, если это позволяют условия.

Чтобы понять то что я написал, нужно просто прочесть о функциях применяемых, тогда придет понимание. И уж поверьте, это не сложно, а привычка не доверять словам "РНР это набор циклов и echo", ковыряясь все таки в РНР, это полезно для извилин и упрощает конструкции кода. Читать о функциях, изучать их работу на простых примерах, это все что требуется. Работа array_pop проста, много объяснений не требует. А implode, как следует из ее описания, работает так - объединяет элементы массива (второй аргумент функции) в строку через разделитель указанный первым аргументом функции. Причем первый аргумент функции может быть опущен, и тогда элементы объединяемого массива будут соединены слитно:

<?
//это массив
$a = array(123);
//объединяем его элементы в строку через запятую
echo implode(','$a); //результат - 1,2,3
//объединяем без разделения
echo implode($a): //результат - 123
//отсюда недолго сделать заключение - можно элементы массива и html-тегами
//нам надо обрамить их тегами ячеек таблицы
//а так как разделитель вставляется между элементами
//значит мы должны указать в качестве разделителя закрывающий и открывающий теги
//а в начале добавить открывающий тег для первого элемента, и в конце закрывающий для последнего
echo '<td>'.implode('</td><td>'$a).'</td>; //результат - <td>1</td><td>2</td><td>3</td>  


Просто? Конечно, даже до смешного, но если только читать, вникать.

На примере строки, которая у вас вызывает ошибку и поясним еще раз на словах, что это на самом деле просто. Тем более, что в эту строку я изначально заложил "избыток", дабы потом в качестве ответа на вопрос пояснить разницу. А если ошибка, то тем более есть повод.

Но сперва отвлечемся, и поясню почему я написал "избыток".

Стоит задача - написать строку запроса обновления таблицы. Это можно сделать тремя способами:

1) написать явно (в лоб) - UPDATE имя_таблицы SET имя_поля=значение, имя_поля=значение, имя_поля=значение, ... Такой подход при больших массивах данных или при анонимном обращении к ним не удобен.

2) используя цикл. В моем примере имена полей, это отдельный массив ($fields) полученный путем пересечения массивов (по их ключам) - массива имен полей таблицы базы ($fields) и массива $_POST, из которого извлечен последний элемент - кнопка содержащая значение идентификатора буренки, при этом массив усечен на один элемент с конца. К этому массиву добавляется имя поля хранящего дату - ('vet_date').
Элементы значений, это элементы массива $_POST (после усечения, удаления из него кнопки) с добавлением значения текущей даты - date('Y-m-d H:i').
Чтобы объединить эти массивы в строку, как параметры запроса, циклом, можно обхойти массив имен полей ($fields) циклом for(), обращаясь по номеру его итерации как индексу к массиву $_POST, получая таким образом значение.
Можно, но скучно и конструкция при этом блещет минимализмом. Лучше объединим тогда эти два массива в один (array_combine) и используем цикл foreach(). Поехали:

<?
//здесь функцией array_combine() объединяем массив имен полей с их значениями
//функция вернет массив, в котором ключами будут имена полей из массива $fields
//а их значением значения из массива $_POST
$fields array_combine($fields$_POST);
//начинаем формировать строку запроса
$sql 'UPDATE cow SET ';
//в цикле при каждой его итерации строка $sql дополняется (.=) значением
//имя_поля="значение" с завершением запятой  
foreach($fields as $k=>$v$sql .= $k.'="'.$v.'",';
//после цикла строка будет завершаться запятой, которую надо удалить, 
//так как далее идет ключевое слово WHERE
//удаляем ее функцией rtrim и дополняем сразу строку завершением запроса
$sql rtrim($sql',').' WHERE cid='.$cid;


Мой "избыток" точь в точь повторяет суть этого варианта, почему я его и вклеил в код. А теперь поясним почему при array_map это избыток.

3) используя array_map, что тоже является циклом, просто явно мы его не видим и не задаем. Вся прелесть этой функции в том, что она возвращает массив обработанный/полученный нужным нам способом (в примере она применяется и при выводе - array_map('htmlspecialchars', $r)). А это значит, что это действие мы можем сразу подключить в вывод/формирование строки, упрощая конструкцию.

Теперь об "избытке" в моем примере. Мы знаем, что функция implode объединяет между собой элементы через указанный разделитель. То есть в моем примере должно возвращаться:

<?
//вместо
return $k.'="'.$v.'",';
//это
return $k.'="'.$v.'"'//то есть закрывать запятой не надо
//так как каждый элемент массива будет содержать следующее:
//имя_поля_таблицы="значение"
//без запятой в конце 


А с помощью implode объединим элементы этого массива через запятую, что и требуется. Rtrim здесь лишнее тогда. То есть без излишка должно быть так:

<?
$sql 
'UPDATE cow SET '.implode(','array_map(function($k$v) {
        return 
$k.'="'.$v.'"'
}, 
$fields$_POST)).' WHERE cid='.$cid;


Легко пояснить все это и словами:

обойти (array_map) все элементы массивов ($fields, $_POST), передавая каждый их элемент функции ($k, $v), объединив их в строку и вернув результат, элементы возвращенного массива объединить в строку через запятую.

А так как эта конструкция является частью строки формируемой ($sql), то мы сразу получаем нужный результат.

Теперь об ошибке. Первый аргумент функции array_map указывает на функцию, которой будут обработаны элементы массива передаваемые в нее. Вы можете записать эту конструкцию так:

<?
$sql 
'UPDATE cow SET '.implode(','array_map('set_update_vars'$fields$_POST)).' WHERE cid='.$cid;
//объявив внешнюю функцию обработчик - set_update_vars
function set_update_vars($k$v) {
    return 
$k.'="'.$v.'"';
}   


Другой способ, это задать анонимную функцию с помощью create_function.

А я использую анонимную функцию явно - array_map(function($k, $v) {}..., что стало возможным начиная с версии 5.3. Значит у вас версия более старая, если перейдете на более новую, что желательно и желательно не ниже 5.4, то и проблема исчезнет.

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

О безопасности

Об этом нужно думать всегда, если ваше приложение использует удаленный сервер, а не работает изолированно на домашнем компьютере.
Hmlspecialchars в данном случае не сколько защита от угроз, а предотвращение ошибок html-структуры страницы, которые могут возникнуть, если вы по ошибке введете недопустимый символ в значение. В этом случае, например, ваша форма будет "разбита", и устранять придется все руками в базе.
А вот mysql_real_escape_string, это как раз против атак, которые могут организовать "плохие парни".

  Ответить  
 
 автор: davidoff_72   (27.08.2014 в 14:47)   письмо автору
 
   для: confirm   (27.08.2014 в 04:24)
 

Здравствуйте!
Читаю с упоением. Спасибо! разбираюсь потихоньку

  Ответить  
 
 автор: davidoff_72   (28.08.2014 в 01:01)   письмо автору
 
   для: confirm   (27.08.2014 в 04:24)
 

Перечитываю предложения по нескольку раз..Откровенно , не хватает пока знаний для быстррого осмысления..
Так же наткнулся на информацию, что таблицы при создании необходимо сразу связывать... Истинно ли данное утверждение? мне показалось, что Вы предлагаете связывать таблицы из кода... возможно, я ещё не всё разобрал.

  Ответить  
 
 автор: confirm   (28.08.2014 в 06:29)   письмо автору
 
   для: davidoff_72   (28.08.2014 в 01:01)
 

Не знаю что вы там прочли, о какой связи, скорее всего вы не понимаете о чем там пишется.

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

Вернемся к нашим баранам, то есть коровам. Кстати в дампах я оставил ошибку - создается таблица с именем veterinary:

CREATE TABLE IF NOT EXISTS `veterinary`


а дамп для нее указан как для таблицы medicine:

INSERT INTO `medicine` (`mid`, `remedy`) VALUES
должно быть
INSERT INTO `veterinary` (`mid`, `remedy`) VALUES


Если хотите разобраться и понять на примере этом, то исправьте.

Связаны ли две таблицы этого примера или нет?

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

<?
//список лекарств
$medic_list = array(
    
=> 'Лекарство 1',
         
'Лекарство 2',
         
'Лекарство 3',
         
'Лекарство 4',
         
'Лекарство 5'
);

//теперь при выводе списка буренок не требуется вложенного запроса за названиями лекарств, 
//и запрос будет таким
if($q mysql_query('SELECT *, DATE_FORMAT(vet_date, "%e.%c.%Y") vet FROM cow')) {
    
//а вывод ячеек таблицы таким
    
while($r mysql_fetch_object($q)) $tbl .= '<tr><td>'.$r->cid.'</td><td><a href="edit.php?id='.$r->cid.'">'.htmlspecialchars($r->name).'</a></td>
                     <td>'
.$r->yields.'</td><td>'.$r->vet.'</td><td>'.$medic_list[$r->mid].'</td></tr>';            
}
//а вот так будет добавляться этот список в форму
//добавляем список
foreach($medic_list as $k=>$v$f .= '<option value='.$k.($k==$r->mid ' selected' null).'>'.htmlspecialchars($v).'</option>';


Ячейка таблицы названия лекарства получает значение как $medic_list[$r->mid] - id лекарства из базы как индекс массива $medic_list. Другими словами таблица cow базы в поле mid хранит индекс массива $medic_list, по которому при выводе таблицы получаем значение. Разве исходя из этого можно сказать, что таблица cow связана с массивом $medic_list? Конечно же нет, этот массив просто переменная хранящая некие значения. Хотите назовите этот массив сервисным, хотите информационным, хотите просто хранилищем.

То же самое в случае когда лекарства находятся в таблице базы - действительно связи между таблицами cow и veterinary нет. Таблица veterinary - это просто хранилище, из которого при выводе таблицы cow вложенным запросом к ней получаем название лекарства по указателю хранящемуся в поле mid таблицы cow.

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

А если ветеринар может назначать каждой буренке по несколько лекарств, то хранить эти назначения в таблице cow как id лекарства (mid) уже нельзя. В этом случае действительно нужна таблица связанная с таблицей cow, которая будет хранить множества назначений для каждой буренки. Структура этой таблицы при этом будет такая: поле cid хранящее id буренки и поле mid хранящее id лекарства. Поле mid из таблицы cow удаляется. Список SELECT при этом должен иметь атрибут multiple, позволяющий делать выбор нескольких значений в нем, а имя его должно ассоциироваться с массивом - name="name_select[]".

Таблица назначений будет связана с таблицей cow по id буренок. При выводе таблицы cow нужно объединить ее данные с данными таблицы назначений по cid, получая id лекарства (mid), и по полученному mid объединить еще и таблицу хранилища лекарств, так как именно в ней хранятся их наименования.

В этом случае результирующий запрос вернет не обязательно две записи, так как буренок две, а равное общему числу назначенных буренкам лекарств, то есть, например у первой 2 назначения, а у второй 3, значит запрос вернет 5 записей. И вывод html-таблицы будет несколько сложнее при этом.

Вот что такое связь. Но не РНР и SQL породило нас и мы теперь пытаемся жить по их правилам, а мы породили РНР и SQL, наделив их необходимыми средствами позволяющими решить наши потребности. Поэтому, не решайте свою задачу задом наперед, а определитесь со своими потребностями и только потом берите те средства из РНР и SQL, которые позволят их решить.

Ведь на SELECT свет клином тоже не сошелся, а что если кроме имени продукта необходима еще информация, например содержащая некие условия по каждому продукту? В этом случае SELECT не подходит. Но не проблема решить эту проблему - если каждому клиенту можно назначить только один продукт, значит список продуктов для выбора на странице можно описать группой радио-кнопок (input type=radio), а если несколько продуктов для каждого клиента, то массивом флажков (input type=checkbox), и можно вывести любую сопутствующую продуктам информацию.

Пора ответить на вопрос самому себе - один продукт из множества или несколько?
Если один, то никакой связанной таблицы не нужно, иначе кроме списка продуктов нужна и связанная таблица хранящая множественный выбор, сама таблица продуктов при этом как была хранилищем, так им и останется.

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

Определились с этим, приступили к выбору как хранить, какие инструменты потребуются из РНР. Вот и все решение. В противном случае застрянете на начальном этапе в умных терминах.

  Ответить  
 
 автор: davidoff_72   (30.08.2014 в 02:44)   письмо автору
 
   для: confirm   (28.08.2014 в 06:29)
 

Ошибку исправил. По не внимательности удивлялся, почему не вставляется.

В моем случае, фирма может продавать товаров больше одного. И у меня возникает вопрос - а как я выведу в брауззер, в список фирм, если вирм может продавать 10-20 ассортиментных единиц.
Спасибо.

  Ответить  
 
 автор: davidoff_72   (30.08.2014 в 00:36)   письмо автору
 
   для: confirm   (27.08.2014 в 04:24)
 

Изначально я хотел - один товар из многих , теперь поннимаю что необходимо много товаров из многих. Да, я адаптировал, но потом убедился, что не все выводит и мой зпрос тоже не все выводил до "адаптирования".
Из масива я сразу научился выводить, из двух криво получилось. Теперь вижу, что это изначально был не правильный путь. Мне нужно сделать, чтоб у одной фирмы могло быть больше одной товарной группы.
Не всё что вы написали я понимаю, изза недостатка знаний. Мои знания покачто ограничиваются: подключение к базе данных, выбор одной таблицы и полей и вывод их в таблицу html примитивным способом. ну ещё, кое как могу внести в базу из формы.
Но каждый день узнаю, что то новое , включая то, что сначала надо спроектировать все в голове.
Вы рекомендуете исправить проблему одним из спсобов, но я пока что многого из написанного не поннимаю. И второй вопрос, может оставить эту проблему и начать изучать "многие из многих".
Спасибо.

  Ответить  
 
 автор: confirm   (30.08.2014 в 11:54)   письмо автору
 
   для: davidoff_72   (30.08.2014 в 00:36)
 

Чтобы появился "достаток" в знаниях, нужно не просто копировать код, а еще и изучать его. То есть открывать РНР-руководство и читать о функциях, которые применяются в коде. О функциях нужно не просто читать, а пробовать их на примерах, чтобы понимать их работу. В руководстве кроме описания функции зачастую есть и простые примеры.

Ошибку у вас вызывает то, что у вас версия РНР ниже 5.3. Я писал как можно вынести анонимную функцию во внешнюю. Тогда и ошибки не будет. Но лучше поступать не так, а ориентироваться на версию РНР, которая у вас на реальном хосте. Если вы мой пример пробуете на локальном сервере и на нем версия ниже 5.3, а на реальном 5.3 или выше, значит установите и на локальном сервере версию старше. Если у вас локальный хост это Денвер, то на нем без знаний вам этого не сделать. Но лучше выбросить Денвер, он остановился в развитии, а скачать и установить Openserver, в нем легко переключаться между различными конфигурациями сервера.

То, что пришло понимание, что требуется на самом деле, это уже успех. Правда это понимание должно приходить загодя до намерения его запрограммировать, ибо это потребность чисто техническая, которую без наличия РНР и SQL можно было бы осуществить в обычных тетрадках учета.

Вот этот же пример, но уже под хранение множественного выбора. Данные назначения кроме идентификатора, и наименования содержат и описания. Это просто для того, чтобы показать то, о чем я говорил ранее - выбор не обязательно всегда SELECT, бывают моменты когда он не подходит. Если нужен список для продуктов, то его выводить нужно так, как и ранее, только добавить атрибут для множественного выбора и к имени списка добавить [].
В остальном прием данных и сохранение их в базе ничем отличаться не будет, так как и флажки, и список со множественным выбором это массив.

Теперь дампы такие

--
-- Структура таблицы `cow`
--

DROP TABLE IF EXISTS `cow`;
CREATE TABLE IF NOT EXISTS `cow` (
  `cid` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Идентификатор',
  `name` varchar(15) NOT NULL COMMENT 'Имя',
  `yields` tinyint(3) unsigned NOT NULL COMMENT 'Надои',
  `vet_date` datetime DEFAULT NULL COMMENT 'Дата последнего осмотра ветеринаром',
  `signs` varchar(15) NOT NULL COMMENT 'Приметы',
  `description` text NOT NULL COMMENT 'Описание',
  PRIMARY KEY (`cid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Буренки' AUTO_INCREMENT=3 ;

--
-- Дамп данных таблицы `cow`
--

INSERT INTO `cow` (`cid`, `name`, `yields`, `vet_date`, `signs`, `description`) VALUES
(1, 'Буренка', 15, '0000-00-00 00:00:00', 'Черная', 'Очень буйная, хлещет хвостом.'),
(2, 'Сестренка', 12, '0000-00-00 00:00:00', 'Белая', 'Спокойная, даже флегматичная корова');


--
-- Структура таблицы `appoint` - таблица связанная с таблицей cow
--

DROP TABLE IF EXISTS `appoint`;
CREATE TABLE IF NOT EXISTS `appoint` (
  `cid` int(11) unsigned NOT NULL COMMENT 'идентификатор буренки',
  `mid` int(10) unsigned NOT NULL COMMENT 'идентификатор лекарства',
  UNIQUE KEY `cid` (`cid`,`mid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='назначения';

--
-- Дамп данных таблицы `appoint`
--

INSERT INTO `appoint` (`cid`, `mid`) VALUES
(1, 2),
(1, 4),
(1, 5),
(2, 1),
(2, 3),
(2, 5);

--
-- Структура таблицы `veterinary`
--

DROP TABLE IF EXISTS `veterinary`;
CREATE TABLE IF NOT EXISTS `veterinary` (
  `mid` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Идентификатор',
  `remedy` varchar(32) NOT NULL COMMENT 'Лекарство',
  `descript` text NOT NULL COMMENT 'описание',
  PRIMARY KEY (`mid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Список лекарств' AUTO_INCREMENT=6 ;

--
-- Дамп данных таблицы `veterinary`
--

INSERT INTO `veterinary` (`mid`, `remedy`, `descript`) VALUES
(1, 'Лекарство 1', 'Против насморка'),
(2, 'Лекарство 2', 'Болеутоляющее'),
(3, 'Лекарство 3', 'Вакцина'),
(4, 'Лекарство 4', 'Против чего-то'),
(5, 'Лекарство 5', 'Для чего-то');


Код, подключение к базе добавите. Анонимная функция теперь не используется, обработчик во внешней функции set_update_vars(). Но как я говорил выше, эту проблему лучше решать переходом на более новую версию РНР, и использовать анонимные функции, если надобности во внешней кроме единственного употребления нет.

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style>
body {
    font: 12px Arial;
    background: #fff;
    color: #000;
}
table {
    font: 12px Arial;
    border-collapse: collapse;
}
th {
    background: #ddd;
    border: 1px solid #000;
    border-bottom: 0;
    padding: 8px;
}
td {
    border: 1px solid #000;
    padding: 8px;
}
em {
    font-weight: normal;
}
form {
    width: 500px;
}
label {
    display: block;
    width: 100%;
    margin-bottom: 10px;
}
textarea {
    width: 100%;
    margin-bottom: 10px;
}
</style>
</head>
<body>
<?php
//запрос от формы
//извлекаем id буренки, это последний элемент формы - кнопка
//усекая POST массив в конце - array_pop()
//и если приведение к integer будет не равно 0, то запись в базу
if($_POST && $cid  = (int)array_pop($_POST)) { 
    
//это ID буренки, которую редактируем
    
echo $cid.'<br><pre>'//это просто для визуального контроля, после просмотра удалить
    //так выглядит массив полученных данных после извлечения из него поля хранящего ID буренки
    //в нем отсутствует поле fld-4
    
print_r($_POST); //это просто для визуального контроля, после просмотра удалить
    //извлекаем из него данные новых назначений
    
$vet array_diff(array_map('intval'array_pop($_POST)), array(0));
    
//теперь полученные POST-данные содержат только то, что надо записать в таблицу cow - поля fld-1 и fld-2 
    
print_r($_POST); //это просто для визуального контроля, после просмотра удалить
    //а массив новых назначений (ID лекарств) для записи в таблицу appoint
    
print_r($vet); //это просто для визуального контроля, после просмотра удалить 
    
echo '</pre>'//это просто для визуального контроля, после просмотра удалить
    //массив имен полей таблицы cow
    
$fields = array('fld-1'=>'description''fld-2'=>'yields');
    
//получаем имена полей, добавляя имя поля даты осмотра
    
$fields array_intersect_key($fields$_POST)+array('vet_date');
    
//защита и добавление текущей даты
    
$_POST array_map('mysql_real_escape_string'$_POST)+array(date('Y-m-d H:i')); 
    
//обновляем таблицу cow
    
if(mysql_query('UPDATE cow SET '.implode(','array_map('set_update_vars'$fields$_POST)).' WHERE cid='.$cid)) {
        
//запись новых назначений, если есть для записи действительные - не равные 0
        
if($vet) {
            
//сперва удалим старые
            
if(mysql_query('DELETE FROM appoint WHERE cid='.$cid)) {
                
//записываем новые назначения
                
if(!mysql_query('INSERT INTO appoint VALUES ('.$cid.','.implode('),('.$cid.','$vet).')')) echo 'Ошибка';
            } else echo 
'Ошибка';
        }
    } else echo 
'Ошибка';
}

//вывод списка
if(!$_GET || $_POST) {
   
//получаем содержимое таблицы cow,
   //а назначения (названия лекарств)
   //получаем из таблицы veterinary 
   //через связанную таблицу appoint
   //путем объединения этих трех таблиц в запросе     
   
$q mysql_query('SELECT *
                     FROM cow
                     LEFT JOIN appoint t2
                     USING(cid)
                     LEFT JOIN veterinary t3
                     ON t2.mid=t3.mid'
);
   if(
$q) {
      if(
mysql_num_rows($q)) { 
?>
<table>
  <tr>
    <th>№</th>
    <th>Имя</th>
    <th>Надои<em>, л.</em></th>
    <th>Последний осмотр</th>
    <th>Назначение</th>
  </tr>
<?
        
//результат запроса может содержать несколько записей, более чем буренок
        //ID буренок, имена, их надои и даты осмотра нужно вывести один раз,
        //но эти данные присутствуют в каждой записи полученного результата  
        //поэтому устанавливаем внешнюю по отношению к циклу переменную $cid,
        //по которой будем определять один проход для этих данных
        
$cid 0;
        while(
$r mysql_fetch_object($q)) {  
            
//для того чтобы понять почему так организован вывод таблицы
            //можно визуально просмотреть что возвращает запрос
            //сколько записей и что они содержат
            //такой же конструкцией как и при записи
            //после просмотра удалив
            
echo '<pre>';
            
print_r($r);
            echo 
'</pre>';
            
            
//непосредственно вывод таблицы 
            
if($cid != $r->cid) {
                
$cid $r->cid//первый проход цикла для буренки
                //добавляем в таблицу все кроме лекарств, предварительно закрывая предыдущую строку таблицы
                
$tbl .= '</tr><tr><td>'.$cid.'</td><td><a href="edit.php?id='.$cid.'">'.htmlspecialchars($r->name).
                       
'</a></td><td>'.$r->yields.'</td><td>'.date('j.n.Y H:i'strtotime($r->vet_date)).'</td><td>';
            }
            
//вывод в последнюю ячейку строки таблицы всех назначений
            
$tbl .= htmlspecialchars($r->remedy).'<br>';           
        }
        echo 
$tbl.'</tr></table>';
    } else echo 
'В базе записей о буренках нет.';
} else echo 
'Ошибка запроса!';      
}

//получение формы редактирования
if(!$_POST && $cid = (int)$_GET['id']) {
    
//если параметр запроса число и не равно нулю, вывод
    //получаем все характеристики запрашиваемой буренки
    
if($q mysql_query('SELECT * FROM cow WHERE cid='.$cid)) {
        if(
mysql_num_rows($q)) { //есть такая буренка
            //это массив данных о буренке
            
$r $mysql_fetch_object($q);
            
//получаем список лекарств
            //и вложенным запросом получаем значение 1 (по условию IF для него), для тех ID лекарств (mid),
            //которые есть и в таблице назначений appoint для редактируемой буренки
            //если в ней не будет такого ID лекарства, что есть и в таблице veterinary,
            //то условие вернет не 1, а 0
            //этому возвращаемому значению присвоим псевдоним slc
            //и при выводе списка назначений по значению slc
            //будем знать, назначено ли на данный момент то или иное лекарство из списка для буренки 
            
if($q mysql_query('SELECT *, IF((SELECT 1 FROM appoint WHERE cid='.$cid.' AND mid=t1.mid), 1, 0) slc FROM veterinary t1')) { 
                
//вывод формы 
                
$f '<form method="post"> 
                      <label>Имя: '
.htmlspecialchars($r->name).'</label> 
                      <label>Приметы: '
.htmlspecialchars($r->signs).'</label> 
                      <label>Описание:</label><textarea name="fld-1">'
.htmlspecialchars($r->description).'</textarea> 
                      <label>Надои: <input name="fld-2" value="'
.$r->yields.'" />  л.</label> 
                      <label>Дата последнего осмотра: '
.date('j.n.Y H:i'strtotime($r->vet_date)).'</label> 
                      <label>Лекарства:</label>'

                
//добавляем в форму список лекарств, а так как они содержат еще и описания,
                //то новый выбор для назначений будет осуществляться массивом флажков 
                
while($s $mysql_fetch_object($q)) $f .= '<label><input type=checkbox name="fld-3[]" value='.$s->mid.($s->slc ' checked' null).' />'.
                                               
htmlspecialchars($s->remedy).' <em>'.htmlspecialchars($s->descript).'</em></label>'
                echo 
$f.'<br><br><button name="fld-4" value='.$cid.'>Отправить</button></form>';      
            } else echo 
'Ошибка запроса!';
        }
    } else echo 
'Ошибка запроса!';
}

//формирование строки параметров/значений для обновления  
function set_update_vars($k$v) {
    return 
$k.'="'.$v.'"';
}
?>
</body>
</html>


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

  Ответить  
 
 автор: davidoff_72   (30.08.2014 в 14:54)   письмо автору
 
   для: confirm   (30.08.2014 в 11:54)
 

Я стараюсь так и делать, если не понятное значение то нахожу его в документации и изучаю. Если с первого раза не запомню, то с пятого раза дойдёт.
У меня нет наверное способностей к програмированию, тяжело запоминаю и с трудом доходит, но есть непреодалимое желание написать приложение которое я хочу! Такое, как я хочу!

я в уме прикинул какие данные мне надо сохранять, как они будут взаимодействовать..стало страшно это 30-40 таблиц а может и больше...для моего понимания это много, если их ещё надо и взаимоувязать корректно, как вы писали выше (пример с назначениями для коров). Хочу потренироваться на двух таблицах (фирмы, товары), и я так понимаю надо сделать некую таблицу посредник (фирмо-товары). Уже понимаю, что сначало надо себе все представить, как это будет выглядить? В тетрадке пытаюсь рисовать, это своего рода архитектура... И возникает вопрос, необходимо ли сразу продумывать все таблицы и включить их в проект или можно потом постепенно добавлять?

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

Сажусь разбираться с кодом и Openserver

Спасибо

  Ответить  
 
 автор: confirm   (30.08.2014 в 17:05)   письмо автору
 
   для: davidoff_72   (30.08.2014 в 14:54)
 

С кодом Openserver разбираться не надо, это архив готового сервера. Нужно его распаковать и следовать инструкциям. В последней версии требуется наличие VC, поэтому будет вопрос на его установку при первом запуске его (в меню его такое выбрать, в системном трее панели задач). В Openserver есть файл помощи, где обо всем рассказано.

В конфигурации нужно выбрать ту версию РНР и SQL, которая будет использоваться и на реальном сервере. Сохранить конфигурацию, и сервер готов.

И возникает вопрос, необходимо ли сразу продумывать все таблицы и включить их в проект или можно потом постепенно добавлять?

Есть заказчики, которых просто убить охота. Заказывает работу, и некие тезисы генеральные считает за техническое задание, по которому исполнитель ну просто обязан написать код для него. Когда же уже по своей инициативе начинаешь уточнять, что же скрывается за этими тезисами, то вразумительного ответа получить не удается. Такие заказчики не могут ответить конкретно даже на конкретный вопрос, отвечая на него большим объемом слов не понятно чего. В конце концов доходит до накала, и на резонный вопрос как же он хочет, чтобы ему написали программу, если вместо ТЗ он предоставляет тезисы, отвечает лаконично (хоть это умеют выражать конкретно):
- Я не программист, не я это должен знать.

А кто должен? Кто должен лучше знать какими способами (и нужны ли они) сортировать список пряников при выводе - продавец пряников или программист, который о пряниках может знать только вкус, и то не всегда, если программа ориентирована как раз на продавца?

Это я к тому, что задумывая что-то, конечно же нужно стараться обдумать все о проекте своем. И это не обязательно что-то для будущей программы, это может быть и летняя беседка на дачном участке. Ну не продумали вы как надо, накупили, напилили, загвоздили, жена пришла с аргументом:
- Я же тебе говорила, что на этом месте нужно строить теплицу под....
Ломаете, строите заново.

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

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

Например, то что продуктов много, как некий их набор надо связать с клиентом теперь вы знаете - через таблицу связей. Как выводить и как добавлять тоже. Но оказывается "ихже несть числа", и представьте себе список или набор флажков с бесконечным числом опций/флажков - удобно ли будет, да и возможно ли вообще в таком списке сделать набор? Возможно придется продукты разбить на категории, те в свою очередь на подкатегории? А это значит, что таблица описывающая продукты будет не одна, а как минимум две. Значит и вывод списка для выбора будет иной. А может будет достаточно выводить такой список по частям?

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

А вот все связанное с клиентами и продуктами, это уже должно быть. Вывод списка, формы редактирования, обновление данных, это можно писать по частям, сразу все физически написать нельзя.

На все эти вопросы дает ответ структура исходных данных, и на начальном этапе можно понять во что это выльется, если сделать так или иначе. Но вам тут никто и не говорил, что написание программ, это как два пальца... Так что придется думать, учиться. А вот "У меня нет наверное способностей к программированию, тяжело запоминаю и с трудом доходит" мне сложно комментировать, возможно что и так, не знаю. Возможно это кажется, что не могу, а стоит только углубиться и понять немного и... Хотя определенная логика мышления для программирования необходима, это точно, и если ее нет, то увы.

  Ответить  
 
 автор: davidoff_72   (02.09.2014 в 15:55)   письмо автору
 
   для: confirm   (30.08.2014 в 17:05)
 

Можете подсказать, что за таинственное VC? ("...требуется наличие VC...")

  Ответить  
 
 автор: confirm   (01.09.2014 в 13:03)   письмо автору
 
   для: davidoff_72   (30.08.2014 в 14:54)
 

Сразу, как планировалось, ответить на все не получилось, поэтому дополнительно только теперь.

>я так понимаю надо сделать некую таблицу посредник (фирмо-товары)

Таблица "фирмо-товары" будет связывать между собой таблицу клиентов и таблицу продуктов (в примере такую роль выполняет таблица appoint, связывая таблицы cow и veterinary).

Действительно, если из списка veterinary выбирается только одно значение, то можно было бы писать в таблицу cow не id из этого списка, а сразу название. Но такой подход чреват тем, то если в списке какое либо значение будет изменено, например, исправлена ошибка допущенная в нем, то придется исправлять эту ошибку для всех записей в таблице cow.

При множественном выборе тоже можно записывать не набор id выбранных из списка, а названия, разделяя каждое тегом <br> или переводом строки, заменив их тегом <br> при выводе. При таком подходе можно не только наступить на грабли описанные выше, но еще получить одну проблему. Если к примеру, надо будет при выводе сортировать список по какому либо из назначений, то придется разбирать строку назначений, а это не продуктивно. А вот поиск указанного числа (id) и сортировка по нему, это быстро.

То есть при множественном выборе без связывающей таблице не обойтись. Ну и сразу нужно обдумывать сам процесс вывода и выбора. Изучая язык запросов SQL, вы вполне можете прийти к выводу о странности запроса:

'SELECT *, IF((SELECT 1 FROM appoint WHERE cid='.$cid.' AND mid=t1.mid), " checked", NULL) slc FROM veterinary t1'


при выводе флажка:

'<label><input type=checkbox name="fld-3[]" value='.$s->mid.($s->slc ? ' checked' : null).' />'


Действительно, если в запросе имеем возможность проверить выбрана ли данная опция у списка, то и атрибут checked (в случае применения SELECT - selected) для флажка можно установить прямо в запросе:

'SELECT *, IF((SELECT 1 FROM appoint WHERE cid='.$cid.' AND mid=t1.mid), " checked", NULL) slc FROM veterinary t1'


а при выводе флажка проверки условия не требуется, просто вывод:

'<label><input type=checkbox name="fld-3[]" value='.$s->mid.$s->slc.' />'


Если же проверку выбора опции производить при выводе ресурса:

'<label><input type=checkbox name="fld-3[]" value='.$s->mid.($s->slc ? ' checked' : null).' />'


то запрос должен быть таким:

'SELECT *, (SELECT 1 FROM appoint WHERE cid='.$cid.' AND mid=t1.mid) slc FROM veterinary t1'


Это "хлебные крошки" для вас.

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

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

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

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

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

Лучше извлечь конфигурации из базы единожды, сразу, в начале скрипта источника, определив эти значения как константы. Константа в отличие от переменной будет доступна всегда, то есть и в функции, не смотря на то, что она объявлена вне ее. Например, таблица конфигураций:

CREATE TABLE IF NOT EXISTS `config` (
  `conf_nav_count` tinyint(3) unsigned NOT NULL COMMENT 'число элементов на странице',
  `conf_nav_width` tinyint(3) unsigned NOT NULL COMMENT 'ширина навигатора',
  `conf_days_note` tinyint(3) unsigned NOT NULL COMMENT 'период дней до уведомления',
  `conf_days_delete` tinyint(3) unsigned NOT NULL COMMENT 'период дней до удаления'
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='конфигурации';

INSERT INTO `config` (`conf_nav_count`, `conf_nav_width`, `conf_days_note`, `conf_days_delete`) VALUES
(30, 10, 15, 30);


А в начале основного файла сценария, до подключения других сценариев, устанавливаем константы с именами полей таблицы конфигурации, соответственно с их значениями:

<?
$q 
mysql_query('SELECT * FROM config');
$q mysql_fetch_assoc($q);
$q array_change_key_case($qCASE_UPPER);
foreach(
$q as $k=>$vdefine($k$v);


Теперь можно оперировать константами, включая подстановку их в запрос, чтобы избежать вложенных запросов тоже:

<?
function myFunc($date) {
    echo  
$date >= CONF_DAYS_NOTE 'Внимание!' 'Норма';   
}

$sql 'SELECT *, IF(date_add + INTERVAL '.CONF_DAYS_DELETE.' DAY >= NOW(), 1, 0) del FROM table';

echo 
'Текущее значение равно '.CONF_DAYS_DELETE;


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

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

Вот таким образом.

  Ответить  
 
 автор: davidoff_72   (02.09.2014 в 02:01)   письмо автору
66.5 Кб
 
   для: confirm   (01.09.2014 в 13:03)
 

Катастрофа, практически ничего не понимаю. Нехватка знаний. Вижу надо многое изучать. Всё это надо будет долго разбирать.
Смысл с таблицами в общем понятен, а код, пока что нет..
Внёс всё в базу данных, создал три таблицы, всё вроде бы нормально внеслось.
Создал подключение к базе - выдалась в браузере таблица и ещё не понятно что...(картинка прикреплена).
Нача изучать теорию баз данных http://citforum.ru/database/osbd/contents.shtml ..не уверен конечно что именно это мне надо (Основы современных баз данных С.Д. Кузнецов)

  Ответить  
 
 автор: confirm   (02.09.2014 в 02:58)   письмо автору
 
   для: davidoff_72   (02.09.2014 в 02:01)
 

Непонятно что, это работа при выводе таблицы вот этих трех строк:

<?
//после просмотра удалив 
echo '<pre>'
print_r($r); 
echo 
'</pre>';


о которых написано - посмотрели раз, уяснили, удалили. Подобные строки есть и в коде приема данных от формы, которые тоже после ознакомления удалить, в конце каждой такой строки об этом сказано в комментарии. print_r($r) - выводит массив, в данном случае возращенный из строки ресурса. И этот вывод заключенный в тег PRE получается форматированным, иначе бы вывод был не колонкой, а все в строке.

Этот вывод наглядно показывает, что несмотря на то, что основная таблица cow, из которой происходит вывод, содержит всего две записи, ресурс возвращает записей больше, если назначений у каждой буренки более чем 1. То есть количество записей будет равно количеству записей в таблице appoint. При этом обратите внимание, что в каждой строке возвращенной ресурсом повторяется информация и о буренках. Это результат объединения таблиц при запросе. Но сама то таблица выведена же двумя строками, что и требуется, а в каждой последней ее ячейке перечислены текущие назначения буренки, и не одно, так как и требовалось. Но если бы не небольшая хитрость с внешней по отношению к циклу переменной $oid (читайте в комментариях к коду), и просто вывод while(...) {вывод таблицы}, то вы бы получили таблицу с количеством строк равных количеству записей, имя буренок и другие ее данные повторялись бы столько раз, сколько назначений им содержит таблица appoint, и назначения были бы выведены не все в одну ячейку таблицы, а выводились по одному в каждой строке таблицы.

Это понятно? Еще раз внимательно посмотрите на это "непонятно что". И вообще запомните эту простую конструкцию echo '<pre>'; print_r(array); echo '</pre>';, и можете ее считать простым визуальным "отладчиком". Если что-то непонятно "почему, вроде бы...?", выводите свой массив, который может пролить свет почему не так получается, или даст понять почему так получается.

Учить придется много, и РНР лучше начать изучать вот с этого http://php.net/manual/ru/langref.php. А по SQL действительно нужна книга, есть, значит хорошо.

  Ответить  
 
 автор: davidoff_72   (02.09.2014 в 03:39)   письмо автору
 
   для: confirm   (02.09.2014 в 02:58)
 

Убрал. да , ушло. Осталась таблица. Разбираюсь дальше.
Справочник языка пытался осваивать. Фундаментально. Тяжело воспринимается, но буду повторять.
продолжу изучать ваш код и таблицы. Попробую для наглядности адаптироваь под свои цели:
Фирмы, Товар
.
В коде обратил внимание на ссылку на
edit.php
, фаил делает ссылку на самого себя или на страницу
edit.php
?
В коде заметил форму:
$f = '<form method="post">  
, но у меня форма не выводится... или я чего то не понял?

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

Спасибо!

  Ответить  
 
 автор: confirm   (02.09.2014 в 03:47)   письмо автору
 
   для: davidoff_72   (02.09.2014 в 03:39)
 

edit.php - это я "условно" так назвал файл сценария, потому оно и упоминается в коде. Сохраните этот код в файле под любым именем, заменив и в коде его. Ссылка "на себя" так как все помещено в один файл.

Вывод формы происходит только по запросу редактирования буренки - в таблице имя буренки, это ссылка на ее редактирование, то есть запрос формы.

Принимается форма (обработка ее данных и сохранение) первой конструкцией кода, до вывода таблицы буренок, чтобы после приема формы в этой таблице отображались изменения.

  Ответить  
 
 автор: davidoff_72   (02.09.2014 в 04:39)   письмо автору
 
   для: confirm   (02.09.2014 в 03:47)
 

Код сохранил в файле под именем
index.php
, создал фаил
edit.php
создал в нём подключение к базе и "тупо" скопировал в него форму (на большее у меня соображения не хватило)...
<?php
$connect 
mysql_connect("localhost""cddelop11659""c5c3042db9") or die ('не подключился');
mysql_query('SET NAMES utf8');
$select mysql_select_db("confirm"$connect) or die ('не выбрана база');

if(
$q mysql_query('SELECT *, IF((SELECT 1 FROM appoint WHERE cid='.$cid.' AND mid=t1.mid), 1, 0) slc FROM veterinary t1')) {  
                
//вывод формы  
                
$f '<form method="post">  
                      <label>Имя: '
.htmlspecialchars($r->name).'</label>  
                      <label>Приметы: '
.htmlspecialchars($r->signs).'</label>  
                      <label>Описание:</label><textarea name="fld-1">'
.htmlspecialchars($r->description).'</textarea>  
                      <label>Надои: <input name="fld-2" value="'
.$r->yields.'" />  л.</label>  
                      <label>Дата последнего осмотра: '
.date('j.n.Y H:i'strtotime($r->vet_date)).'</label>  
                      <label>Лекарства:</label>'
;  
                
//добавляем в форму список лекарств, а так как они содержат еще и описания, 
                //то новый выбор для назначений будет осуществляться массивом флажков  
                
while($s $mysql_fetch_object($q)) $f .= '<label><input type=checkbox name="fld-3[]" value='.$s->mid.($s->slc ' checked' null).' />'
                                               
htmlspecialchars($s->remedy).' <em>'.htmlspecialchars($s->descript).'</em></label>';  
                echo 
$f.'<br><br><button name="fld-4" value='.$cid.'>Отправить</button></form>';       
            } else echo 
'Ошибка запроса!'
            
            
//формирование строки параметров/значений для обновления   
function set_update_vars($k$v) { 
    return 
$k.'="'.$v.'"'


?>


Выдает ошибку Ошибка запроса!. Подозреваю, что я впринципе сделал что то не правильно.

  Ответить  
 
 автор: confirm   (02.09.2014 в 04:58)   письмо автору
 
   для: davidoff_72   (02.09.2014 в 04:39)
 

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

Но если так хочется, разбивайте на части.А чтобы понять причину ошибки вместо else echo 'Ошибка запроса!'; напишите:

else echo mysql_error();


Теперь SQL вернет описание причины. А причина в том, что отсутствует переменная $cid (id буренки), которая подставляется в запрос, плюс вы выдрали из кода вывода формы только часть. То есть всю структуру:

<?
//определение id буренки от запроса формы ссылкой из таблицы
if(!$_POST && $cid = (int)$_GET['id']) { 
    
//тут запрос параметров буренки, что вы тоже выбросили 
    
if($q mysql_query('SELECT * FROM cow WHERE cid='.$cid)) { 
        
//код....
            //и выдрали из кода только это - получение данных для списка  
            
if($q mysql_query('SELECT *, IF((SELECT 1 FROM appoint WHERE cid='.$cid.' AND mid=t1.mid), 1, 0) slc FROM veterinary t1')) {  
                
//вывод формы  
                //....      
            
} else echo 'Ошибка запроса!'
        } 
    } else echo 
'Ошибка запроса!'
}


вы изменили на:

<?
if($q mysql_query('SELECT *, IF((SELECT 1 FROM appoint WHERE cid='.$cid.' AND mid=t1.mid), 1, 0) slc FROM veterinary t1')) {  
       
//вывод формы  
       //....      
} else echo 'Ошибка запроса!'


Если выносить (но правильно) в отдельный файл, то условие должно быть:

<?
if($cid = (int)$_GET['id']) {
    
//код
}


И форма должна иметь атрибут action="", в котором указан файл обработчик формы.

  Ответить  
 
 автор: davidoff_72   (02.09.2014 в 12:21)   письмо автору
 
   для: confirm   (02.09.2014 в 04:58)
 

Да, я заметил, что в
form 
не хватает, но подумал, может так надо , просто я не знаю.

  Ответить  
 
 автор: confirm   (02.09.2014 в 12:43)   письмо автору
 
   для: davidoff_72   (02.09.2014 в 12:21)
 

Чего не хватает, атрибута action?

В моем примере, где все в одном файле, он и не нужен, просто по умолчанию форма будет обращаться к текущему файлу, у вас это index.php, а если его назвать edit.php, то форма обратиться к edit.php.

Вы собрались вынести форму в отдельный файл, так к кому она должна обратиться? Если и обработчик этой формы вы тоже поместите в отдельный файл, то значит action формы должен указывать на этот файл.

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

  Ответить  
 
 автор: davidoff_72   (02.09.2014 в 15:00)   письмо автору
 
   для: confirm   (02.09.2014 в 12:43)
 

Согласен. Буду разбираться с вариантом "всё в одном файле". Для начала мне думаю так будет прощед.
Спасибо.

  Ответить  
 
 автор: confirm   (03.09.2014 в 19:02)   письмо автору
9.9 Кб
 
   для: davidoff_72   (02.09.2014 в 15:00)
 

Урок последний

>Буду разбираться с вариантом "всё в одном файле". Для начала мне думаю так будет проще

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

Прикреплен архив. В нем маленький проект добавления, редактирования на тему фирмы-товары. Как и о коровах, это пример, но уже как некий проект администрирования, со структурой директорий и файлов. Распакуйте этот архив в созданный домен в Openserver. В папке sql находится дамп базы данных, импортируйте его. Все таблицы не заполненные кроме таблицы конфигурации. Подключение к базе на пользователя root, который уже есть на локальном сервере.

Проект написан под версию РНР не ниже 5.4, в нем используется упрощенное объявление массива. Поэтому установите на своем локальном сервере версию не ниже 5.4. Перегружаем сервер, запрашиваем и смотрим. В отличие от буренок этот код проверялся, поэтому будет работать. В нем все по минимуму.

Комментарии к проекту

Задачи:

1) сделать добавление/вывод/редактирование фирм и товаров в административном разделе;
2) выбор операций с данными осуществлять из меню структурированное по основным разделам и таблиц-списков;
3) все изменения данных должны отображаться сразу после операций изменения;
4) вывод ошибок базы данных должен иметь два режима: режим отладки кода (редактирования и добавления его) - вывод ошибок, адреса источников ошибок, ошибочный запрос; режим для пользователей - определяется постоянным значением.

Условия:

1) поля форм добавления/редактирования данных должны быть обязательны для заполнения;
2) поля обязательные для заполнения без ввода данных должны подсвечиваться красным.

Решение:

Если проект о фирмах и товарных группах, следовательно нужно управлять двумя банками данных, это два раздела администрирования. Плюс управление конфигурацией, это еще раздел. Итого 3 раздела, которые отображены в простом одноуровневом меню. Выбор раздела в меню, это вывод списка банка запрашиваемых данных: фирмы, товарные группы или конфигурация. Если банк пуст, то выводится форма добавления данных в банк - фирмы или товарной группы. Если банк не пуст, то выводится таблица-список банка данных, в котором можно выбрать объект (фирму, товарную группу) для редактирования, и форма добавления новых данных в банк (фирмы, товарной группы).

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

Каждому пункту меню назначено значение от 1 до 3, которое во всех сценариях проекта определяет источник данных: фирмы, товарные группы или конфигурация. А тип операции над данными определяет имя ключа этого значения: itm - запрос меню (вывод списка данных раздела), add - добавление данных, edt - запрос формы редактирования данных, upd - обновление данных.

Такой подход упрощает написание кода, и если посмотреть на его конструкции, то видно, что они между собой различаются незначительно - набором данных, запросом к базе. А логика работы в блоках кода операций каждого раздела одинакова. Затраты на написание такого проекта мизерные, и пишется буквально Ctrl+C -> Ctrl+V, с небольшой правкой.

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

Но запросы меню и запросы из списков данных, это GET запросы, которые влияют на url-адрес, а запрос форм, это POST запросы не влияющие на url-адрес. Если после GET-запроса, а затем получения формы не перегрузить страницу, тем самым очистив массив GET-данных, то форма редактирования будет выводиться дважды (первая визуально остается на экране). Это потому, что диспетчеризация запросов осуществляется по GET и POST ключам, а так как POST запрос не изменяет url, то ранее запрошенный GET-ключ останется в url, тем самым спровоцировав лишний запрос на вывод формы.

Решение проблемы перезагрузкой в данном случае не лучший выход, а чтобы не усложнять логику проверки ключей в диспетчере запросов, для решения проблемы использована возможность формы при методе передачи POST передавать не только POST-данные, но и GET данные. Это достигается добавлением GET-данных в адрес атрибута action форм, и для решения указанной проблемы указываем этим данные, но пустые:

<form method="post" action="?" autocomplete="off">


Имя файла обработчика (index.php) , браузер подставит сам, то есть будет так - action="domain/index.php/?", но можно и явно указать имя индексного файла в форме. Пустые GET-данные переданные с формой очистят GET-массив, исключая повторный вывод формы.

Формы, это подключаемые файлы, при этом форма редактирования конфигураций индивидуальна, а для фирм и товарных групп одна базовая форма, у которой в зависимости от источника запроса (раздела данных) изменяются/добавляются параметры. Можно вообще написать функцию вывода формы, которая будет выводить нужную форму для каждого источника запроса, основываясь на соответствующей таблице данных, характеристиках ее полей. А логика обработки запросов позволяет это сделать. Пример такого формирования формы для разных источников запроса я уже приводил на форуме, но без понимания сути такого конструктора написать его код под себя вы не сможете.

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

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

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

Что не продумано проектом

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

А теперь добавьте несколько десятков товарных групп и попробуйте сделать выбор в их списке для фирмы. Удобно? И вряд ли вывод списка порциями (по аналогии с постраничным выводом фирм), это решение проблемы, наоборот, это усугубит проблему. А если как по вашим словам "их тыщи", тогда как?

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

  Ответить  
 
 автор: davidoff_72   (06.09.2014 в 14:53)   письмо автору
 
   для: confirm   (03.09.2014 в 19:02)
 

Да. нашел! Спасибо!
прошу прощения, не заметил прикрепелнній фаил. Сажусь разбираться.
Спасибо!

  Ответить  
 
 автор: davidoff_72   (02.09.2014 в 15:53)   письмо автору
 
   для: confirm   (30.08.2014 в 11:54)
 

То что я разберу на запчасти код и таблицы и разберусь как оно работает, это вопрос только времени (если конечно не сойду с ума...). Но смотрю в перспективу и уже возникает вопрос. Разобравшись с данным кодом я смогу создавать и связывать таблицы и их можно будет уже использовать в работе.
Но смотрю на вещи трезво, создать и увязать все таблицы сразу правильно, понятно что врядли получится, тем более. что их в перспективе 30-40штук. Переписать руками код или переделать таблицу с этим можно смирится. Единственное , что пугает это угроза утраты данных из таблиц при переделке.
Интуитивно чувствую, что данные можно сохранить при переделке базы данных. Но лучше сразу переспрошу. Для меня вопрос утраты данных и внесения их с нуля вручную это самый болезненный вопрос.
Правильно ли я понимаю, что можно сохранить данные при переделке базы данных?
Спасибо.

  Ответить  
 
 автор: confirm   (02.09.2014 в 17:15)   письмо автору
 
   для: davidoff_72   (02.09.2014 в 15:53)
 

Можно, для этого в phpmyadmin, который входит в комплект Openswerver нужно выбрать базу и экспортировать ее, можно экспортировать и каждую таблицу отдельно.

  Ответить  
 
 автор: davidoff_72   (02.09.2014 в 23:12)   письмо автору
 
   для: confirm   (30.08.2014 в 11:54)
 

Может я чего то не понимаю, но насколько я понимаю должно быть
$сid = cid
. Это должно быть до этой конструкции, насколько я знаю:
if($_POST && $cid  = (int)array_pop($_POST)) { 
, в чём секрет? Хотя в браузер информация выводится.

  Ответить  
 
 автор: confirm   (02.09.2014 в 23:37)   письмо автору
 
   для: davidoff_72   (02.09.2014 в 23:12)
 

С чего это вдруг? Во-первых:

//такого в РНР быть просто не может
$сid = cid
//строковые значения, а в данном случае вы пытаетесь 
//присвоить переменой $cid именно строковое значение,
//должны заключаться в кавычки, то есть, если бы,  то
$сid = 'cid';


Но с чего это вдруг? Вот что написано у меня:

<?
//запрос от формы 
//извлекаем id буренки, это последний элемент формы - кнопка 
//усекая POST массив в конце - array_pop() 
//и если приведение к integer будет не равно 0, то запись в базу
//а теперь временно добавьте перед этим "отладчик"
//о котором я говорил
if($_POST) {
   echo 
'<pre>';
   
print_r($_POST);
   echo 
'</pre>';
}
//будет выведен массив пришедший от формы
//и в нем последним его элементом
//будет элемент с ключом fld-4 и значением равным id буренки выбранной для редактирования

//перечитываем еще раз

//запрос от формы 
//извлекаем id буренки, это последний элемент формы - кнопка 
//усекая POST массив в конце - array_pop() 
//и если приведение к integer будет не равно 0, то запись в базу

//if($_POST && $cid  = (int)array_pop($_POST)) на словах
//это пришел ли POST запрос
//и если извлеченный последний элемент массива POST, а это id буренки
//приведенный к числовому значению не равен 0 (id не может быть равно 0,
//а если вам вместо id подсунули гадость строковую, то приведение к int
//как раз вернет 0),
 //то выполняем то, что указано в фигурных скобках
if($_POST && $cid  = (int)array_pop($_POST)) { 
    
//а тут помимо кода, есть опять вывод для уяснения
    //как изменяется массив POST
    //и что мы получаем из него
}

  Ответить  
 
 автор: davidoff_72   (02.09.2014 в 23:22)   письмо автору
 
   для: confirm   (30.08.2014 в 11:54)
 

Если нажимаю на "буренку" или "сестренку", то выдает ошибку ссылаясь на данную строку:
$r = $mysql_fetch_object($q); 
. Не могу разобраться. В чём секрет?

  Ответить  
 
 автор: confirm   (02.09.2014 в 23:38)   письмо автору
 
   для: davidoff_72   (02.09.2014 в 23:22)
 

Значит где-то при копировании кода, или еще по какой причине, вы допустили в нем ошибку.

  Ответить  
 
 автор: confirm   (03.09.2014 в 05:23)   письмо автору
 
   для: davidoff_72   (02.09.2014 в 23:22)
 

Нет, это моя ошибка - посмотрите в конструкции запроса формы в начале имени функции mysql_fetch_object() ошибочно добавлен $.

  Ответить  
 
 автор: davidoff_72   (03.09.2014 в 15:53)   письмо автору
 
   для: confirm   (03.09.2014 в 05:23)
 

Спасибо. Заработало.
Да, моя невнимательность - это даже я знаю, что надо
$cid = 'cid';
. и $mysql_fetch_object() можно было найти в коде , если присмотреться.
Разбираю код. Спасибо.

  Ответить  
 
 автор: confirm   (03.09.2014 в 16:10)   письмо автору
 
   для: davidoff_72   (03.09.2014 в 15:53)
 

Пример написан "с руки", не проверялся, поэтому и не заметил.

  Ответить  
 
 автор: davidoff_72   (06.09.2014 в 14:14)   письмо автору
 
   для: confirm   (03.09.2014 в 16:10)
 

немного разобрался с кодом и адаптировал под свои значения. Но многое все равно не постижимо для меня, пока.
Сейчас погрузился в изучение проектирования базы данных. И продумываю будущую базу и как всё будет работать.
По коду у меня вопрос - хорошо ли , что так много if в коде?

  Ответить  
 
 автор: confirm   (06.09.2014 в 14:20)   письмо автору
 
   для: davidoff_72   (06.09.2014 в 14:14)
 

В каком коде, в последнем что я оставил?

  Ответить  
 
 автор: davidoff_72   (06.09.2014 в 14:28)   письмо автору
 
   для: confirm   (06.09.2014 в 14:20)
 

Ранее (выше) вы писали. я заметил, что много if в if. Возможно у меня ещё недостаточно знаний.

<?php 
//запрос от формы 
//извлекаем id буренки, это последний элемент формы - кнопка 
//усекая POST массив в конце - array_pop() 
//и если приведение к integer будет не равно 0, то запись в базу 
if($_POST && $cid  = (int)array_pop($_POST)) {  
    
//это ID буренки, которую редактируем 
    
echo $cid.'<br><pre>'//это просто для визуального контроля, после просмотра удалить 
    //так выглядит массив полученных данных после извлечения из него поля хранящего ID буренки 
    //в нем отсутствует поле fld-4 
    
print_r($_POST); //это просто для визуального контроля, после просмотра удалить 
    //извлекаем из него данные новых назначений 
    
$vet array_diff(array_map('intval'array_pop($_POST)), array(0)); 
    
//теперь полученные POST-данные содержат только то, что надо записать в таблицу cow - поля fld-1 и fld-2  
    
print_r($_POST); //это просто для визуального контроля, после просмотра удалить 
    //а массив новых назначений (ID лекарств) для записи в таблицу appoint 
    
print_r($vet); //это просто для визуального контроля, после просмотра удалить  
    
echo '</pre>'//это просто для визуального контроля, после просмотра удалить 
    //массив имен полей таблицы cow 
    
$fields = array('fld-1'=>'description''fld-2'=>'yields'); 
    
//получаем имена полей, добавляя имя поля даты осмотра 
    
$fields array_intersect_key($fields$_POST)+array('vet_date'); 
    
//защита и добавление текущей даты 
    
$_POST array_map('mysql_real_escape_string'$_POST)+array(date('Y-m-d H:i'));  
    
//обновляем таблицу cow 
    
if(mysql_query('UPDATE cow SET '.implode(','array_map('set_update_vars'$fields$_POST)).' WHERE cid='.$cid)) { 
        
//запись новых назначений, если есть для записи действительные - не равные 0 
        
if($vet) { 
            
//сперва удалим старые 
            
if(mysql_query('DELETE FROM appoint WHERE cid='.$cid)) { 
                
//записываем новые назначения 
                
if(!mysql_query('INSERT INTO appoint VALUES ('.$cid.','.implode('),('.$cid.','$vet).')')) echo 'Ошибка'
            } else echo 
'Ошибка'
        } 
    } else echo 
'Ошибка'


//вывод списка 
if(!$_GET || $_POST) { 
   
//получаем содержимое таблицы cow, 
   //а назначения (названия лекарств) 
   //получаем из таблицы veterinary  
   //через связанную таблицу appoint 
   //путем объединения этих трех таблиц в запросе      
   
$q mysql_query('SELECT * 
                     FROM cow 
                     LEFT JOIN appoint t2 
                     USING(cid) 
                     LEFT JOIN veterinary t3 
                     ON t2.mid=t3.mid'
); 
   if(
$q) { 
      if(
mysql_num_rows($q)) {  
?> 
<table> 
  <tr> 
    <th>№</th> 
    <th>Имя</th> 
    <th>Надои<em>, л.</em></th> 
    <th>Последний осмотр</th> 
    <th>Назначение</th> 
  </tr> 
<? 
        
//результат запроса может содержать несколько записей, более чем буренок 
        //ID буренок, имена, их надои и даты осмотра нужно вывести один раз, 
        //но эти данные присутствуют в каждой записи полученного результата   
        //поэтому устанавливаем внешнюю по отношению к циклу переменную $cid, 
        //по которой будем определять один проход для этих данных 
        
$cid 0
        while(
$r mysql_fetch_object($q)) {   
            
//для того чтобы понять почему так организован вывод таблицы 
            //можно визуально просмотреть что возвращает запрос 
            //сколько записей и что они содержат 
            //такой же конструкцией как и при записи 
            //после просмотра удалив 
            
echo '<pre>'
            
print_r($r); 
            echo 
'</pre>'
             
            
//непосредственно вывод таблицы  
            
if($cid != $r->cid) { 
                
$cid $r->cid//первый проход цикла для буренки 
                //добавляем в таблицу все кроме лекарств, предварительно закрывая предыдущую строку таблицы 
                
$tbl .= '</tr><tr><td>'.$cid.'</td><td><a href="edit.php?id='.$cid.'">'.htmlspecialchars($r->name). 
                       
'</a></td><td>'.$r->yields.'</td><td>'.date('j.n.Y H:i'strtotime($r->vet_date)).'</td><td>'
            } 
            
//вывод в последнюю ячейку строки таблицы всех назначений 
            
$tbl .= htmlspecialchars($r->remedy).'<br>';            
        } 
        echo 
$tbl.'</tr></table>'
    } else echo 
'В базе записей о буренках нет.'
} else echo 
'Ошибка запроса!';       


//получение формы редактирования 
if(!$_POST && $cid = (int)$_GET['id']) { 
    
//если параметр запроса число и не равно нулю, вывод 
    //получаем все характеристики запрашиваемой буренки 
    
if($q mysql_query('SELECT * FROM cow WHERE cid='.$cid)) { 
        if(
mysql_num_rows($q)) { //есть такая буренка 
            //это массив данных о буренке 
            
$r $mysql_fetch_object($q); 
            
//получаем список лекарств 
            //и вложенным запросом получаем значение 1 (по условию IF для него), для тех ID лекарств (mid), 
            //которые есть и в таблице назначений appoint для редактируемой буренки 
            //если в ней не будет такого ID лекарства, что есть и в таблице veterinary, 
            //то условие вернет не 1, а 0 
            //этому возвращаемому значению присвоим псевдоним slc 
            //и при выводе списка назначений по значению slc 
            //будем знать, назначено ли на данный момент то или иное лекарство из списка для буренки  
            
if($q mysql_query('SELECT *, IF((SELECT 1 FROM appoint WHERE cid='.$cid.' AND mid=t1.mid), 1, 0) slc FROM veterinary t1')) {  
                
//вывод формы  
                
$f '<form method="post">  
                      <label>Имя: '
.htmlspecialchars($r->name).'</label>  
                      <label>Приметы: '
.htmlspecialchars($r->signs).'</label>  
                      <label>Описание:</label><textarea name="fld-1">'
.htmlspecialchars($r->description).'</textarea>  
                      <label>Надои: <input name="fld-2" value="'
.$r->yields.'" />  л.</label>  
                      <label>Дата последнего осмотра: '
.date('j.n.Y H:i'strtotime($r->vet_date)).'</label>  
                      <label>Лекарства:</label>'
;  
                
//добавляем в форму список лекарств, а так как они содержат еще и описания, 
                //то новый выбор для назначений будет осуществляться массивом флажков  
                
while($s $mysql_fetch_object($q)) $f .= '<label><input type=checkbox name="fld-3[]" value='.$s->mid.($s->slc ' checked' null).' />'
                                               
htmlspecialchars($s->remedy).' <em>'.htmlspecialchars($s->descript).'</em></label>';  
                echo 
$f.'<br><br><button name="fld-4" value='.$cid.'>Отправить</button></form>';       
            } else echo 
'Ошибка запроса!'
        } 
    } else echo 
'Ошибка запроса!'


//формирование строки параметров/значений для обновления   
function set_update_vars($k$v) { 
    return 
$k.'="'.$v.'"'

?> 

  Ответить  
 
 автор: confirm   (06.09.2014 в 14:39)   письмо автору
 
   для: davidoff_72   (06.09.2014 в 14:28)
 

If - это условие (если) и если необходимо проверить что-то по условию, то и пишется. А то, что вложение условий в условиях, так в этом ничего страшного нет.

Я же вам прикрепил целый мини-проект о фирмах и клиентах вместо коров, вы что по ссылке не читали?

  Ответить  
 
 автор: davidoff_72   (06.09.2014 в 14:53)   письмо автору
 
   для: confirm   (06.09.2014 в 14:39)
 

Да. нашел! Спасибо!
Прошу прощения, не заметил прикрепелнный фаил. Сажусь разбираться.
Спасибо!

  Ответить  
 
 автор: davidoff_72   (11.09.2014 в 03:24)   письмо автору
 
   для: confirm   (06.09.2014 в 14:39)
 

Большое спасибо! всё красиво работает!
Изучаю код: все не понятные мне значения копирую в вордовский фаил и вставляю описание из документации. Работаю как учёный , разбирая экземпляр на детали и изучая их. Изучив данный код, планирую добавить в него ещё несколько сущностей (таблиц) и адаптировать под свои нужды.
Изучаю проектирование баз данных.
Спасибо.

  Ответить  
 
 автор: confirm   (11.09.2014 в 04:20)   письмо автору
 
   для: davidoff_72   (11.09.2014 в 03:24)
 

А зачем готовить документ Word для изучения? На официальном сайте есть руководство РНР в формате CHM, русское, скачайте и пользуйтесь. В нем есть и оглавление, и поиск, и примеры, и с подсветкой кода. Уж во всяком случае намного удобнее простого тестового документа.

  Ответить  
 
 автор: davidoff_72   (11.09.2014 в 18:29)   письмо автору
 
   для: confirm   (11.09.2014 в 04:20)
 

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

  Ответить  
 
 автор: confirm   (11.09.2014 в 19:12)   письмо автору
 
   для: davidoff_72   (11.09.2014 в 18:29)
 

Для открытия файла CHM в windows уже все есть, иначе бы он вообще не открылся, а был бы запрос приложения.
Скорее всего он у вас заблокирован, поэтому и не видно содержания. Щелкните по нему правой кнопкой мышки, выберите Свойства, если во вкладке Общие будет предупреждение и кнопка Разблокировать, разблокируйте.

  Ответить  
 
 автор: davidoff_72   (11.09.2014 в 21:22)   письмо автору
 
   для: confirm   (11.09.2014 в 19:12)
 

Спасибо. Так и есть. Работает.

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования