Bezdepbonusu7Программирование: статьи и ответы

Вопрос

ColdFusion - динамическое создание имен столбцов с помощью CFLOOP

Автор вопроса: BlondeMomentОтветов: 2

У меня есть таблица, в которой записано имя загруженных документов, до 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>

Однако я не могу получить правильный синтаксис, независимо от того, что я пробовал. Может кто-нибудь, пожалуйста, помогите мне с этим? Спасибо!

  • Это громоздкая структура. Отдельные документы лучше хранить в виде строк, а не столбцов. Тогда их может быть столько, сколько нужно. Хранение их в виде 14 разных столбцов будет затруднено для поиска и обработки. Leigh 13.10.2010
  • Я могу только поддержать комментарий Ли. Ваша структура таблицы неверна. Tomalak 13.10.2010

coldfusioncoldfusion-8

Ответы

Ответ 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>

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы