/[cvs]/nfo/php/libs/com.newsblob.phphtmllib/form/FormProcessor.inc
ViewVC logotype

Annotation of /nfo/php/libs/com.newsblob.phphtmllib/form/FormProcessor.inc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.5 - (hide annotations)
Thu Aug 11 14:09:26 2005 UTC (18 years, 11 months ago) by jonen
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +86 -70 lines
+ updated to version 2.5.3

1 jonen 1.1 <?php
2     /**
3     * This file contains the FormProcessor class.
4     *
5 jonen 1.5 * $Id: FormProcessor.inc,v 1.47.2.3 2005/05/12 01:24:02 hemna Exp $
6 jonen 1.1 *
7 jonen 1.5 * @author Walter A. Boring IV <waboring@newsblob.com>
8 jonen 1.1 * @author Suren Markossian <suren@cbestwhat?>
9     * @package phpHtmlLib
10     * @subpackage FormProcessing
11     *
12     * @copyright LGPL - See LICENCE
13     *
14     */
15    
16 jonen 1.3 define("FORM_ACTION", "_form_action");
17     define("FORM_VISITED", "_form_visited");
18     define("FORM_CONFIRM", "_form_confirm");
19 jonen 1.1
20     /**
21     * This is the main engine for the processing
22     * of Forms. It builds the form tag, and calls
23     * the appropriate FormContent methods to build
24 jonen 1.5 * the FormElement's and validation, as well as
25 jonen 1.1 * backend processing to do the action after the
26     * data has been validated.
27     *
28     * @package phpHtmlLib
29     * @subpackage FormProcessing
30     */
31     class FormProcessor extends Container {
32    
33    
34     /**
35 jonen 1.3 * This array holds the FORMtag
36     * attributes for this form
37 jonen 1.1 *
38     */
39 jonen 1.3 var $_form_attributes = array("method" => "post",
40     "action" => "",
41     "name" => "myform",
42     "target" => "",
43     "onsubmit" => "",
44     "style" => "margin: 0px 0px 0px 0px;");
45 jonen 1.1
46     /**
47     * This holds the FormContent Object
48     * that knows how to render the
49     * form.
50     */
51     var $_form_content = NULL;
52    
53    
54     /**
55     * This flag lets us know there
56     * were errors during processing or
57     * validating the form.
58     */
59     var $_has_errors = FALSE;
60    
61     /**
62     * Flag to let us know the form
63     * has been confirmed.
64     */
65     var $_confirmed = FALSE;
66    
67     /**
68     * Flag to let us know if we should
69     * render the form after it was
70     * successfully processed
71     */
72     var $_form_success_render = TRUE;
73    
74 jonen 1.3 /**
75     * This is the FormValidation object
76     * used to validate the form elements
77     */
78     var $_FormValidation = NULL;
79    
80     /**
81     * The action that was taken
82     * for the form
83     */
84     var $_form_submit_action = NULL;
85    
86     /**
87     * The form was processed and passed
88 jonen 1.5 * the confirmation if any, and
89 jonen 1.3 * it was successfull ?
90     */
91     var $_confirmed_successfull = FALSE;
92    
93     /**
94     * This tells us to show or not to
95     * show the form errors autmatically.
96     * The user of the FormProcessor
97     * may want to deal with errors manually
98     */
99     var $_auto_show_errors = TRUE;
100    
101 jonen 1.1
102     /**
103     * The constructor for the FormProcessor
104     *
105     * @param FormContent object
106     * @param string the form name
107     */
108 jonen 1.3 function FormProcessor(&$form_content, $form_name="myform",
109 jonen 1.1 $form_action=NULL) {
110    
111     $this->_form_content = &$form_content;
112 jonen 1.3 $this->set_form_name( $form_name );
113 jonen 1.1 $this->_form_content->set_form_name($form_name);
114    
115     if ($form_action != NULL) {
116 jonen 1.3 $this->set_form_action( $form_action );
117 jonen 1.1 } else {
118 jonen 1.3 $this->set_form_action( $_SERVER["PHP_SELF"] );
119 jonen 1.1 }
120    
121 jonen 1.3 //Set up the Validation object
122     //and the FormErrors object to
123     //be used by this form.
124     $this->setup_validation();
125    
126     //now process the form
127     $this->_process_form();
128 jonen 1.1 }
129    
130     /**
131 jonen 1.3 * This function is used to setup
132     * the validation object and the
133     * form errors object that is to be
134     * used by this form.
135     *
136 jonen 1.5 * You can override this method to
137 jonen 1.3 * use a different FormErrors object
138     * for localization.
139     */
140 jonen 1.5 function setup_validation() {
141     $this->_FormValidation =& FormValidation::singleton();
142     $this->_form_content->_set_validation_object($this->_FormValidation);
143     }
144 jonen 1.3
145     /**
146 jonen 1.1 * This method does the logic of
147     * doing the form processing
148     */
149     function _process_form() {
150 jonen 1.4 $this->_init_form_content();
151 jonen 1.1
152     //we only need to process the form
153     //if it has been visited. Otherwise
154     //it just gets rendered.
155 jonen 1.5 if (!empty($_REQUEST[$this->_form_attributes['name'].FORM_VISITED]) &&
156     $_REQUEST[$this->_form_attributes['name'].FORM_VISITED] == 1) {
157 jonen 1.3 $this->_set_action();
158 jonen 1.1
159     //let see if this was a confirmation page.
160 jonen 1.4 if ( !empty($_REQUEST[FORM_CONFIRM]) ) {
161     if ($_REQUEST[FORM_CONFIRM] == 1) {
162     //looks like this was a submit on a
163     //confirmation page. we don't need
164     //to do form field validation.
165     $this->_confirmed = TRUE;
166     } else {
167     //looks like the confirmation was aborted.
168     xxx("aborted");
169     }
170 jonen 1.1 }
171    
172 jonen 1.5 if ($this->_form_content->has_confirm()) {
173     //the form content has a confirmation
174     //we need to process
175     $this->_has_errors = !$this->_pre_confirm();
176     }
177    
178     //we haven't been confirmed, so we
179     //need to validate the form.
180     if ($this->can_validate()) {
181     //looks like we should do validation
182     $this->do_validation();
183     }
184     if (!$this->_has_errors) {
185     //no errors were found
186 jonen 1.1 //make sure we don't have any backend errors
187     $this->_has_errors = !$this->_form_content->form_backend_validation();
188 jonen 1.5 if (!$this->_has_errors && (($this->_form_content->has_confirm()
189     && $this->_confirmed) || !$this->_form_content->has_confirm())) {
190     // process action only at the final stage
191 jonen 1.1 $this->_has_errors = !$this->_process_action();
192 jonen 1.5
193 jonen 1.3 if (!$this->_has_errors) {
194     $this->_set_confirmed_success(TRUE);
195     }
196 jonen 1.5 }
197 jonen 1.1 }
198     }
199     }
200    
201    
202     /**
203     * This function is responsible for
204     * processing the form action
205     * after validation, and form confirmation
206     * happens.
207     *
208     */
209     function _process_action() {
210     //There were no validation errors.
211     return $this->_form_content->form_action();
212     }
213    
214     /**
215 jonen 1.5 * This method calls the FormContent
216 jonen 1.1 * to let it do any data munging before the
217     * confirmation page is rendered
218     */
219     function _pre_confirm() {
220 jonen 1.4
221     if ($this->_form_content->_has_file_element) {
222     //we need to allow any/all of the file elements
223     //save the temp files during a confirmation.
224 jonen 1.5 //if we don't, then the web server may delete
225 jonen 1.4 //them before confirmation has been accepted.
226     $this->_form_content->_pre_confirm();
227     }
228    
229     //call the user defineable FormContent pre_confirm.
230 jonen 1.1 return $this->_form_content->pre_confirm();
231     }
232    
233    
234     /**
235     * This method walks the FormContent's visible elements
236     * and calls the validation function for the element
237     *
238     */
239     function do_validation() {
240     $keys = array_keys( $this->_form_content->_elements );
241     foreach( $keys as $key ) {
242 jonen 1.5 if (!$this->_form_content->_elements[$key]->is_disabled()) {
243     $valid = $this->_form_content->_elements[$key]->_do_validation($this->_FormValidation);
244     if (!$valid) {
245     $this->_has_errors = TRUE;
246     }
247     } else {
248     //detect disabled field hack attempts
249     if ($this->_form_content->_elements[$key]->has_error()) {
250     $this->_has_errors = TRUE;
251     }
252 jonen 1.1 }
253     }
254     }
255    
256    
257     /**
258     * This method is called to render the form's html
259     *
260     */
261     function render($indent_level=0, $output_debug=0) {
262     if ($this->_has_errors) {
263     //we need to render the form errors
264     //and then the form
265     return $this->render_error($indent_level, $output_debug);
266     } else {
267     //there are no errors!
268 jonen 1.5 if (@$_REQUEST[$this->_form_attributes['name'] . FORM_VISITED] == 1) {
269 jonen 1.1 //looks like the form has been processed?
270     if ($this->_form_content->has_confirm() && !$this->_confirmed) {
271     return $this->render_confirm($indent_level, $output_debug);
272     } else {
273     //Looks like the action worked
274 jonen 1.3 $success = $this->_form_content->form_success();
275 jonen 1.5
276 jonen 1.1 if ($this->_form_success_render) {
277     return $this->render_form($indent_level, $output_debug,
278     $success);
279     } else {
280     if (method_exists($success,"render")) {
281     //looks like this is an object.
282     //we'll assume it has a render function.
283     return $success->render($indent_level, $output_debug);
284     } else {
285     //since its not an object,
286     //lets just display it.
287     return $success;
288     }
289     }
290     }
291     } else {
292     return $this->render_form($indent_level, $output_debug);
293     }
294     }
295     }
296    
297    
298     /**
299     * This renders the form
300     *
301     * @param the FormContent->form() object
302     * @param int - $indent_level
303     * @param int - $output_debug
304     * @param object - the form errors object.
305     * @return raw html
306     */
307     function render_form( $indent_level, $output_debug, $obj=NULL ) {
308    
309     //build the $this->_form object.
310     $this->_build_form_tag();
311    
312 jonen 1.3 //check to see if the form_content
313     //has any js, or any of the form elements
314     //have js.
315     $form_js = $this->_build_javascript();
316     if (strlen($form_js) > 0) {
317     $script = html_script();
318     $script->add( $form_js );
319     //$this->_form->add( $script );
320     }
321    
322 jonen 1.1 if ($obj) {
323     $this->_form->add_reference( $obj );
324     }
325    
326     $this->_form->add_reference( $this->_form_content->form() );
327    
328     //add the FormContent's hidden declared
329     //hidden form fields.
330     $this->_add_hidden_fields();
331    
332     //Ok lets add our hidden vars
333     $this->__hidden_fields();
334    
335 jonen 1.3 if (isset($script)) {
336     $c = container( $script, $this->_form );
337     return $c->render($indent_level, $output_debug);
338     } else {
339     return $this->_form->render($indent_level, $output_debug);
340     }
341 jonen 1.5
342 jonen 1.1 }
343    
344     /**
345     * This function renders the confirmation
346     * page. This page sits in between the
347     * front end form, and the action handler.
348     * This only gets called after a form
349     * and its data has been successfully
350     * validated.
351     *
352     * @param int - $indent_level
353     * @param int - $output_debug
354     *
355     * @return string - the raw html
356     */
357     function render_confirm( $indent_level, $output_debug ) {
358     //build the $this->_form object.
359     $this->_build_form_tag();
360    
361     //add the confirm object/html
362 jonen 1.3 $confirm = &$this->_form_content->form_confirm( );
363 jonen 1.1 $this->_form->add_reference( $confirm );
364    
365     //ok add all of the submitted data as hidden form fields
366     $this->_add_confirm_data();
367    
368     //Ok lets add our hidden vars
369     $this->__hidden_fields();
370    
371     return $this->_form->render($indent_level, $output_debug);
372     }
373    
374    
375     /**
376     * This renders the error table
377     * and then the form with the fields
378     *
379     * @param array - the form field vlues.
380     * @param array - array of errors.
381     * @param int - $indent_level
382     * @param int - $output_debug
383     *
384     * @return raw html
385     */
386     function render_error( $indent_level, $output_debug) {
387 jonen 1.5
388 jonen 1.3 if ($this->_auto_show_errors) {
389     //Ok first lets build the error table
390     $wrapper = new DIVtag;
391     $errors = &$this->_form_content->form_errors();
392     if ($errors != NULL) $wrapper->add( $errors, html_br() );
393     } else {
394     $wrapper = NULL;
395     }
396 jonen 1.5
397 jonen 1.1
398 jonen 1.3 return $this->render_form( $indent_level, $output_debug, $wrapper);
399 jonen 1.1 }
400    
401    
402    
403    
404     //***********************************************//
405     //* utility functions for this class *//
406     //***********************************************//
407    
408    
409     /**
410     * This method lets us turn on/off the
411     * ability to do validation for the form
412     *
413     * @return BOOLEAN
414     */
415     function can_validate() {
416     return TRUE;
417     }
418    
419    
420     /**
421     * This function turns on the ability to
422     * render the form after the success
423     * of the action. Normally this feature
424     * is off
425     *
426     */
427 jonen 1.3 function set_render_form_after_success($flag=TRUE) {
428     $this->_form_success_render = $flag;
429     }
430    
431     /**
432     * This is used to test to see if the form action
433 jonen 1.5 * was processed succesfully.
434 jonen 1.3 * This is usefull for external entities to determine
435     * if the form was processed, and it was successfull.
436     *
437     * @return boolean
438     */
439     function is_action_successfull() {
440     return $this->_confirmed_successfull;
441     }
442    
443     /**
444     * This flag sets the flag that tells
445     * if we successfully confirmed the form,
446     * and processed the action
447     *
448     * @param boolean
449     */
450     function _set_confirmed_success($flag=TRUE) {
451     $this->_confirmed_successfull = $flag;
452     }
453    
454     /**
455     * This sets the flag that tells this class
456     * to automatically call the form contents
457     * form errors and display it or not
458 jonen 1.5 *
459 jonen 1.3 * @param boolean - show errors?
460     */
461     function set_auto_error_display($flag=TRUE) {
462     $this->_auto_show_errors = $flag;
463     }
464    
465     /**
466     * This gets the current value of the flag
467     * that tells us to show form errors automatically
468     * or not.
469     *
470     * @return boolean
471     */
472     function get_auto_error_display() {
473     return $this->_auto_show_errors;
474     }
475    
476    
477     /**
478     * This method allows us to get access to the
479     * errors display object that is generated by
480     * the form content. This is the display
481     * object that is meant to be rendered directly.
482     * If there are no errors. we will return NULL
483     *
484     * @return object
485     */
486     function &get_error_display_object() {
487     if ($this->_has_errors) {
488     return $this->_form_content->form_errors();
489     } else {
490     return NULL;
491     }
492     }
493    
494    
495     /**
496     * This method returns an array of errors that
497     * happened in the form.
498 jonen 1.5 *
499 jonen 1.3 * @return array
500     */
501     function get_error_array() {
502     return $this->_form_content->get_error_array();
503     }
504    
505     /**
506     * This returns the flag that tells us that
507     * the form has errors during processing
508     *
509     * @return boolean
510     */
511     function has_errors() {
512     return $this->_has_errors;
513     }
514    
515    
516    
517    
518     //************************************************//
519     //* FORMtag Attributes for this class *//
520     //************************************************//
521    
522     /**
523     * This function is used to set the
524     * form name
525     *
526     * @param string
527     */
528     function set_form_name($name) {
529     $this->_form_attributes["name"] = $name;
530     }
531    
532     /**
533     * This function is used to get
534     * the form name
535     *
536     * @return string
537     */
538     function get_form_name() {
539     return $this->_form_attributes["name"];
540     }
541    
542     /**
543     * This function is used to set the
544     * form target
545     *
546     * @param string
547     */
548     function set_form_target($target) {
549     $this->_form_attributes["target"] = $target;
550     }
551    
552     /**
553     * This function is used to get
554     * the form target
555     *
556     * @return string
557     */
558     function get_form_target() {
559     return $this->_form_attributes["target"];
560     }
561    
562     /**
563     * This function is used to set the
564     * form method
565     *
566     * @param string (POST or GET)
567     */
568     function set_form_method($method) {
569     if ( strcasecmp($method,"GET") !=0 && strcasecmp($method,"POST") !=0 ) {
570     user_error("FormProcessor::set_form_method() - INVALID Form method ".$method);
571     } else {
572     $this->_form_attributes["method"] = $method;
573     }
574     }
575    
576     /**
577     * This function is used to get
578     * the form method
579     *
580     * @return string (POST or GET)
581     */
582     function get_form_method() {
583     return $this->_form_attributes["method"];
584     }
585    
586     /**
587     * Sets the form action
588     *
589     * @param string
590     */
591     function set_form_action($action) {
592     $this->_form_attributes["action"] = $action;
593     }
594    
595     /**
596     * This function is used to get
597     * the form action
598     *
599     * @return string (POST or GET)
600     */
601     function get_form_action() {
602     return $this->_form_attributes["action"];
603     }
604    
605     /**
606     * Sets the form enctype
607     *
608     * @param string
609     */
610     function set_form_enctype($enctype) {
611     $this->_form_attributes["enctype"] = $enctype;
612     }
613    
614     /**
615     * This function is used to get
616     * the form enctype value
617     *
618     * @return string
619     */
620     function get_form_enctype() {
621     return $this->_form_attributes["enctype"];
622     }
623    
624    
625     /**
626 jonen 1.5 * This is used to set the action
627 jonen 1.3 * submitted by the user
628     *
629     */
630     function _set_action() {
631     $this->_form_submit_action = $_REQUEST[FORM_ACTION];
632     $this->_form_content->set_action($this->_form_submit_action);
633     }
634    
635     /**
636     * This is used to get the action that was
637     * processed by the form
638     *
639     * @return string
640     */
641     function get_action() {
642     return $this->_form_submit_action;
643 jonen 1.1 }
644    
645    
646     /**
647 jonen 1.4 * Set the onsubmit attribute to the form
648     * NOTE: The FormContent child can automatically
649     * set this value depending on the FormElement
650     * children it contains.
651 jonen 1.5 *
652 jonen 1.4 * @param string
653     * @return none
654     */
655     function set_onsubmit($js) {
656     $this->_form_attributes["onsubmit"] = $js;
657     }
658    
659     /**
660     * Gets the current value of the form tag's
661     * onsubmit value
662 jonen 1.5 *
663 jonen 1.4 * @return string
664     */
665     function get_onsubmit() {
666     return $this->_form_attributes["onsubmit"];
667     }
668    
669 jonen 1.5 /**
670     * Set a random attribute on the form tag.
671     * You should know what you are doing as this
672     * might invalidate the output html with the
673     * W3C validator.
674     *
675     * @param string the key
676     * @param string the value
677     */
678     function set_form_attribute($key, $value) {
679     $this->_form_attributes[$key] = $value;
680     }
681    
682 jonen 1.4
683     //************************************//
684     //* Some Private methods *//
685     //************************************//
686    
687     /**
688     * This method initializes the FormContent
689     * during processing.
690 jonen 1.5 *
691 jonen 1.4 * @return none
692     */
693     function _init_form_content() {
694     //let the form build the FormElement objects
695     //that will be used by the form
696     $this->_form_content->form_init_elements();
697    
698     //first we need to
699 jonen 1.5 if (!@$_REQUEST[$this->_form_attributes['name'] . FORM_VISITED]) {
700 jonen 1.4 $this->_form_content->form_init_data();
701     }
702    
703     //see if the form content has a child of the
704     //FEFile element, so we can automatically
705     //add the enctype to the form tag attribute
706     if ($this->_form_content->_has_file_element) {
707     $this->set_form_enctype("multipart/form-data");
708 jonen 1.5 }
709 jonen 1.4 }
710    
711    
712     /**
713 jonen 1.1 * this function builds the FORMtag object
714     * and its attributes.
715     *
716     * @return FORMtag object.
717     */
718     function _build_form_tag() {
719 jonen 1.4 //see if we need to add the onsubmit attribute to the form
720     //this only needs to happen on the non-confirmation
721     //portion of the forms.
722 jonen 1.5 if (!isset($_REQUEST[$this->_form_attributes['name'] . FORM_VISITED])) {
723 jonen 1.4 if (strlen($this->_form_content->_form_on_submit) > 0) {
724     $set = TRUE;
725 jonen 1.5 $this->set_onsubmit( $this->get_onsubmit().$this->_form_content->_form_on_submit.$this->_form_content->_form_action_elements_on_submit );
726 jonen 1.4 }
727     } else {
728     //re-rendering the form and it has errors.
729     //we need the onsubmit if they have it.
730 jonen 1.5 if (isset($_REQUEST[$this->_form_attributes['name'] . FORM_VISITED]) && $this->_has_errors) {
731 jonen 1.4 if (strlen($this->_form_content->_form_on_submit) > 0) {
732     $set = TRUE;
733 jonen 1.5 $this->set_onsubmit($this->get_onsubmit().$this->_form_content->_form_on_submit.$this->_form_content->_form_action_elements_on_submit );
734 jonen 1.4 }
735 jonen 1.5 } else if (isset($_REQUEST[FORM_CONFIRM]) && $_REQUEST[FORM_CONFIRM] == 1) {
736     //form has been confirmed lets add it
737     //in case we are showing the form again
738 jonen 1.4 if (strlen($this->_form_content->_form_on_submit) > 0) {
739     $set = TRUE;
740 jonen 1.5 $this->set_onsubmit( $this->get_onsubmit().$this->_form_content->_form_on_submit.$this->_form_content->_form_action_elements_on_submit );
741 jonen 1.4 }
742 jonen 1.5 } else {
743     $this->set_onsubmit($this->_form_content->_form_action_elements_on_submit);
744 jonen 1.4 }
745     }
746    
747 jonen 1.3 $form_attrs = array();
748     foreach( $this->_form_attributes as $name => $value) {
749     if ($value) {
750     $form_attrs[$name] = $value;
751     }
752 jonen 1.5 }
753 jonen 1.1 $this->_form = new FORMtag( $form_attrs );
754     }
755    
756     /**
757     * This adds all of the submitted data as
758     * hidden form fields
759     *
760     */
761     function _add_confirm_data() {
762     $keys = array_keys( $this->_form_content->_elements );
763     foreach( $keys as $key ) {
764 jonen 1.5 //make sure the element isn't disabled.
765     if (!$this->_form_content->_elements[$key]->is_disabled()) {
766     $this->_form->add($this->_form_content->_elements[$key]->get_confirm_element());
767     }
768 jonen 1.1 }
769    
770     $keys = array_keys( $this->_form_content->_hidden_elements );
771     foreach( $keys as $key ) {
772 jonen 1.4 $this->_form->add( $this->_form_content->_hidden_elements[$key]->get_confirm_element() );
773 jonen 1.1 }
774     }
775    
776    
777     /**
778     * This function adds the form content's
779     * hidden form fields to the
780     * form automatically
781     *
782     */
783     function _add_hidden_fields() {
784     //Lets add the form's hidden vars it wants
785     foreach ($this->_form_content->_hidden_elements as $element) {
786     $this->_form->add( $element->get_element() );
787     }
788     }
789    
790    
791     /**
792     * This method adds the processor specific
793     * hidden fields.
794     *
795     */
796     function __hidden_fields() {
797     $this->_form->add( form_hidden(FORM_ACTION),
798 jonen 1.5 form_hidden($this->_form_attributes['name'] . FORM_VISITED,1) );
799 jonen 1.1
800     if ($this->_form_content->has_confirm() && !$this->_confirmed) {
801 jonen 1.5 if (@!$_REQUEST[$this->_form_attributes['name'] . FORM_VISITED] || $this->_has_errors) {
802 jonen 1.1 $this->_form->add( form_hidden(FORM_CONFIRM, 0 ) );
803     } else {
804     $this->_form->add( form_hidden(FORM_CONFIRM, 1 ) );
805     }
806     } else if ($this->_form_content->has_confirm() && !$this->_confirmed) {
807     //reset this so they can submit again
808     $this->_form->add( form_hidden(FORM_CONFIRM, 0 ) );
809     }
810 jonen 1.3 }
811    
812     /**
813     * This method is used to build any Javascript
814     * that is used by the form and/or the form elements
815     * used in the form.
816     *
817     * @return string
818     */
819     function _build_javascript() {
820     $form_js = $this->_form_content->javascript();
821    
822     //now walk each form element and try to get any js
823     foreach( $this->_form_content->_elements as $element ) {
824     $form_js .= $element->javascript();
825     }
826    
827     return $form_js;
828 jonen 1.1 }
829     }
830     ?>

MailToCvsAdmin">MailToCvsAdmin
ViewVC Help
Powered by ViewVC 1.1.26 RSS 2.0 feed