У меня есть таблица, в которой записано имя загруженных документов, до 14 на запись. Столбцы называются так:
TABLE tblDocuments
COLUMNS documentID (int, not null, pk)
document1 (varchar(250), null)
document2 (varchar(250), null)
/* and this continues through */
document14 (varchar(250), null)
Поэтому я запрашиваю любые документы для конкретной записи:
<cfquery name="qryGetDocs" datasource="#dsn#">
SELECT document1, ...document14
FROM tblDocuments
WHERE documentID = <cfqueryparam name="SESSION.documentID" cfsqltype="cf_sql_integer">
</cfquery>
Форма выглядит примерно так:
<form name="frmUploadDocs" method="post" action="documentsPage.cfm">
<input type="file" name="document1" size="50" >
<cfif qryGetDocs.document1 IS NOT ''>
(current file name: <a href="#vars.file_path#/#qryGetDocs.document1#">#qryGetDocs.document1#</a>)</cfif>
<input type="file" name="document2" size="50" >
<cfif qryGetDocs.document2 IS NOT ''>
(current file name: <a href="#vars.file_path#/#qryGetDocs.document2#">#qryGetDocs.document2#</a>)</cfif>
<!--- list all documents --->
<input type="file" name="document14" size="50" >
<cfif qryGetDocs.document14 IS NOT ''>
(current file name: <a href="#vars.file_path#/#qryGetDocs.document14#">#qryGetDocs.document14#</a>)</cfif>
<input type="submit" name="submit" value="Upload Documents">
</form>
Я хочу выполнить цикл от 1 до 14, чтобы у меня был только один оператор <input> и <cfif>, например:
<cfloop from="1" to="14" index="i">
<input type="fiile" name="document#i#" size="30">
<cfif qryGetDocs.document#i# IS NOT ''>
(current file name: <a href="#vars.file_path#/#qryGetDocs.document[#i#]#">#qryGetDocs.document[#i#]#</a>)
</cfif>
</cfloop>
Однако я не могу получить правильный синтаксис, независимо от того, что я пробовал. Может кто-нибудь, пожалуйста, помогите мне с этим? Спасибо!
Ответ 1 · рейтинг 3 · Leigh
(На исходный вопрос уже был дан ответ. Но просто для иллюстрации...)
Более гибкая структура - хранить документы в виде строк. Таким образом, основная таблица может быть:
TABLE: tblDocuments
COLUMNS: DocumentID (unique record id)
UserID
DocumentName
Используя эту структуру, вы можете получить все существующие документы для одного пользователя с помощью простого запроса.
<cfquery name="qryGetDocs" datasource="#dsn#">
SELECT documentID, documentName
FROM tblDocuments
WHERE userID = <cfqueryparam name="#SomeUserIDVariable#" cfsqltype="cf_sql_integer">
</cfquery>
.. и отображать их с помощью простого цикла вывода. (Обратите внимание, я добавил "ID документа" в качестве скрытого поля для идентификации существующих документов..)
<cfoutput query="qryGetDocs">
...
<input type="file" name="document#CurrentRow#" size="50" >
<input type="hidden" name="documentID#CurrentRow#" value="#documentID#" >
(current file name: <a href="#vars.file_path#/#documentName#">#documentName#</a>)
</cfoutput>
Если запрос содержит менее 14 файлов (или любое другое максимальное значение), вы можете использовать query.recordCount, чтобы определить, сколько дополнительных входных файлов нужно отобразить.
<cfset nextInputNumber = qryGetDocs.recordCount + 1>
<cfoutput>
<cfloop from="#nextInputNumber#" to="#MaximumNumberOfDocs#" index="counter">
<input type="file" name="document#counter#" size="50" >
<input type="hidden" name="documentID#counter#" value="0" >
</cfloop>
</cfoutput>
Ответ 2 · рейтинг 2 · Tomalak
Доступ к запросам (как и к структурам) можно получить с помощью строкового индекса и квадратных скобок, но только если вы также включите нужный номер строки (!). Это работает как двумерный массив.
<cfloop from="1" to="14" index="i">
<input type="file" name="document#i#" size="30">
<cfif qryGetDocs["document#i#"][qryGetDocs.CurrentRow] IS NOT ''>
(current file name: <a href="HTMLEditFormat("#vars.file_path#/#qryGetDocs["document#i#"][qryGetDocs.CurrentRow]#")#">#HTMLEditFormat(qryGetDocs["document#i#"][qryGetDocs.CurrentRow])#</a>)
</cfif>
</cfloop>
Обратите внимание на HTMLEditFormat(), чтобы защитить себя от атак межсайтового скриптинга. Это важно! Никогда не выводите данные в HTML без надлежащего экранирования. (Я признаю, что имена файлов являются маловероятным вектором атаки, потому что они обычно не могут содержать заостренные скобки, но а) нельзя быть слишком осторожным, б) это хорошая привычка, и в) никто не знает, что такое безопасность дыры всплывут, когда код будет рефакторинг в какой-то момент в будущем. Не экранирование HTML-данных - непростительная небрежность.)
Более идиоматичной и гораздо более читаемой версией будет:
<cfloop from="1" to="14" index="i">
<cfset RowNum = qryGetDocs.CurrentRow>
<cfset ColName = "document#i#">
<cfset DocName = qryGetDocs[ColName][RowNum]>
<cfset DocPath = "#vars.file_path#/#DocName#">
<input type="file" name="#ColName#" size="30">
<cfif FileExists(ExpandPath(DocPath))>
(current file name: <a href="#HTMLEditFormat(DocPath)#">#HTMLEditFormat(DocName)#</a>)
</cfif>
</cfloop>