ATK /relations/class.atkrelation.inc

Language PHP Lines 394
MD5 Hash 859d5a80d8b2716426e7fa572d61b242
Repository https://github.com/ibuildingsnl/ATK.git View Raw File View Project SPDX
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
<?php
  /**
   * This file is part of the Achievo ATK distribution.
   * Detailed copyright and licensing information can be found
   * in the doc/COPYRIGHT and doc/LICENSE files which should be
   * included in the distribution.
   *
   * @package atk
   * @subpackage relations
   *
   * @copyright (c)2000-2004 Ivo Jansch
   * @license http://www.achievo.org/atk/licensing ATK Open Source License
   *
   * @version $Revision: 6320 $
   * $Id$
   */

  /**
   * The atkRelation class defines a relation to another node.
   *
   * @author Ivo Jansch <ivo@achievo.org>
   * @package atk
   * @subpackage relations
   * @abstract
   *
   */
  class atkRelation extends atkAttribute
  {
    /**
     * @var String Destination node.
     */
    var $m_destination;

    /**
     * @var atkNode Destination instance.
     */
    var $m_destInstance="";

    /**
     * @var String Filter for destination records.
     */
    var $m_destinationFilter="";

    /**
     * Descriptor template for destination node.
     * @var String
     */
    var $m_descTemplate = NULL;

    /**
     * Descriptor handler.
     * @var Object
     */
    var $m_descHandler = NULL;

    /**
     * Constructor
     * @param String $name The name of the relation.
     * @param String $destination The destination node (in module.name notation)
     * @param int $flags Flags for the relation
     */
    function atkRelation($name, $destination, $flags=0)
    {
      $this->atkAttribute($name, $flags);
      $this->m_destination = $destination;

    }

    /**
     * Returns the destination filter.
     * @return String The destination filter.
     */
    function getDestinationFilter()
    {
      return $this->m_destinationFilter;
    }

    /**
     * Sets the destination filter.
     * @param String $filter The destination filter.
     */
    function setDestinationFilter($filter)
    {
      $this->m_destinationFilter = $this->_cleanupDestinationFilter($filter);
    }

    /**
     * Remove redundant (more than 1 subsequently) spaces from the filter string.
     *
     * This prevents the filter from rapidly becoming too long to be passed in the URL if
     * enters are used in code to make the filter readable.
     *
     * @param string $filter
     * @return string
     */
    function _cleanupDestinationFilter($filter)
    {
      $result = '';
      $filter_length = strlen($filter);
      $quotes = array("'",'"','`');
      $quoteStack = array();
      $lastChar = '';

      for ($i = 0; $i < $filter_length; $i++)
      {
        $currentChar = $filter[$i];

        if(in_array($currentChar,$quotes))
        {
          if(sizeof($quoteStack) > 0 && $currentChar == $quoteStack[sizeof($quoteStack) - 1])
          {
            array_pop($quoteStack);
          }
          else
          {
            array_push($quoteStack,$currentChar);
          }
        }

        // not between quotes
        if(!($currentChar === ' ' && $lastChar === ' ' && sizeof($quoteStack) == 0))
        {
          if($currentChar != "\n") $result .= $currentChar;
        }
        $lastChar = $currentChar;
      }
      return $result;
    }
    /**
     * Adds a filter value to the destination filter.
     * @param String $filter Filter to be added to the destination filter.
     */
    function addDestinationFilter($filter)
    {
      $filter = $this->_cleanupDestinationFilter($filter);
      if($this->m_destinationFilter != "")
        $this->m_destinationFilter = "({$this->m_destinationFilter}) AND ({$filter})";
      else
        $this->m_destinationFilter = $filter;
      return $this;
    }

    /**
     * Get descriptor handler.
     * @return Object descriptor handler
     */
    function &getDescriptorHandler()
    {
      return $this->m_descHandler;
    }

    /**
     * Set descriptor handler.
     * @param Object $handler The descriptor handler.
     */
    function setDescriptorHandler(&$handler)
    {
      $this->m_descHandler = &$handler;
    }

    /**
     * Returns the descriptor template for the destination node.
     * @return String The descriptor Template
     */
    function getDescriptorTemplate()
    {
      return $this->m_descTemplate;
    }

    /**
     * Sets the descriptor template for the destination node.
     * @param String $template The descriptor template.
     */
    function setDescriptorTemplate($template)
    {
      $this->m_descTemplate = $template;
    }

    /**
     * Descriptor handler. Forwards description handler calls
     * to the real description handler.
     *
     * @param array $record The record
     * @param atkNode $node The atknode object
     * @return String with the descriptor
     */
    function descriptor($record, &$node)
    {
      $method = $this->m_name."_descriptor";
      if (method_exists($this->m_descHandler, $method))
        return $this->m_descHandler->$method($record, $node);
      else return $this->m_descHandler->descriptor($record, $node);
    }

    /**
     * Create the instance of the destination.
     *
     * If succesful, the instance is stored in the m_destInstance member variable.
     *
     * @return boolean true if succesful, false if something went wrong.
     */
    function createDestination()
    {
      if (!is_object($this->m_destInstance))
      {
        $cache_id = $this->m_owner.".".$this->m_name;
        $this->m_destInstance = &getNode($this->m_destination, true, $cache_id);

        // Validate if destination was created succesfully
        if (!is_object($this->m_destInstance))
        {
          atkerror("Relation with unknown nodetype '".$this->m_destination."' (in node '".$this->m_owner."')");
          $this->m_destInstance = NULL;
          return false;
        }

        if ($this->hasFlag(AF_NO_FILTER))
          $this->m_destInstance->m_flags |= NF_NO_FILTER;

        foreach (array_keys($this->m_destInstance->m_attribList) as $key)
        {
          $attribute = &$this->m_destInstance->m_attribList[$key];

          if (is_subclass_of($attribute, "atkrelation") && is_object($this->m_ownerInstance) && $attribute->m_destination == $this->m_ownerInstance->atkNodeType())
          {
            $attribute->m_destInstance = &$this->m_ownerInstance;

            if (count($attribute->m_tabs) == 1 && $attribute->m_tabs[0] == "default")
            {
              $attribute->setTabs($this->m_tabs);
            }
          }
        }

        if (!empty($this->m_descHandler))
          $this->m_destInstance->setDescriptorHandler($this);

        if (!empty($this->m_descTemplate))
          $this->m_destInstance->setDescriptorTemplate($this->m_descTemplate);
      }
      return true;
    }

    /**
     * Return a displayable string for a record.
     * @param array $record The record that contains the information to display.
     * @return String a displayable string for this value.
     */
    function display($record)
    {
      return $record[$this->fieldName()];
    }

    /**
     * Validation method. Empty implementation. Derived classes may override
     * this function.
     * @abstract
     *
     * @param array $record The record that holds the value for this
     *                      attribute. If an error occurs, the error will
     *                      be stored in the 'atkerror' field of the record.
     * @param String $mode The mode for which should be validated ("add" or
     *                     "update")
     */
    function validate(&$record, $mode)
    {
    }

    /**
     * Check if the relation is empty
     * @param array $record The record to check
     * @return boolean true if a destination record is present. False if not.
     */
    function isEmpty($record)
    {
      if ($this->createDestination() && isset($record[$this->fieldName()][$this->m_destInstance->primaryKeyField()]))
      {
        return empty($record[$this->fieldName()][$this->m_destInstance->primaryKeyField()]);
      }
      else if ($this->createDestination() && isset($record[$this->fieldName()]))
      {
        return empty($record[$this->fieldName()]);
      }
      return true; // always empty if error.
    }

    /**
     * Retrieve the searchmodes supported by the relation.
     * @return array A list of supported searchmodes.
     */
    function getSearchModes()
    {
      // exact match and substring search should be supported by any database.
      // (the LIKE function is ANSI standard SQL, and both substring and wildcard
      // searches can be implemented using LIKE)
      // Possible values
      //"regexp","exact","substring", "wildcard","greaterthan","greaterthanequal","lessthan","lessthanequal"
      return array("exact");
    }

    /**
     * Get the searchmode for nested/child attributes.
     *
     * @param string|array $searchmode searchmode
     * @param string       $childname  the child attribute's name
     * @return string|array the child searchmode
     */
    protected function getChildSearchMode($searchmode, $childname)
    {
      if (is_array($searchmode) && isset($searchmode[$childname]))
        return $searchmode[$childname];
      return $searchmode;
    }

    /**
     * Since most relations do not store anything in a field, the default
     * fieldtype for relations is "". Exceptions (like the many2oone relation,
     * which stores a foreign key) can implement their own dbFieldType().
     * @abstract
     * @return String
     */
    function dbFieldType()
    {
      return "";
    }

    /**
     * Returns the condition (SQL) that should be used when we want to join a relation's
     * owner node with the parent node.
     *
     * @param atkQuery $query The query object
     * @param string $tablename The tablename
     * @param string $fieldalias
     * @return String SQL string for joining the owner with the destination.
     *                Defaults to false.
     */
    function getJoinCondition(&$query, $tablename="",$fieldalias="")
    {
      return false;
    }

    /**
     * Returns an instance of the node that the relation points to.
     * @return atkNode The node that this relation points to, or
     *                 NULL if the destination is not valid.
     */
    function &getDestination()
    {
      if ($this->createDestination())
      {
        return $this->m_destInstance;
      }
      return NULL;
    }

    /**
     * Attempts to get a translated label which can be used when composing an "add" link
     *
     * @return String Localised "add" label
     */
    function getAddLabel()
    {
      // Try to get a translation for link_fieldname_add (or if not found, a translation for link_destination_add)
      $keys = array("link_" . $this->fieldName() . "_add", "link_" . getNodeType($this->m_destination) . "_add");
      $label = atktext($keys, getNodeModule($this->m_destination), "", "", "", true);

      // If translation not found, then use a concatenation of translations of the destination and the word "add" as default
      if ($label=="")
        $label = atktext(getNodeType($this->m_destination), getNodeModule($this->m_destination)) . " " . strtolower(atktext("add", "atk"));

      // Return the translation
      return $label;
    }

    /**
     * Parses the destination filter
     *
     * @param string $destFilter filter to parse
     * @param array $record the current record
     * @return $filter string filter.
     */
    function parseFilter($destFilter,$record)
    {
      if($destFilter!="")
      {
        atkimport("atk.utils.atkstringparser");
        $parser = new atkStringParser($destFilter);
        return $parser->parse($record);
      }
      return "";
    }
  }
?>
Back to Top