2010-10-12 4 views
2

J'ai une table qui enregistre le nom des documents téléchargés, jusqu'à 14 par enregistrement. Les colonnes sont nommées ainsi:ColdFusion - Création dynamique de noms de colonnes avec CFLOOP

TABLE tblDocuments 
COLUMNS documentID (int, not null, pk) 
     document1 (varchar(250), null) 
     document2 (varchar(250), null) 
     /* and this continues through */ 
     document14 (varchar(250), null) 

Je requête pour tous les documents pour un enregistrement particulier:

<cfquery name="qryGetDocs" datasource="#dsn#"> 
    SELECT document1, ...document14 
    FROM tblDocuments 
    WHERE documentID = <cfqueryparam name="SESSION.documentID" cfsqltype="cf_sql_integer"> 
</cfquery> 

La forme ressemble à ceci:

<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> 

Je veux boucle de 1 à 14, de sorte que je n'ai qu'une seule instruction <input> et <cfif>, comme ceci:

<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> 

Cependant, je ne peux pas obtenir la syntaxe correcte, peu importe ce que j'ai essayé. Quelqu'un pourrait m'aider avec ça? Je vous remercie!

+3

Ceci est une structure peu maniable. Il est préférable de stocker les documents individuels sous forme de lignes et non de colonnes. Ensuite, il peut y avoir autant ou aussi peu que nécessaire. Les stocker comme 14 colonnes différentes sera difficile à chercher et à manipuler. – Leigh

+2

Je ne peux que seconder le commentaire de Leigh. Vous structure de table est tout faux. – Tomalak

Répondre

3

(La question initiale était déjà répondu Mais pour illustrer ...)

Une structure plus flexible consiste à stocker les documents sous forme de lignes. Donc, la table de base pourrait être:

TABLE: tblDocuments 
COLUMNS: DocumentID (unique record id) 
      UserID 
      DocumentName 

En utilisant cette structure, vous pouvez récupérer tous les documents existants pour un seul utilisateur avec une simple requête

<cfquery name="qryGetDocs" datasource="#dsn#"> 
    SELECT documentID, documentName 
    FROM tblDocuments 
    WHERE userID = <cfqueryparam name="#SomeUserIDVariable#" cfsqltype="cf_sql_integer"> 
</cfquery> 

.. et de les afficher avec une boucle de sortie simple. (Note, j'ajouté « documentID » comme champ caché pour identifier les documents existants ..)

<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> 

Si la requête contient moins de 14 fichiers (ou quel que soit votre maximum ..), vous pouvez utiliser le query.recordCount pour déterminer combien de entrées de fichiers supplémentaires à afficher.

<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

Les requêtes sont accessibles (comme les structures) avec un index de chaîne et des crochets, mais seulement si vous incluez également le numéro de ligne désiré (!). Cela fonctionne comme un tableau à deux dimensions.

<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> 

Notez le HTMLEditFormat() pour vous protéger contre les attaques de cross site scripting. Ceci est important! Ne jamais afficher des données au format HTML sans l'échapper correctement. (J'avoue que les noms de fichiers sont un vecteur d'attaque improbable car ils ne peuvent généralement pas contenir de parenthèses pointues, mais a) vous ne pouvez pas être trop prudent, b) c'est une bonne habitude, et c) personne ne sait pop-up lorsque le code est re-factorisé à un moment donné dans le futur. Les données non-escaping HTML est inexcusable laisser-aller)

A plus idiomatiques et version beaucoup plus lisible serait:..

<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> 
+0

Juste ne pas oublié d'ajouter le numéro de ligne à savoir #queryName ["colName"] [rowNumber] # – Leigh

+0

@Leigh: Oui, désolé posté trop tôt. Voir éditer. – Tomalak

+0

@Tomalak - Cool. Meilleure lisibilité aussi. – Leigh

Questions connexes