GeoMOOSE Feature Editor
====================================
To setup a table for editing in GeoMOOSE it requires thinking about the layer for editing ahead of time.  First, the layer needs to be stored in a PostGIS database.  Others may be supported in the future.  Shapefiles are not editable as they cannot be properly shared amongst multiple users.  Second, the layer in PostGIS needs to have a primary key, a sequence for generating keys, and have a proper entry in the geometry_columns table.  Layers coming from OGR will have all of these requirements met.  Finally, the layer must be configured for the editor by creating an “ini” for the editor script, adding the proper service entries to the mapbook, and finally configuring a proper identify record template.

Setting up the Table Properly for Editing
-----------------------------------------
All editing tables require having a primary key in the table, a sequence that works as the iterator for that primary key, and a geometry column.  The SQL to create an example would be as follows:

To create the table, the CONSTRAINT .. PRIMARY KEY directive specifies the primary key for the table::

	CREATE TABLE test_polygons
	(
	  polygon_id integer NOT NULL,
	  title character varying(100),
	  owner character varying(100),
	  wkb_geometry geometry,
	  CONSTRAINT pk_test_polygons PRIMARY KEY (polygon_id)
	)

.. toctree::
   :maxdepth: 2

To create the sequence::

	CREATE SEQUENCE test_polygons_seq;

Add the table to the register of geometry_columns, this may vary depending on your dataset, but for the purposes of the example this is what was used::

	insert into geometry_columns values ('', 'public', 'test_polygons', 'wkb_geometry', 2, -1, 'GEOMETRY');

Create a Mapfile for the Table
------------------------------

There is only one quick to creating a mapfile for a layer to be edited, it is necessary to add a well-known text geometry column.  This is used to feed back the shape of the feature to the interface.  There are two files we need to create for each table, a mapfile and a .ini file.  I highly suggest keeping these named the same as the table to prevent confusion.  In this case the file name would be “test_polygons.map”.  To keep things segregated each table should be put into it's own folder.  I created a “test_polygons” directory and then wrote “test_polygons.map” and “identify.html” (see details below) in the “test_polygons” directory. The mapfile::

	MAP
		SIZE 400 400
		EXTENT  427632.500000 4893613.330000 560300.922104 5015936.680000
		UNITS METERS
		SYMBOLSET '../symbols/symbol.sym'
		STATUS ON

		TRANSPARENT TRUE

		LAYER
			NAME 'polygons'
			TYPE POLYGON
			STATUS ON

			CONNECTIONTYPE POSTGIS
			CONNECTION 'host=192.168.52.1 dbname=geomoose_test user=postgres password=postgres22'
			DATA 'wkb_geometry from (select polygon_id, title, owner, astext(wkb_geometry) as wkt_geometry, wkb_geometry from test_polygons) as mytable using unique feature_id'

			CLASS
				STYLE
					SYMBOL 'circle'
					OUTLINECOLOR 255 255 0
					SIZE 10
				END
			END

			METADATA
				'identify_record' 'identify.html'
			END
		END
	END

Add the Layer to the Interface
------------------------------

The first step is to create mapservice that points to the test_polygons mapfile::

        <map-service path="editor" type="mapserver">
                <file>/var/www/geomoose2/maps/test_polygon/test_polygon.map</file>
                <layer name="polygons"/>
        </map-service>

Then add an entry to the catalog (the bold text was added to a pre-existing group)::

	<group title="Editing Layers" expand="true">
		<layer title="Points" path="editor/points"/>
		<layer title="Polygons" path="editor/polygons"/>
	</group>

Verify the layer is displaying properly in the mapping interface before continuing.

Setting up the .INI file
------------------------

The .INI file is how the editor script knows about your table.  It is where all the vital information for your table is stored for editing.  All of the files are stored in “conf/editor”.  To continue with the example from earlier I created a “test_polygons.ini” file.  Since each table has a separate host/dbname configuration it is possible for a single GeoMOOSE interface to edit tables on multiple different servers  without the user knowing the difference.

Example INI file::

	; Basic Connection Information
	host=192.168.52.1
	dbname=geomoose_test
	username=postgres
	password=postgres22

	; Table Information
	tablename=test_polygons				; Database table name
	geometry_column=wkb_geometry			; Column name from the CREATE TABLE SQL
	primary_key_column=polygon_id			; Primary Key Column from CREATE TABLE
	primary_key_sequence=test_polygons_seq		; Sequence name from CREATE SEQUENCE

	; GeoMOOSE Information
	layerpath=editor/polygons			; The full path in GeoMOOSE (same as catalog)

Setting up a Create/Add Service
-------------------------------

This is arguably the most difficult part of setting up the service as it requires the most amount of knowledge on how GeoMOOSE services are configured.  But all tables should follow roughly the same pattern.  All of the columns in the table are referred to as “feature:[COLUMN NAME]” so if the table as a column named “owner” it is referenced as “feature:owner” for the name to be used with the editor script.

The service definition starts simple with the header::
<service name=”add_polygon”>

And add a reference to the editor url::

	<url>php/editor.php</url>

Now, we need a step to tell GeoMOOSE to draw a polygon::

	<step type='spatial' name='feature:wkb_geometry' line='false' polygon='true' point='false' default='polygon'>
	</step>

You can see, above, that the “name” references the name of the geometry column.  We also turn off all of the tools except the polygon drawing tool by specifying “false” values for the “line” and “polygon” attributes.  This would change depending on the dataset (as some datasets are points and others lines).  The “default” attribute tells GeoMOOSE to start this step using the “polygon” tool instead of Navigation or other tools.

Then there is a required step to describe which operation we're performing and the attributes that will be edited::

	<step type="input"> <!-- This tells GeoMOOSE there will be user input -->
		<input type="hidden" name="op" value="create"/>
		<!-- The “op” variable tells the editor which operation to perform: create, update, or delete -->
		<input type="hidden" name="table" value="test_polygons"/>
		<!-- The “table” refers to the name of the “ini” file.  -->
		<input type="user" name="feature:title" title="Title:"/>
		<input type="user" name="feature:owner" title="Owner:"/>
		<!-- These previous two lines refer to columns in the table. -->
	</step>

Putting it all together::

        <service name="add_polygon">
                <url>php/editor.php</url>
                <step type='spatial' name='feature:wkb_geometry' line='false' polygon='true' point='false' default='polygon'>
                </step>
                <step type="input">
                        <input type="hidden" name="op" value="create"/>
                        <input type="hidden" name="table" value="test_polygons"/>
                        <input type="user" name="feature:title" title="Title:"/>
                        <input type="user" name="feature:owner" title="Owner:"/>
                </step>
        </service>

Finally, the service needs to be added to the toolbar::

	<toolbar>
		...
		<tool name=”add_polygon” title=”Add Polygon” type=”service” service=”add_polygon”/>
		...
	</toolbar>

It's usually nice to add some CSS to decorate up the Polygon Tool, so something like this might be prudent in htdocs/css/user_tools.css::

	#tool-add_polygon {
		background-image: url('../images/toolbar/add.png');
		background-position: 2 2;
		background-repeat: no-repeat;
		padding-left: 2px;
	}

	#tool-add_polygon .ToolText {
		padding: 2px;
		display: block;
		width: auto;
	}

	#tool-add_polygon .ToolContent {
		width: auto;
	}

Creating the Update Service
---------------------------

While it is nice to create features, it may be possible to actually edit those features.   Updating requires setting up a similar service to creating.

The entry for the update will look like this::

        <service name="modify_polygon">
                <url>php/editor.php</url>
                <step type='spatial' name='feature:wkb_geometry' line='false' polygon='true' point='false' default='point' edit-polygon='true'> <!-- It's necessary to specify that the polygon editor be turned on, the rest of the options are CREATION functions -->
                        <input type="hidden" name="op" value="update"/>
			<!-- This just changes the option to 'update' instead of 'create' -->
                        <input type="hidden" name="table" value="test_polygons"/>
                        <input type="hidden" name="feature:polygon_id"/>
                        <input type="user" name="feature:title" title="Title:"/>
                        <input type="user" name="feature:owner" title="Owner:"/>
                </step>
        </service>

Creating the Delete Service
---------------------------

This is the easiest service to create as there are no user inputs or spatial steps to define::

        <service name="delete_polygon">
                <url>php/editor.php</url>
                <step type='input'>
                        <input type="hidden" name="op" value="delete"/>
		This just needs to be changed to “delete”
                        <input type="hidden" name="table" value="test_polygons"/>
                        <input type="hidden" name="feature:polygon_id"/>
                </step>
        </service>

Create the Identfy.html File
----------------------------

Now we'll try to get the layer properly identifying in the interface.

identify.html::

	<tr bgcolor="#AA55AA">
		<td colspan="2"><b>[title] ([polygon_id])</b></td>
	</tr>
	<tr>
		<td>Owner:</td><td>[owner]</td>
	</tr>
	<tr>
	<td>
		<a href="javascript:GeoMOOSE.startService('modify_polygon', {'feature:polygon_id' : '[polygon_id]','feature:wkb_geometry' : '[wkt_geometry]', 'feature:title' : '[title]', 'feature:owner' : '[owner]'})">Edit</a>
	</td>
	<td>
		<a href="javascript:if(confirm('Are you sure you want to delete this?')) { GeoMOOSE.startService('delete_polygon', {'feature:polygon_id' : '[polygon_id]'}); }">Delete</a>
	</td>
	</tr>

The key to the editing functionality is in the <a href=”javascript...”> links.  These links are calling the editing service definitions with the values “filled in” for the selected object form the identify request.  Every dataset requires changing this list to reflect the attributes of the specific dataset.
