[luci] Please help with validating unique vlaues

Jo-Philipp Wich xm at subsignal.org
Wed Feb 24 09:00:49 CET 2010


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi Chris.

Now it's getting a bit hairy :)

First a few words on the program flow:

When a CBI map is rendered after a form submit, the associated
controller calls m:parse() which triggers form value fetching and
validation across all sections within the map, each section in turn does
validation on each fields within it.

If one of the field validation functions fail, the whole map is flagged
invalid by setting .save = false on the map object.

When a validation error occurs on a per-field or per-section level, the
associated error handling sets the property .error to a table value to
flag the error condition in a specific field (or section) - this is used
by the templates later on to highlight failed options (for example make
them red and print an error text next to it).

The error structure looks like this:

.error = {
   [section_id_1] = "Error message string",
   [section_id_2] = "Another error message"
}


The format is the same for per-section and per-option errors. The
variables section_id_1 and section_id_2 are the uci identifiers of the
underlying section e.g. "lan" for "config interface lan" and
"cfg12ab23f" for "config foo" (anonymous section).

To complicate it further, sections of the type TypedSection are not 1:1
mapped to the CBI model, one TypeSection declaration may result in
multiple actual section blocks rendered in the form so you need to treat
it correctly when traversing the map->sections->options tree.



With that in mind, you can hijack the Map's .parse function to implement
some kind of global validation:


local utl = require "luci.util"

m = Map("config", ...)

function m.parse(self, ...)   -- NB: "..." actually means ellipsis here
	-- call the original parse implementation
	Map.parse(self, ...)

	-- do custom processing
	local sobj
	for _, sobj in ipairs(self.children) do
		local sids

		-- check section type
		if utl.instanceof(sobj, NamedSection) then
			-- this is a named section,
			-- the uci id of this section is
			-- stored in sobj.section
			sids = { sobj.section }
		elseif utl.instanceof(sobj, TypedSection) then
			-- this is a typed section,
			-- it may map to multiple uci ids
			sids = sobj:cfgsections()
		end

		-- now validate the fields within this section
		-- for each associated config section
		local sid, fld

		for _, sid in ipairs(sids) do
			for _, fld in ipairs(sobj.children) do
				-- get the value for a specific field in
				-- a specific section
				local val = fld:formvalue(sid)

				-- do some custom checks on val,
				-- e.g. compare against :cfgvalue(),
				-- some global structure etc.
				if not is_valid(val, other_stuff) then
					-- failed, flag map (self == m)
					self.save = false

					-- create field error for
					-- template highlight
					fld.error = {
						[sid] = "Error foobar"
					}
				end
			end
		end
	end
end



~ JoW
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkuE3LEACgkQdputYINPTPOK0wCaAyJaSl8EbzH5kfnx/hz/KRCj
ZcgAn2hXEAka/Cl/9TuNZqeY39abdJZ5
=prtZ
-----END PGP SIGNATURE-----


More information about the luci mailing list