Tutorial Pasukan Lucee MY

Ubah produk dan arkib tanpa memadam data

Bina halaman ubah produk dengan URL parameter yang selamat, UPDATE yang tepat, dan arkib lembut supaya sejarah jualan tidak hilang daripada laporan bulanan.

Ubah produk dan arkib tanpa memadam data
0
Kandungan

Ubah produk dan arkib tanpa memadam data

Produk akan berubah. Harga naik, ejaan nama salah, atau barang tidak lagi dijual. Aplikasi yang hanya boleh menambah data akan menyimpan kesilapan itu selamanya.

Bab ini menambah dua keupayaan: mengubah produk, dan menyembunyikannya tanpa memadam rekod.

Mengapa bukan butang padam

Butang padam kelihatan mudah, tetapi ia mencipta masalah yang tidak kelihatan pada mulanya.

Apabila anda memadam satu produk, semua rujukan kepadanya hilang. Laporan bulan lalu tidak lagi boleh dikira. Rekod jualan yang menyebut produk itu menjadi yatim. Dan jika pelanggan bertanya tentang pesanan lama, tiada apa yang tinggal untuk ditunjukkan.

Arkib menyelesaikan masalah ini. Produk disembunyikan daripada senarai harian, tetapi rekodnya kekal untuk laporan dan sejarah.

KeperluanPadamArkib
Sembunyi daripada senaraiYaYa
Kekal dalam laporan lamaTidakYa
Boleh dipulihkanTidakYa
Selamat untuk rekod jualanTidakYa

Kita menggunakan satu lajur baharu, is_active, yang bernilai 1 untuk produk aktif dan 0 untuk yang diarkibkan. Lajur ini ditambah pada jadual yang anda bina dalam bab pangkalan data. Senarai utama hanya memaparkan baris dengan is_active = 1.

Tambah lajur arkib

Buka phpMyAdmin, pilih pangkalan data inventori, dan jalankan arahan ini pada tab SQL:

ALTER TABLE produk
ADD COLUMN is_active TINYINT(1) NOT NULL DEFAULT 1 AFTER stok;

Nilai lalai 1 bermakna semua produk sedia ada terus aktif. Tiada data hilang.

Mengapa kita menghantar id, bukan nama

Anda mungkin tertanya mengapa URL menggunakan ?id=3 dan bukan ?nama=Gula%201kg.

Sebabnya, nama boleh berubah dan boleh berulang. Dua produk boleh mempunyai nama yang sama dalam kategori berbeza, dan nama yang mengandungi ruang perlu dikodkan dalam URL, yang menyukarkan pembacaan.

Nombor id tidak berubah selepas baris dicipta. Ia ringkas, unik, dan mudah disahkan sebagai nombor bulat. Apabila aplikasi ini membesar, setiap pautan ke satu rekod akan menggunakan id, bukan teks.

Ini juga sebabnya kita tidak membenarkan SKU diubah dalam borang: ia berfungsi sebagai pengenal kedua yang dibaca manusia, dan menukarnya akan memutuskan rujukan dalam rekod lain.

Halaman ubah menerima nombor dari URL

Halaman ubah perlu tahu produk mana yang hendak diubah. Kita menghantarnya melalui URL, contohnya produk-ubah.cfm?id=3.

Nilai itu datang daripada orang luar, jadi ia tidak boleh dipercayai. Kita menggunakan val() untuk menukarnya kepada nombor bulat:

<cfparam name="url.id" default="0">
<cfset idProduk = val(url.id)>

val() membuang semua yang bukan nombor. Kalau seseorang menaip id=3 OR 1=1, nilai itu menjadi 3, dan cubaan suntikan itu mati sebelum sampai ke pangkalan data.

Selepas itu, kita membaca rekod:

<cfquery name="produk" datasource="inventori">
    SELECT id, sku, nama, harga, stok, is_active
    FROM produk
    WHERE id = <cfqueryparam value="#idProduk#" cfsqltype="cf_sql_integer">
</cfquery>

Borang ubah dengan nilai sedia ada dan pilihan arkib

Hasil sebenar pada rig ujian kami: SKU dipaparkan, harga diformat 3.20, dan kotak arkib di bawah.

Kalau produk.recordCount ialah sifar, kita memaparkan mesej "Produk tidak dijumpai" dan bukannya borang kosong. Ini mengelakkan pengguna daripada mengisi borang yang tidak akan menyimpan apa-apa.

Borang yang mengingati dirinya

Fail produk-ubah.cfm menggunakan corak yang sama seperti borang tambah dalam bab sebelumnya, dengan dua perbezaan.

Pertama, nilai awal diambil daripada rekod sedia ada, bukan kosong:

<cfset nilai = { sku: produk.sku, nama: produk.nama, harga: numberFormat(produk.harga, "0.00"), stok: produk.stok }>

Kedua, alamat borang membawa id produk:

<form method="post" action="produk-ubah.cfm?id=#produk.id#" class="borang">

Ini penting. Apabila pengesahan gagal dan borang dipaparkan semula, id itu masih ada dalam URL, jadi halaman masih tahu produk mana yang sedang diubah.

UPDATE yang tidak merosakkan semua baris

Inilah peraturan paling berbahaya dalam SQL: UPDATE tanpa WHERE mengubah setiap baris dalam jadual.

<cfquery datasource="inventori">
    UPDATE produk
    SET nama = <cfqueryparam value="#nilai.nama#" cfsqltype="cf_sql_varchar">,
        harga = <cfqueryparam value="#nilai.harga#" cfsqltype="cf_sql_decimal" scale="2">
    WHERE id = <cfqueryparam value="#produk.id#" cfsqltype="cf_sql_integer">
</cfquery>

Perhatikan dua perkara. Setiap nilai melalui <cfqueryparam>, dan WHERE menggunakan id yang dibaca daripada pangkalan data, bukan daripada URL.

Menggunakan produk.id dan bukan url.id bermakna nilai itu sudah disahkan wujud. Ia tidak boleh diubah oleh pengguna selepas halaman dimuatkan.

Sebelum menulis sebarang UPDATE, biasakan bertanya: baris mana yang saya mahu ubah, dan bagaimana saya memastikan hanya baris itu? Kalau jawapannya tidak jelas, jangan jalankan query itu.

Halaman arkib

Fail produk-arkib.cfm hanya melakukan satu perkara: menetapkan is_active = 0 pada satu id.

<cfparam name="form.id" default="0">
<cfset idProduk = val(form.id)>

<cfquery datasource="inventori">
    UPDATE produk
    SET is_active = 0
    WHERE id = <cfqueryparam value="#idProduk#" cfsqltype="cf_sql_integer">
</cfquery>

<cflocation url="index.cfm?berjaya=arkib" addtoken="false">

Ia menerima id melalui borang, bukan URL. Sebabnya, mengarkibkan produk mengubah data, dan perubahan data mesti melalui POST.

Menapis senarai

Senarai utama kini menambah satu baris:

WHERE is_active = 1

Itu sahaja. Tiada perubahan lain diperlukan, kerana semua halaman lain membaca jadual yang sama.

Lajur tindakan ditambah pada jadual yang anda bina dalam bab header dan jadual, dengan pautan ke halaman ubah:

<td><a href="produk-ubah.cfm?id=#id#">Ubah</a></td>

Perhatikan bahawa id kini perlu dipilih dalam query senarai. Sebelum ini kita hanya mengambil sku, nama, harga dan stok.

Pepijat yang berulang

Semasa membina halaman ini, saya sekali lagi terlupa membalut satu baris dengan <cfoutput>:

SKU #encodeForHTML(produk.sku)#

Hasilnya, pengguna nampak kod itu sebagai teks. Ini kali kedua dalam siri ini, dan ia mengajar satu perkara: apabila anda melihat tanda # pada halaman, semak sama ada ia berada di dalam <cfoutput>.

Satu lagi butiran kecil: harga dipaparkan sebagai 3.2 dan bukan 3.20. Nilai dalam pangkalan data betul, tetapi paparannya tidak. numberFormat(produk.harga, "0.00") menyelesaikannya, dan pengguna melihat harga yang biasa dilihat dalam kedai.

Ralat lazim

Semua produk berubah harga selepas satu suntingan. WHERE tiada dalam UPDATE. Semak semula query itu serta-merta.

Produk tidak dijumpai walaupun ia ada. Biasanya id dalam URL tidak sepadan dengan id dalam pangkalan data, atau val() menerima nilai kosong.

Borang kosong selepas ralat pengesahan. Nilai awal diambil daripada form, dan blok pengesahan menetapkan semula nilai sebelum memaparkan borang.

Produk yang diarkibkan masih muncul. Query senarai belum ditambah WHERE is_active = 1.

Ralat kekangan unik apabila menukar SKU. Kita tidak membenarkan SKU diubah dalam borang ini, kerana ia mengenal pasti produk. Kalau anda perlu menukarnya, tambah semakan pendua terlebih dahulu.

Apa yang anda sudah ada

Aplikasi anda kini boleh menambah, mengubah dan mengarkibkan produk, dengan pertahanan suntikan SQL di setiap query. Corak cfqueryparam ini sama seperti yang anda pelajari dalam bab nilai dan keputusan, tetapi kini ia digunakan pada data yang benar-benar datang daripada orang lain.

Tetapi sesiapa sahaja yang tahu alamat produk-ubah.cfm boleh mengubah harga. Bab seterusnya menambah log masuk, supaya hanya orang yang dibenarkan boleh membuat perubahan.

Soalan Lazim

Boleh saya memulihkan produk yang diarkibkan? Boleh. Ia hanya satu UPDATE yang menetapkan is_active = 1. Kita tidak menambah butang itu kerana arkib sepatutnya jarang, tetapi keupayaannya sedia ada.

Kenapa SKU tidak boleh diubah? Kerana ia mengenal pasti produk dalam rekod lain dan dalam fail eksport. Menukarnya boleh memutuskan rujukan. Nama dan harga selamat diubah.

Adakah val() mencukupi untuk semua jenis input? Tidak. Ia hanya sesuai untuk nilai berangka. Untuk teks, gunakan <cfqueryparam>, dan untuk output, gunakan encodeForHTML.

Boleh saya gunakan DELETE untuk data ujian? Boleh, semasa di komputer sendiri. Tetapi biasakan arkib dari awal, kerana tabiat itu yang akan anda bawa ke pelayan sebenar.

Bagaimana kalau dua orang mengubah produk yang sama serentak? Orang terakhir yang menyimpan akan menang. Untuk kedai kecil itu boleh diterima. Kita akan bincangkan kawalan serentak apabila mula menyentuh stok.

Sumber

Log masuk untuk menyimpan kemajuan bacaan anda.

0 komen

0 komen

Log masuk untuk menjawab atau memberi komen.

Log masuk