1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.MonoRail
.ActiveRecordSupport
18 using System
.Reflection
;
19 using Castle
.Components
.Binder
;
20 using Castle
.MonoRail
.Framework
;
23 /// Mark a parameter with this attribute to instruct the <see cref="SmartDispatcherController" />
24 /// to load an <c>ActiveRecord</c> instance of the parameter type, using the request parameter
25 /// as the identifier.
28 /// The <see cref="ARFetchAttribute"/> only loads an instance
29 /// based on the primary key value obtained from <see cref="IRequest.Params"/>
30 /// <para>For example:</para>
32 /// public class CustomerController : ARSmartDispatcherController
34 /// public void UpdateCustomerLocation([ARFetch("customer.id")] Customer customer, [ARFetch("location.id")] Location location)
36 /// customer.Location = location;
39 /// RedirectToAction("index");
43 /// The code above assumes that you have the fields
44 /// <c>customer.id</c> and <c>location.id</c> on the form being
47 [AttributeUsage(AttributeTargets
.Parameter
), Serializable
]
48 public class ARFetchAttribute
: Attribute
, IParameterBinder
50 private String requestParameterName
;
52 private bool create
, required
;
53 private IDataBinder binder
;
56 /// Constructs an <see cref="ARFetchAttribute"/>
57 /// specifying the parameter name and the create and require behavior
59 /// <param name="requestParameterName">The parameter name to be read from the request</param>
60 /// <param name="create"><c>true</c> if you want an instance even when the record is not found</param>
61 /// <param name="required"><c>true</c> if you want an exception if the record is not found</param>
62 public ARFetchAttribute(String requestParameterName
, bool create
, bool required
) : base()
64 this.requestParameterName
= requestParameterName
;
66 this.required
= required
;
70 /// Constructs an <see cref="ARFetchAttribute"/> using the
71 /// parameter name as the <see cref="ARFetchAttribute.RequestParameterName"/>
73 public ARFetchAttribute() : this(null, false, false)
78 /// Constructs an <see cref="ARFetchAttribute"/> specifing the
80 /// <seealso cref="ARFetchAttribute.RequestParameterName"/>
82 public ARFetchAttribute(String requestParameterName
) : this(requestParameterName
, false, false)
87 /// Constructs an <see cref="ARFetchAttribute"/> using the
88 /// parameter name as the <see cref="ARFetchAttribute.RequestParameterName"/>
89 /// and the create and require behavior
91 /// <param name="create"><c>true</c> if you want an instance even when the record is not found</param>
92 /// <param name="require"><c>true</c> if you want an exception if the record is not found</param>
93 public ARFetchAttribute(bool create
, bool require
) : this(null, create
, require
)
98 /// The parameter name to be read from the request. The parameter value will
99 /// be used as the primary key value to load the target object instance.
101 public String RequestParameterName
103 get { return requestParameterName; }
104 set { requestParameterName = value; }
108 /// When set to <c>true</c> an instance of
109 /// the target type will be created if the record
110 /// is not found. The default is <c>false</c>.
114 get { return create; }
115 set { create = value; }
119 /// When set to <c>true</c>, an exception will be thrown
120 /// if the record specified is not found. The default is <c>false</c>.
124 get { return required; }
125 set { required = value; }
129 /// Comma-separated list of lazy associations to eager-fetch, when loading the ActiveRecord object.
133 get { return eager; }
134 set { eager = value; }
137 public virtual int CalculateParamPoints(IEngineContext context
, IController controller
, IControllerContext controllerContext
, ParameterInfo parameterInfo
)
139 String paramName
= RequestParameterName
?? parameterInfo
.Name
;
141 return context
.Request
.Params
.Get(paramName
) != null ? 10 : 0;
144 public virtual object Bind(IEngineContext context
, IController controller
, IControllerContext controllerContext
, ParameterInfo parameterInfo
)
146 EnsureBinderExists();
148 ARFetcher fetcher
= new ARFetcher(binder
.Converter
);
150 return fetcher
.FetchActiveRecord(parameterInfo
, this, context
.Request
);
153 private void EnsureBinderExists()
157 binder
= CreateBinder();
162 /// Creates the data binder implementation.
164 /// <returns></returns>
165 protected virtual IDataBinder
CreateBinder()
167 return new DataBinder();