| 360 | == A sample use == |
| 361 | |
| 362 | Now that we have our new class and provider in place, '''let's see how to use them'''! |
| 363 | |
| 364 | === Creating a new, non-existing object === |
| 365 | |
| 366 | To create a new, non existing object of our new class, we follow the steps outlined above: |
| 367 | |
| 368 | 1. specify a key at contruction time, |
| 369 | 2. set any other property via the {{{obj['fieldname'] = value}}} syntax, including custom fields, |
| 370 | 3. call the insert() method on the object. |
| 371 | |
| 372 | See the following code. |
| 373 | |
| 374 | {{{ |
| 375 | # Let's first import our new class definition. |
| 376 | # Note that you don't have to deal with the framework in any way, the class may be defined on its own. |
| 377 | from tracgenericworkflow.model import ResourceWorkflowState |
| 378 | }}} |
| 379 | |
| 380 | {{{ |
| 381 | # The following statement will create an empty object with a specific key, and suddenly |
| 382 | # try to fetch an object with the same key from the database. |
| 383 | # If it is found, then the object's properties will be filled with the corresponding values |
| 384 | # from the database, and the internal field "exists" set to True. |
| 385 | rws = ResourceWorkflowState(self.env, id, sometext) |
| 386 | |
| 387 | # We can here check whether the object was found in the database |
| 388 | if rws.exists: |
| 389 | # The object already exists! So we can get its property values |
| 390 | print rws['state'] |
| 391 | else: |
| 392 | # Here we decide to create the object. So we fill in some other properties and then call the "insert()" method. |
| 393 | # The object will be stored into the database, and all registered listeners will be called. |
| 394 | rws['state'] = 'new' |
| 395 | rws.insert() |
| 396 | }}} |
| 397 | |
| 398 | === Reading an existing object, and changing it === |
| 399 | |
| 400 | Here we want to read an existing object of our new class, alter some of its properties and save it back. |
| 401 | |
| 402 | We follow the steps outlined above: |
| 403 | |
| 404 | 1. specify a key at contruction time: the object will be filled with all of the values form the database, |
| 405 | 2. modify any other property via the {{{obj['fieldname'] = value}}} syntax, including custom fields. |
| 406 | This syntax is the only one to keep track of the changes to any field. |
| 407 | 3. call the save_changes() method on the object.[[BR]] |
| 408 | |
| 409 | See the code below. |
| 410 | |
| 411 | {{{ |
| 412 | rws = ResourceWorkflowState(self.env, id, sometext) |
| 413 | |
| 414 | if rws.exists: |
| 415 | # The object already exists. |
| 416 | # Now we also want to modify the object's 'state' property, and save the updated object. |
| 417 | rws['state'] = 'ok' |
| 418 | |
| 419 | # The following code will modify the object in the database and also call all |
| 420 | # of the registered listeners. |
| 421 | try: |
| 422 | rws.save_changes(author, "State changed") |
| 423 | except: |
| 424 | self.log.info("Error saving the resource with id %s" % rws['id']) |
| 425 | }}} |
| 426 | |
| 427 | Saving changes will also keep track of the change history into a different table, named like the base table with an "_change" suffix. |
| 428 | Note: Currently there is no explicit programmatic API to access these change tables, you must access them directly with SQL if you need to. |
| 429 | |
| 430 | === Delete an object === |
| 431 | |
| 432 | Deleting an object is as simple as calling the {{{delete()}}} method on the object instance. |
| 433 | |
| 434 | See the following code. |
| 435 | |
| 436 | {{{ |
| 437 | rws = ResourceWorkflowState(self.env, id, sometext) |
| 438 | |
| 439 | if rws.exists: |
| 440 | # The object already exists. |
| 441 | # Now we want to delete the object from the database. The following code will delete the |
| 442 | # object and also call all of the registered listeners. |
| 443 | try: |
| 444 | rws.delete() |
| 445 | except: |
| 446 | self.log.info("Error deleting the resource with id %s" % rws['id']) |
| 447 | }}} |
| 448 | |
| 449 | === Use pattern-matching to find a particular set of objects === |
| 450 | |
| 451 | You can get a list of objects matching a particular set of properties - i.e. pattern matching - very easily: |
| 452 | |
| 453 | 1. Create an empty, template object, without specifying a key, |
| 454 | 2. Give values to any properties you want the objects in the database to match, |
| 455 | 3. Call the list_matching_objects() method on the object. |
| 456 | |
| 457 | See the following code. |
| 458 | |
| 459 | {{{ |
| 460 | # We create a template object here, i.e. not providing a key. |
| 461 | rws_search = ResourceWorkflowState(self.env) |
| 462 | |
| 463 | # Let's say we want to list all the objects in the database having a 'state' of 'new'. |
| 464 | # We set the desired property values in the template objects |
| 465 | rws_search['state'] = 'new' |
| 466 | |
| 467 | # We then start the search |
| 468 | for rws in rws_search.list_matching_objects(): |
| 469 | # At every cycle, rws will hold another result matching the search pattern, in the |
| 470 | # form of a full-fetched object of the ResourceWorkflowState type. |
| 471 | print rws['id'] |
| 472 | }}} |
| 473 | |
| 474 | [[BR]] |
| 475 | == Providing specific results to the Trac search engine == |
| 476 | |
| 477 | Subclasses can participate in the Trac search engine, if they wish to. It is a matter of a few lines of code. |
| 478 | |
| 479 | First of all, the concrete class provider must explicitly state this support in the class metadata, just by setting the 'searchable' metadata property. For more details about class metadata, refer to the IConcreteClassProvider interface implementation. |
| 480 | |
| 481 | Then, the subclass must override the {{{get_search_results()}}} method. |
| 482 | |
| 483 | For details about how to implement this method, refer to the base Trac documentation about the {{{ISearchSource}}} interface in the {{{trac.search}}} package. |
| 484 | |
| 485 | [[BR]] |