File Coverage

blib/lib/FWS/V2/Database.pm
Criterion Covered Total %
statement 24 1279 1.8
branch 0 350 0.0
condition 0 229 0.0
subroutine 8 67 11.9
pod 50 50 100.0
total 82 1975 4.1


line stmt bran cond sub pod time code
1             package FWS::V2::Database;
2              
3 1     1   20 use 5.006;
  1         3  
  1         46  
4 1     1   5 use strict;
  1         2  
  1         30  
5 1     1   4 use warnings;
  1         2  
  1         27  
6 1     1   6 no warnings 'uninitialized';
  1         9  
  1         107  
7              
8             =head1 NAME
9              
10             FWS::V2::Database - Framework Sites version 2 data management
11              
12             =head1 VERSION
13              
14             Version 1.13091122
15              
16             =cut
17              
18             our $VERSION = '1.13091122';
19              
20              
21             =head1 SYNOPSIS
22              
23             use FWS::V2;
24              
25             #
26             # Create FWS with MySQL connectivity
27             #
28             my $fws = FWS::V2->new(
29             DBName => 'theDBName',
30             DBUser => 'myUser',
31             DBPassword => 'myPass'
32             );
33              
34             #
35             # create FWS with SQLite connectivity
36             #
37             my $fws2 = FWS::V2->new(
38             DBType => 'SQLite',
39             DBName => '/home/user/your.db'
40             );
41              
42              
43              
44             =head1 DESCRIPTION
45              
46             Framework Sites version 2 common methods that connect, read, write, reorder or alter the database itself.
47              
48              
49             =head1 METHODS
50              
51             =head2 mergeExtra
52              
53             In FWS database tables there is a field named extra_value. This field holds a hash that is to be appended to the return hash of the record it belongs to.
54              
55             #
56             # If we have an extra_value field and a real hash lets combine them together
57             #
58             %dataHash = $fws->mergeExtra( $extra_value, %dataHash );
59              
60             Note: If anything but stored extra_value strings are passed, the method will throw an error
61              
62             =cut
63              
64             sub mergeExtra {
65 0     0 1   my ( $self, $extraValue, %addHash ) = @_;
66              
67             #
68             # lets use storable in comptabile nfreeze mode
69             #
70 1     1   1327 use Storable qw(nfreeze thaw);
  1         4285  
  1         1340  
71              
72             #
73             # pull the hash out
74             #
75 0           my %extraHash;
76              
77             #
78             # only if its populated unthaw it
79             #
80 0 0         if ( $extraValue ) { %extraHash = %{thaw( $extraValue )} }
  0            
  0            
81              
82             #
83             # return the two hashes combined together
84             #
85 0           return ( %addHash, %extraHash );
86             }
87              
88             =head2 adminUserArray
89              
90             Return an array of the admin users. The hash array will contain name, userId, and guid.
91              
92             #
93             # get a reference to the hash array
94             #
95             my $adminUserArray = $fws->adminUserArray( ref => 1 );
96              
97             =cut
98              
99             sub adminUserArray {
100 0     0 1   my ( $self, %paramHash ) = @_;
101 0           my @userHashArray;
102              
103             #
104             # get the data from the database and push it into the hash array
105             #
106 0           my $adminUserArray = $self->runSQL( SQL => "select name, user_id, guid from admin_user" );
107 0           while ( @$adminUserArray ) {
108             #
109             # assign the data to variables: Perl likes it done this way
110             #
111 0           my %userHash;
112 0           $userHash{name} = shift @{$adminUserArray};
  0            
113 0           $userHash{userId} = shift @{$adminUserArray};
  0            
114 0           $userHash{guid} = shift @{$adminUserArray};
  0            
115              
116             #
117             # push it into the array
118             #
119 0           push @userHashArray, {%userHash};
120             }
121 0 0         if ( $paramHash{ref} ) { return \@userHashArray }
  0            
122 0           return @userHashArray;
123             }
124              
125              
126             =head2 adminUserHash
127              
128             Return an array of the admin users. The hash array will contain name, userId, and guid.
129              
130             #
131             # get a reference to the hash
132             #
133             my $dataHashRef = $fws->adminUserHash( guid => 'someGUIDOfAnAdminUser', ref => 1 );
134              
135             =cut
136              
137             sub adminUserHash {
138 0     0 1   my ( $self, %paramHash ) = @_;
139 0           my $extArray = $self->runSQL( SQL => "select extra_value, 'email', email, 'userId', user_id, 'name', name from admin_user where guid='" . $self->safeSQL( $paramHash{guid} ) . "'");
140 0           my $extraValue = shift @{$extArray};
  0            
141 0           my %adminUserHash = @$extArray;
142 0           %adminUserHash = $self->mergeExtra( $extraValue, %adminUserHash );
143 0 0         if ( $paramHash{ref} ) { return \%adminUserHash }
  0            
144 0           return %adminUserHash;
145             }
146              
147             =head2 alterTable
148              
149             It is not recommended you would use the alterTable method outside of its intended core database creation and maintenance routines but is here for completeness. Some of the internal table definitions alter data based on its context and will be unpredictable. For work with table structures not directly tied to the FWS 2 core schema, use FWS::Lite in a non web rendered script.
150              
151             #
152             # retrieve a reference to an array of data we asked for
153             #
154             # Note: It is not recommended to change the data structure of
155             # FWS default tables
156             #
157             print $fws->alterTable(
158             table => 'table_name', # case sensitive table name
159             field => 'field_name', # case sensitive field name
160             type => 'char(255)', # Any standard cross platform type
161             key => '', # MUL, PRIMARY KEY, FULL TEXT
162             default => '', # '0000-00-00', 1, 'default value'...
163             );
164              
165             =cut
166              
167             sub alterTable {
168 0     0 1   my ( $self, %paramHash ) = @_;
169              
170             #
171             # because this is only called interanally and all data is static and known,
172             # we can be a little laxed on safety there is no need to wrapper everything
173             # in safeSQL - even so in the context of some parts here we actually
174             # might even been adding tics out of place on purpose.
175             #
176              
177             #
178             # set some vars we will flip depending on db type
179             # alot is defaulted to mysql, because that
180             # is the norm, we will groom things that need to be groomed
181             #
182 0           my $sqlReturn;
183 0           my $autoIncrement = 'AUTO_INCREMENT ';
184 0           my $indexStatement = 'alter table ' . $paramHash{table} . ' add INDEX ' . $paramHash{table} . '_' . $paramHash{field} . ' (' . $paramHash{field} . ')';
185              
186             #
187             # if default is timestamp lets not put tic's around it
188             #
189 0 0         if ( $paramHash{default} ne 'CURRENT_TIMESTAMP' ) {
190 0           $paramHash{default} = "'" . $paramHash{default} . "'";
191             }
192              
193             #
194             # the default value is not applicable to text types lets not set it!
195             #
196 0           my $default = " NOT NULL default " . $paramHash{default};
197 0 0         if ( $paramHash{type} =~ /^text/i ) { $default = '' }
  0            
198              
199             #
200             # build teh statements
201             #
202 0           my $addStatement = "alter table " . $paramHash{table} . " add " . $paramHash{field} . " " . $paramHash{type} . $default;
203 0           my $changeStatement = "alter table " . $paramHash{table} . " change " . $paramHash{field} . " " . $paramHash{field} . " " . $paramHash{type} . $default;
204              
205             #
206             # add primary key if the table is not an ext field
207             #
208 0           my $primaryKey = "PRIMARY KEY";
209              
210             #
211             # show tables statement
212             #
213 0           my $showTablesStatement = "show tables";
214              
215             #
216             # do SQLLite changes
217             #
218 0 0         if ( $self->{DBType} =~ /^sqlite$/i ) {
219 0           $autoIncrement = "";
220 0           $indexStatement = "create index " . $paramHash{table} . "_" . $paramHash{field} . " on " . $paramHash{table} . " (" . $paramHash{field} . ")";
221 0           $showTablesStatement = "select name from sqlite_master where type='table'";
222             }
223              
224             #
225             # do mySQL changes
226             #
227 0 0         if ( $self->{DBType} =~ /^mysql$/i ) {
228 0 0         if ( $paramHash{key} eq 'FULLTEXT' ) {
229 0           $indexStatement = "create FULLTEXT index " . $paramHash{table} . "_" . $paramHash{field} . " on " . $paramHash{table} . " (" . $paramHash{field} . ")";
230             }
231             }
232              
233             #
234             # FULTEXT is MUL if not mysql, and mysql returns them as MUL even if they are full text so we don't need to updated them if they are set to that
235             # so lets change it to MUL to keep mysql and other DB's without FULLTEXT syntax happy
236             #
237 0 0         if ( $paramHash{key} eq 'FULLTEXT' ) { $paramHash{key} = 'MUL' }
  0            
238              
239             #
240             # blank by default because we use guid - enxt if we are trans we need order ids for easy to read transactions
241             # this is for legacy eCommerce, but I like it anyways so we'll keep it this way
242             #
243 0           my $idField;
244 0 0         if ( $paramHash{table} eq 'trans' ) { $idField = ", id INTEGER " . $autoIncrement . $primaryKey }
  0            
245              
246             #
247             # if its the sessions table make it like this
248             #
249 0 0         if ( $paramHash{table} eq 'fws_sessions' ) { $idField = ", id char(36) " . $primaryKey }
  0            
250              
251             #
252             # compile the statement
253             #
254 0           my $createStatement = "create table " . $paramHash{table} . " (site_guid char(36) NOT NULL default ''" . $idField . ")";
255              
256             #
257             # For full text searching, we will need to use MyISAM
258             #
259 0 0         if ( $self->{DBType} =~ /^mysql$/i ) { $createStatement .= " ENGINE=MyISAM" }
  0            
260              
261             #
262             # get the table hash
263             #
264 0           my %tableHash;
265 0           my @tableList = @{$self->runSQL( SQL => $showTablesStatement, noUpdate => 1 )};
  0            
266 0           while (@tableList) {
267 0           my $fieldInc = shift @tableList;
268 0           $tableHash{$fieldInc} = 1;
269             }
270              
271             #
272             # create tht table if it does not exist
273             #
274 0 0         if ( !$tableHash{$paramHash{table}} ) {
275 0           $self->runSQL( SQL => $createStatement, noUpdate => 1 );
276 0           $sqlReturn .= $createStatement . '; ';
277             }
278              
279             #
280             # get the table definition hash
281             #
282 0           my %tableFieldHash = $self->tableFieldHash( $paramHash{table} );
283              
284             #
285             # make the field if its not there
286             #
287 0 0         if ( !$tableFieldHash{$paramHash{field}}{type} ) {
288 0           $self->runSQL( SQL => $addStatement, noUpdate=> 1 );
289 0           $sqlReturn .= $addStatement . '; ';
290             }
291              
292             #
293             # change the datatype if we are talking about MySQL for now if your SQLite
294             # we still have to add support for that
295             #
296 0 0 0       if ( $paramHash{type} ne $tableFieldHash{$paramHash{field}}{type} && $self->{DBType} =~ /^mysql$/i ) {
297 0           $self->runSQL( SQL => $changeStatement, noUpdate => 1 );
298 0           $sqlReturn .= $changeStatement . '; ';
299             }
300              
301             #
302             # set any keys if not the same;
303             #
304 0 0 0       if ( $tableFieldHash{$paramHash{table} . '_' . $paramHash{field}}{key} ne 'MUL' && $paramHash{key} ) {
305 0           $self->runSQL( SQL => $indexStatement, noUpdate => 1 );
306 0           $sqlReturn .= $indexStatement . '; ';
307             }
308              
309 0           return $sqlReturn;
310             }
311              
312              
313             =head2 autoArray
314              
315             Return a hash array of make, model, and year from the default automotive tables if they are installed.
316              
317             #
318             # get a list of autos make model and year based on year
319             #
320             my @autoArray = $fws->autoArray( year => '1994' );
321             for my $i (0 .. $#autoArray) {
322             print $autoArray[$i]{make} . "\t" . $autoArray[$i]{model} . "\n";
323             }
324            
325              
326             =cut
327              
328             sub autoArray {
329 0     0 1   my ( $self, %paramHash ) = @_;
330              
331 0           my $whereStatement = '1=1';
332              
333             #
334             # add active critiria if appicable
335             #
336 0 0         if ( $paramHash{model} ) { $whereStatement .= " and model like '" . $self->safeSQL( $paramHash{model} ) . "'" }
  0            
337 0 0         if ( $paramHash{year} ) { $whereStatement .= " and year like '" . $self->safeSQL( $paramHash{year} ) . "'" }
  0            
338 0 0         if ( $paramHash{make} ) { $whereStatement .= " and make like '" . $self->safeSQL( $paramHash{make} ) . "'" }
  0            
339              
340 0           my @autoArray = @{$self->runSQL( SQL => "select make, model, year from auto where " . $whereStatement )};
  0            
341              
342 0           my @returnArray;
343 0           while (@autoArray) {
344 0           my %autoHash;
345 0           $autoHash{make} = shift @autoArray;
346 0           $autoHash{model} = shift @autoArray;
347 0           $autoHash{year} = shift @autoArray;
348 0           push @returnArray, {%autoHash};
349             }
350 0           return @returnArray;
351             }
352              
353              
354             =head2 connectDBH
355              
356             Do the initial database connection via MySQL or SQLite. This method will return back the DBH it creates, but it is only here for completeness and would normally never be used. For FWS database routines this is not required as it will be implied when executing those methods.
357              
358             $fws->connectDBH();
359              
360             If you want to pass DBType, DBName, DBHost, DBUser, and DBPassword as a hash, the global FWS DBH will not be passed, and the DBH it creates will be returned from the method.
361              
362             The first time this is ran, it will cache the DBH and not ask for another. If you are running multipule data sources you will need to add noCache=>1. This will not cache the DBH, nor use the the cached DBH used as the default return.
363              
364             =cut
365              
366             sub connectDBH {
367 0     0 1   my ( $self, %paramHash ) = @_;
368              
369             #
370             # hook up with some DBI
371             #
372 1     1   3089 use DBI;
  1         25729  
  1         4473  
373              
374             #
375             # Use defaults if they are not passed
376             #
377 0   0       $paramHash{DBType} ||= $self->{DBType};
378 0   0       $paramHash{DBName} ||= $self->{DBName};
379 0   0       $paramHash{DBHost} ||= $self->{DBHost};
380 0   0       $paramHash{DBUser} ||= $self->{DBUser};
381 0   0       $paramHash{DBPort} ||= $self->{DBPort};
382 0   0       $paramHash{DBPassword} ||= $self->{DBPassword};
383 0   0       $paramHash{noCache} ||= 0;
384              
385             #
386             # fill this up!
387             #
388 0           my $DBH;
389              
390             #
391             # grab the DBI if we don't have it yet, or if noCache is passed do it again
392             #
393 0 0 0       if ( !$self->{'_DBH_'.$paramHash{DBName} . $paramHash{DBHost}} || $paramHash{noCache} eq '1') {
394              
395             #
396             # DBType for mysql is always lower case
397             #
398 0 0         if ( $paramHash{DBType} =~ /mysql/i) { $paramHash{DBType} = lc( $paramHash{DBType} ) }
  0            
399              
400             #
401             # default set to mysql
402             #
403 0           my $dsn = $paramHash{DBType} . ":" . $paramHash{DBName} . ":" . $paramHash{DBHost} . ":" . $paramHash{DBPort};
404              
405             #
406             # SQLite
407             #
408 0 0         if ( $paramHash{DBType} =~ /SQLite/i ) { $dsn = "SQLite:" . $paramHash{DBName} }
  0            
409              
410             #
411             # set the DBH for use throughout the script
412             #
413 0           $DBH = DBI->connect( 'DBI:' . $dsn, $paramHash{DBUser}, $paramHash{DBPassword} );
414              
415             #
416             # send an error if we got one
417             #
418 0 0         if ( DBI->errstr() ) { $self->FWSLog( 'DB connection error: ' . DBI->errstr() ) }
  0            
419             }
420              
421             #
422             # if DBH cache isn't defined then lets define it
423             #
424 0 0 0       if ( !$self->{'_DBH_' . $paramHash{DBName} . $paramHash{DBHost}} && !$paramHash{noCache} ) { $self->{'_DBH_' . $paramHash{DBName} . $paramHash{DBHost}} = $DBH }
  0            
425              
426             #
427             # in either case return the DBH in case someone wants it for convience
428             #
429 0           return $DBH;
430             }
431              
432              
433             =head2 copyData
434              
435             Make a copy of data hash giving it a unique guid, and appending (Copy) text to name and title if you pass the extra key of addTail.
436              
437             #
438             # duplicate a data record
439             #
440             my %newHash = $fws->copyData( %dataHash );
441              
442             #
443             # do the same thing but add (Copy) to the end of the name and title
444             #
445             my %copyHash = $fws->copyData( addTail => 1, %dataHash );
446              
447             =cut
448              
449             sub copyData {
450 0     0 1   my ( $self, %paramHash ) = @_;
451              
452 0           my %dataHash = $self->dataHash( guid => $paramHash{guid} );
453              
454 0 0         if ( $paramHash{addTail} ) {
455 0           $dataHash{name} .= ' (Copy)';
456 0           $dataHash{title} .= ' (Copy)';
457             }
458              
459 0           delete $paramHash{addTail};
460 0           $dataHash{guid} = '';
461 0           $dataHash{parent} = $paramHash{parent};
462              
463 0           return $self->saveData( %dataHash );
464             }
465              
466              
467             =head2 changeUserEmail
468              
469             Change the email of a user throught the system.
470              
471             my $failMessage = $fws->changeUserEmail( 'from@email.com', 'to@eamil.com' );
472              
473             Fail message will be blank if it worked.
474              
475             =cut
476              
477             sub changeUserEmail {
478 0     0 1   my ( $self, $emailFrom, $emailTo ) = @_;
479              
480             #
481             # check to make sure its not already being used
482             #
483 0           my %userHash = $self->userHash( $emailTo );
484              
485             #
486             # check to make sure the emails we are chaning it to are valid
487             #
488 0 0         if ( !$self->isValidEmail( $emailTo ) ) {
489 0           return 'The email you are chaning to is invalid';
490             }
491              
492             #
493             # if its not used, lets do it!
494             #
495 0 0 0       if ( $userHash{guid} && $emailFrom ) {
496              
497             #
498             # THIS NEEDS TO BE EXPORTD SOME HOW TO ECommerce
499             #
500             #my @transArray = $self->transactionArray(email=>$emailFrom);
501             #for my $i (0 .. $#transArray) {
502             # $self->runSQL( SQL => "update trans set email='" . $self->safeSQL( $emailTo ) . "' where email like '" . $self->safeSQL( $emailFrom ) . "'" );
503             #
504             # }
505              
506             #
507             # update the profile we are changing
508             #
509 0           $self->runSQL( SQL => "update profile set email='" . $self->safeSQL( $emailTo ) . "' where email like '" . $self->safeSQL( $emailFrom ) . "'" );
510              
511              
512              
513             }
514 0           else { return 'Email could not be changed, it is already being used.'; }
515 0           return;
516             }
517              
518              
519             =head2 dataArray
520              
521             Retrieve a hash array based on any combination of keywords, type, guid, or tags
522              
523             my @dataArray = $fws->dataArray( guid => $someParentGUID );
524             for my $i ( 0 .. $#dataArray ) {
525             $valueHash{html} .= $dataArray[$i]{name} . "
";
526             }
527              
528             Any combination of the following parameters will restrict the results. At least one is required.
529              
530             =over 4
531              
532             =item * guid: Retrieve any element whose parent element is the guid
533              
534             =item * keywords: A space delimited list of keywords to search for
535              
536             =item * tags: A comma delimited list of element tags to search for
537              
538             =item * type: Match any element which this exact type
539              
540             =item * containerId: Pull the data from the data container
541              
542             =item * childGUID: Retrieve any element whose child element is the guid (This option can not be used with keywords attribute)
543              
544             =item * showAll: Show active and inactive records. By default only active records will show
545              
546             =back
547              
548             Note: guid and containerId cannot be used at the same time, as they both specify the parent your pulling the array from
549              
550             =cut
551              
552             sub dataArray {
553 0     0 1   my ( $self, %paramHash ) = @_;
554              
555             #
556             # set site GUID if it wasn't passed to us
557             #
558 0   0       $paramHash{siteGUID} ||= $self->{siteGUID};
559              
560             #
561             # transform the containerId to the parent id
562             #
563 0 0         if ( $paramHash{containerId} ) {
564              
565             #
566             # if we don't get one, we will fail on the next check because we won't have a guid
567             #
568 0           ( $paramHash{guid} ) = @{$self->runSQL( SQL => "select guid from data where name='" . $self->safeSQL( $paramHash{containerId} ) . "' and element_type='data' and site_guid='" . $self->safeSQL( $paramHash{siteGUID} ) . "' LIMIT 1" )};
  0            
569              
570             }
571              
572             #
573             # if we don't have any data to search for get out so we don't get "EVERYTHING"
574             #
575 0 0 0       if ( $paramHash{childGUID} eq '' && $paramHash{guid} eq '' && !$paramHash{type} && $paramHash{keywords} eq '' && $paramHash{tags} eq '' ) {
      0        
      0        
      0        
576 0           return ();
577             }
578              
579             #
580             # get the where and join builders ready for content
581             #
582 0           my $addToExtWhere;
583             my $addToDataWhere;
584 0           my $addToExtJoin;
585 0           my $addToDataXRefJoin;
586              
587             #
588             # bind by element Type could be a comma delemented List
589             #
590 0 0         if ( $paramHash{type} ) {
591 0           my @typeArray = split( /,/, $paramHash{type} );
592 0           $addToDataWhere .= 'and (';
593 0           $addToExtWhere .= 'and (';
594 0           while (@typeArray) {
595 0           my $type = shift @typeArray;
596 0           $addToDataWhere .= "data.element_type like '" . $type . "' or ";
597             }
598 0           $addToExtWhere =~ s/\s*or\s*$//g;
599 0           $addToExtWhere .= ')';
600 0           $addToDataWhere =~ s/\s*or\s*$//g;
601 0           $addToDataWhere .= ')';
602             }
603              
604             #
605             # data left join connector
606             #
607 0           my $dataConnector = 'guid_xref.child=data.guid';
608              
609             #
610             # bind critera by child guid, so we are only seeing stuff who's child = #
611             #
612 0 0         if ( $paramHash{childGUID} ) {
613 0           $addToExtWhere .= "and guid_xref.child = '" .
614             $self->safeSQL( $paramHash{childGUID} ) . "' ";
615 0           $addToDataWhere .= "and guid_xref.child = '" .
616             $self->safeSQL( $paramHash{childGUID} ) . "' ";
617 0           $dataConnector = 'guid_xref.parent=data.guid';
618             }
619              
620             #
621             # bind critera by array guid, so we are only seeing stuff who's parent = #
622             #
623 0 0         if ( $paramHash{guid} ) {
624 0           $addToExtWhere .= "and guid_xref.parent = '" .
625             $self->safeSQL( $paramHash{guid} ) . "' ";
626 0           $addToDataWhere .= "and guid_xref.parent = '" .
627             $self->safeSQL( $paramHash{guid} ) . "' ";
628             }
629              
630              
631             #
632             # find data by tags
633             #
634 0 0         if ( $paramHash{tags} ) {
635 0           my @tagsArray = split( /,/, $paramHash{tags} );
636 0           my $tagGUIDs;
637 0           while (@tagsArray) {
638 0           my $checkTag = shift @tagsArray;
639              
640             #
641             # bind by tags Type could be a comma delemented List
642             #
643 0           my %elementHash = $self->_fullElementHash();
644              
645 0           for my $elementType ( keys %elementHash ) {
646 0           my $incTags = $elementHash{$elementType}{tags};
647 0 0 0       if ( ( $incTags =~/^$checkTag$/
      0        
      0        
648             || $incTags =~/^$checkTag,/
649             || $incTags =~/,$checkTag$/
650             || $incTags =~/,$checkTag,$/
651             )
652             && $incTags && $checkTag ) {
653 0           $tagGUIDs .= ',\'' . $elementType . '\'';
654             }
655             }
656             }
657              
658 0           $addToDataWhere .= 'and (data.element_type in (\'\'' . $tagGUIDs . '))';
659 0           $addToExtWhere .= 'and (data.element_type in (\'\'' . $tagGUIDs . '))';
660             }
661              
662              
663             #
664             # add the keywordScore field response
665             #
666 0           my $keywordScoreSQL = '1';
667 0           my $dataCacheSQL = '1';
668 0           my $dataCacheJoin = '';
669              
670             #
671             # if any keywords are added, and create an array of ID's and join them into comma delmited use
672             #
673 0 0         if ( $paramHash{keywords} ) {
674              
675             #
676             # build the field list we will search against
677             #
678 0           my @fieldList = ( 'data_cache.title', 'data_cache.name' );
679 0           for my $key ( keys %{$self->{dataCacheFields}} ) { push @fieldList, 'data_cache.' . $key }
  0            
  0            
680              
681             #
682             # set the cache and join statement starters
683             #
684 0           $dataCacheSQL = 'data_cache.pageIdOfElement';
685 0           $dataCacheJoin = 'left join data_cache on (data_cache.guid=child)';
686              
687             #
688             # do some last minute checking for keywords stablity
689             #
690 0           $paramHash{keywords} =~ s/[^a-zA-Z0-9 \.\-]//sg;
691              
692             #
693             # build the actual keyword chains
694             #
695 0           $addToDataWhere .= " and data.active='1' and (";
696 0           $addToDataWhere .= $self->_getKeywordSQL( $paramHash{keywords}, @fieldList );
697 0           $addToDataWhere .= ")";
698              
699             #
700             # if we are on mysql lets do some fuzzy matching
701             #
702 0 0         if ( $self->{DBType} =~ /^mysql$/i ) {
703 0           $keywordScoreSQL = "(";
704 0           while (@fieldList) {
705 0           $keywordScoreSQL .= "(MATCH (" . $self->safeSQL( shift @fieldList ) . ") AGAINST ('" . $self->safeSQL( $paramHash{keywords} ) . "'))+"
706             }
707 0           $keywordScoreSQL =~ s/\+$//sg;
708 0           $keywordScoreSQL = $keywordScoreSQL . ")+1 as keywordScore";
709             }
710             }
711              
712 0           my @hashArray;
713 0           my $arrayRef = $self->runSQL( SQL => "select distinct " . $keywordScoreSQL . ", " . $dataCacheSQL . ", data.extra_value, data.guid, data.created_date, data.show_mobile, data.lang, guid_xref.site_guid, data.site_guid, data.site_guid, data.active, data.friendly_url, data.page_friendly_url, data.title, data.disable_title, data.default_element, data.disable_edit_mode, data.element_type, data.nav_name, data.name, guid_xref.parent, data.page_guid, guid_xref.layout from guid_xref " . $dataCacheJoin . " left join data on (guid_xref.site_guid='" . $self->safeSQL( $paramHash{siteGUID} ) . "') and " . $dataConnector . " " . $addToDataXRefJoin . " " . $addToExtJoin . " where guid_xref.parent != '' and guid_xref.site_guid is not null " . $addToDataWhere . " order by guid_xref.ord" );
714              
715             #
716             # for speed we will add this to here so we don't have to ask it EVERY single time we loop though the while statemnent
717             #
718 0           my $showMePlease = 0;
719 0 0 0       if (( $paramHash{showAll} || $self->formValue('editMode') eq '1' || $self->formValue('p') =~ /^fws_/) ) { $showMePlease =1 }
  0   0        
720              
721             #
722             # move though the data records creating the individual hashes
723             #
724 0           while (@{$arrayRef}) {
  0            
725 0           my %dataHash;
726              
727 0           my $keywordScore = shift @{$arrayRef};
  0            
728 0           my $pageIdOfElement = shift @{$arrayRef};
  0            
729 0           my $extraValue = shift @{$arrayRef};
  0            
730 0           $dataHash{guid} = shift @{$arrayRef};
  0            
731 0           $dataHash{createdDate} = shift @{$arrayRef};
  0            
732 0           $dataHash{showMobile} = shift @{$arrayRef};
  0            
733 0           $dataHash{lang} = shift @{$arrayRef};
  0            
734 0           $dataHash{guid_xref_site_guid} = shift @{$arrayRef};
  0            
735 0           $dataHash{siteGUID} = shift @{$arrayRef};
  0            
736 0           $dataHash{site_guid} = shift @{$arrayRef};
  0            
737 0           $dataHash{active} = shift @{$arrayRef};
  0            
738 0           $dataHash{friendlyURL} = shift @{$arrayRef};
  0            
739 0           $dataHash{pageFriendlyURL} = shift @{$arrayRef};
  0            
740 0           $dataHash{title} = shift @{$arrayRef};
  0            
741 0           $dataHash{disableTitle} = shift @{$arrayRef};
  0            
742 0           $dataHash{defaultElement} = shift @{$arrayRef};
  0            
743 0           $dataHash{disableEditMode} = shift @{$arrayRef};
  0            
744 0           $dataHash{type} = shift @{$arrayRef};
  0            
745 0           $dataHash{navigationName} = shift @{$arrayRef};
  0            
746 0           $dataHash{name} = shift @{$arrayRef};
  0            
747 0           $dataHash{parent} = shift @{$arrayRef};
  0            
748 0           $dataHash{pageGUID} = shift @{$arrayRef};
  0            
749 0           $dataHash{layout} = shift @{$arrayRef};
  0            
750              
751              
752              
753 0 0 0       if ( $dataHash{active} || ( $showMePlease && $dataHash{siteGUID} eq $paramHash{siteGUID}) || ( $paramHash{siteGUID} ne $dataHash{siteGUID} && $dataHash{active} ) ) {
      0        
      0        
      0        
754              
755             #
756             # twist our legacy statements around. titleOrig isn't legacy - but I don't
757             # know why its here either. We will attempt to deprecate it on the next version
758             #
759 0           $dataHash{element_type} = $dataHash{type};
760 0           $dataHash{titleOrig} = $dataHash{title};
761              
762             #
763             # if the title is blank lets dump the name into it
764             #
765 0   0       $dataHash{title} ||= $dataHash{name};
766              
767             #
768             # add the extended fields and create the hash
769             #
770 0           %dataHash = $self->mergeExtra( $extraValue, %dataHash );
771              
772             #
773             # overwriting these, just in case someone tried to save them in the extended hash
774             #
775 0           $dataHash{keywordScore} = $keywordScore;
776 0           $dataHash{pageIdOfElement} = $pageIdOfElement;
777 0           $dataHash{pageIdOfElement} = $pageIdOfElement;
778              
779             #
780             # push the hash into the array
781             #
782 0           push @hashArray, {%dataHash};
783             }
784             }
785              
786             #
787             # return the reference or the array
788             #
789 0 0         if ( $paramHash{ref} ) { return \@hashArray }
  0            
790 0           return @hashArray;
791             }
792              
793             =head2 dataHash
794              
795             Retrieve a hash or hash reference for a data matching the passed guid. This can only be used after setSiteValues() because it required $fws->{siteGUID} to be defined.
796              
797             #
798             # get the hash itself
799             #
800             my %dataHash = $fws->dataHash( guid => 'someguidsomeguidsomeguid' );
801              
802             #
803             # get a reference to the hash
804             #
805             my $dataHashRef = $fws->dataHash( guid => 'someguidsomeguidsomeguid', ref => 1 );
806              
807             =cut
808              
809             sub dataHash {
810 0     0 1   my ( $self, %paramHash ) = @_;
811              
812             #
813             # set site GUID if it wasn't passed to us
814             #
815 0   0       $paramHash{siteGUID} ||= $self->{siteGUID};
816              
817 0           my $arrayRef = $self->runSQL( SQL => "select data.extra_value, data.element_type, 'pageGUID', data.page_guid, 'lang', lang, 'guid', data.guid, 'pageFriendlyURL', page_friendly_url, 'friendlyURL', friendly_url, 'defaultElement', data.default_element, 'guid_xref_site_guid', data.site_guid, 'showLogin', data.show_login, 'showMobile', data.show_mobile, 'showResubscribe', data.show_resubscribe, 'groupId', data.groups_guid, 'disableEditMode',data.disable_edit_mode, 'siteGUID', data.site_guid, 'site_guid', data.site_guid, 'title', data.title, 'disableTitle', data.disable_title, 'active', data.active, 'navigationName', nav_name, 'name', data.name from data left join site on site.guid=data.site_guid where data.guid='" . $self->safeSQL( $paramHash{guid} ) . "' and (data.site_guid='" . $self->safeSQL( $paramHash{siteGUID} ) . "' or site.sid='fws')" );
818              
819             #
820             # pull off the first two fields because we need to manipulate them
821             #
822 0           my $extraValue = shift @{$arrayRef};
  0            
823 0           my $dataType = shift @{$arrayRef};
  0            
824              
825             #
826             # convert it to a hash
827             #
828 0           my %dataHash = @$arrayRef;
829              
830             #
831             # do some legacy data type switching around. some call it type (wich it should be, and some call it element_type
832             #
833 0           $dataHash{type} = $dataType;
834 0           $dataHash{element_type} = $dataType;
835              
836            
837             #
838             # combine the hash
839             #
840 0           %dataHash = $self->mergeExtra( $extraValue, %dataHash );
841              
842             #
843             # Overwrite the title with the name if it is blank
844             #
845 0   0       $dataHash{title} ||= $dataHash{name};
846              
847             #
848             # return the hash or hash reference
849             #
850 0 0         if ( $paramHash{ref} ) { return \%dataHash }
  0            
851 0           return %dataHash;
852             }
853              
854             =head2 deleteData
855              
856             Delete something from the data table. %dataHash must contain guid and either containerId or parent. By passing noOrphanDelete with a value of 1, any data orphaned from the act of this delete will also be deleted.
857              
858             my %dataHash;
859             $dataHash{noOrphanDelete} = '0';
860             $dataHash{guid} = 'someguid123123123';
861             $dataHash{parent} = 'someparentguid';
862             my %dataHash $fws->deleteData( %dataHash );
863              
864             =cut
865              
866             sub deleteData {
867 0     0 1   my ( $self, %paramHash ) = @_;
868 0           %paramHash = $self->runScript( 'preDeleteData', %paramHash );
869              
870             #
871             # get the sid if one wasn't passed
872             #
873 0   0       $paramHash{siteGUID} ||= $self->{siteGUID};
874              
875             #
876             # transform the containerId to the parent id
877             #
878 0 0         if ( $paramHash{containerId} ) {
879 0           ( $paramHash{parent} ) = @{$self->runSQL( SQL => "select guid from data where name='" . $self->safeSQL( $paramHash{containerId} ) . "' and element_type='data' and site_guid='" . $self->safeSQL( $paramHash{siteGUID} ) . "' LIMIT 1" )};
  0            
880             }
881              
882             #
883             # Kill the xref
884             #
885 0           $self->_deleteXRef( $paramHash{guid}, $paramHash{parent}, $paramHash{siteGUID} );
886              
887             #
888             # Kill any data recrods now orphaned from this process
889             #
890 0           $self->_deleteOrphanedData("guid_xref","child","data","guid");
891              
892             #
893             # if we are cleaning orphans continue
894             #
895 0 0         if ( !$paramHash{noOrphanDelete} ) {
896             #
897             # loop though till we don't see anything dissapear
898             #
899 0           my $keepGoing = 1;
900              
901 0           while ( $keepGoing ) {
902             #
903             # set up the tests
904             #
905 0           my ( $firstTest ) = @{$self->runSQL( SQL => "select count(1) from guid_xref" )};
  0            
906 0           my ( $firstTestData ) = @{$self->runSQL( SQL => "select count(1) from data" )};
  0            
907              
908             #
909             # get rid of any parent that no longer has a perent
910             #
911 0           $self->_deleteOrphanedData( 'guid_xref', 'parent', 'data', 'guid', ' and guid_xref.parent <> \'\'' );
912              
913             #
914             # get rid of any data records that are now orphaned from the above process's
915             #
916 0           $self->_deleteOrphanedData( "data", "guid", "guid_xref", "child");
917              
918             #
919             # if we are not deleting orphans do the checks
920             #
921 0 0         if ( !$paramHash{noOrphanDelete} ) {
922              
923             #
924             # grab a second test to match against
925             #
926 0           my ( $secondTest ) = @{$self->runSQL( SQL => "select count(1) from guid_xref" )};
  0            
927 0           my ( $secondTestData ) = @{$self->runSQL( SQL => "select count(1) from data" )};
  0            
928              
929             #
930             # now that we have a first and second pass. if they have changed keep going, but if nothing happened
931             # lets ditch out of here
932             #
933 0 0 0       if ( $secondTest eq $firstTest && $secondTestData eq $firstTestData ) { $keepGoing = 0 } else { $keepGoing = 1 }
  0            
  0            
934             }
935             }
936             #
937             # Kill any data recrods now orphaned from the cleansing
938             #
939 0           $self->_deleteOrphanedData("guid_xref","child","data","guid");
940             }
941              
942             #
943             # run any post scripts and return what we were passed
944             #
945 0           %paramHash = $self->runScript('postDeleteData',%paramHash);
946 0           return %paramHash;
947             }
948              
949             =head2 deleteHash
950              
951             Remove a hash based on its guid from FWS hash object.
952              
953             =cut
954              
955             sub deleteHash {
956 0     0 1   my ( $self, %paramHash ) = @_;
957              
958             #
959             # get the current array
960             #
961 0           my @hashArray = $self->hashArray(%paramHash);
962 0           my @newArray;
963              
964             #
965             # go though each one of the shippingLocation items, figure out what one is being updated and update it!
966             #
967 0           for my $i (0 .. $#hashArray) {
968              
969             #
970             # update the loc with the same guid with the new hash
971             #
972 0 0         if ( $paramHash{guid} ne $hashArray[$i]{guid} ) { push @newArray, {%{$hashArray[$i]}} }
  0            
  0            
973             }
974 0           return (nfreeze(\@newArray));
975             }
976              
977              
978             =head2 deleteUser
979              
980             Delete a user by passing the guid in as a hash key
981              
982             =cut
983              
984             sub deleteUser {
985 0     0 1   my ( $self, %paramHash ) = @_;
986 0           %paramHash = $self->runScript( 'preDeleteUser', %paramHash );
987 0           $self->runSQL( SQL => "delete from profile where guid='" . $self->safeSQL( $paramHash{guid} ) . "'" );
988 0           %paramHash = $self->runScript( 'preDeleteUser', %paramHash );
989 0           return %paramHash;
990             }
991              
992              
993             =head2 deleteQueue
994              
995             Delete from the message and process queue
996              
997             my %queueHash;
998             $queueHash{guid} = 'someQueueGUID';
999             my %queueHash $fws->deleteQueue( %queueHash );
1000              
1001             =cut
1002              
1003             sub deleteQueue {
1004 0     0 1   my ( $self, %paramHash ) = @_;
1005 0           %paramHash = $self->runScript( 'preDeleteQueue', %paramHash );
1006 0           $self->runSQL( SQL => "delete from queue where guid = '" . $self->safeSQL( $paramHash{guid} ) . "'" );
1007 0           %paramHash = $self->runScript( 'postDeleteQueue', %paramHash );
1008 0           return %paramHash;
1009             }
1010              
1011              
1012             =head2 elementArray
1013              
1014             Return the elements from the database. This will not pull elements from plugins!
1015              
1016             =cut
1017              
1018             sub elementArray {
1019 0     0 1   my ( $self, %paramHash ) = @_;
1020              
1021             #
1022             # array holder for the return
1023             #
1024 0           my @elementArrayReturn;
1025              
1026             #
1027             # the where satement we will be appending to
1028             #
1029             my $addToWhere;
1030              
1031             #
1032             # if we are passed a parent guid we have to match
1033             #
1034 0 0         if ( $paramHash{parent} ) { $addToWhere = " and parent='" . $self->safeSQL( $paramHash{parent} ) . "'" }
  0            
1035              
1036             #
1037             # TODO does this really need be done anymore? 1.3 used 0 numbers
1038             #
1039 0 0         if ( $paramHash{parent} eq '0' ) { $addToWhere = " and parent=''" }
  0            
1040              
1041             #
1042             # match only with matching siteGUID
1043             #
1044 0 0         if ( $paramHash{siteGUID} ) { $addToWhere .= " and site_guid='" . $self->safeSQL( $paramHash{siteGUID} ) . "'" }
  0            
1045              
1046             #
1047             # match only with matching plugin, all other search cretira is overwritten!
1048             # And these plugins are only alowed to be shows if they are the root of a site
1049             #
1050 0 0         if ( $paramHash{plugin} ) {
1051             # TODO update to not use s%, have it actually xref the site table for parents in case later we descide they won't all start with s
1052 0           $addToWhere = " and plugin='" . $self->safeSQL( $paramHash{plugin} ) . "' and parent like 's%'"
1053             }
1054              
1055 0 0         if ( $paramHash{tags} ) {
1056 0           my @tagsArray = split( /,/, $paramHash{tags} );
1057 0           while (@tagsArray) {
1058 0           my $checkTag = shift @tagsArray;
1059             #
1060             # add extra ,'s where any spaces are, that will fill in gaps for the like
1061             #
1062 0           $checkTag =~ s/ //sg;
1063              
1064             #
1065             # add the where with all chanches of like
1066             #
1067 0 0         if ( $checkTag ) {
1068 0           $addToWhere .= " and (tags like '" . $checkTag . "' or tags like '" . $checkTag . ",%' or tags like '%," . $checkTag . "' or tags like '%," . $checkTag . ",%')";
1069             }
1070             }
1071             }
1072              
1073 0 0         if ( $paramHash{keywords} ) {
1074 0           my $keywordSQL = $self->_getKeywordSQL( $paramHash{keywords}, "css_devel", "js_devel", "schema_devel", "script_devel", "title", "type", "guid", "admin_group" );
1075 0 0         if ( $keywordSQL ) { $addToWhere .= ' and ( ' . $keywordSQL . ' ) ' }
  0            
1076             }
1077              
1078             #
1079             # grab the array from the DB
1080             #
1081 0           my ( @elementArray ) = @{$self->runSQL( SQL => "select ord, plugin, admin_group, root_element, site_guid, guid, type, parent, title, schema_devel, script_devel, checkedout from element where 1=1" . $addToWhere . " order by title" )};
  0            
1082            
1083             #
1084             # look at element included in plugins
1085             #
1086 0           for my $guid ( sort { $self->{elementHash}{$a}{alphaOrd} <=> $self->{elementHash}{$b}{alphaOrd} } keys %{$self->{elementHash}}) {
  0            
  0            
1087              
1088 0           my $addElement = 0;
1089 0 0         if ( $paramHash{tags} ) {
1090 0           my @tagsArray = split( /,/, $paramHash{tags} );
1091              
1092 0           while (@tagsArray) {
1093 0           my $checkTag = shift @tagsArray;
1094             #
1095             # add extra ,'s where any spaces are, that will fill in gaps for the like
1096             #
1097 0           $checkTag =~ s/ //sg;
1098 0 0 0       if ( $checkTag && $self->{elementHash}{$guid}{tags} =~ /^$checkTag$/ ) { $addElement = 1 }
  0            
1099             }
1100              
1101 0 0         if ( $addElement ) { push @elementArrayReturn, {%{$self->{elementHash}{$guid}}} }
  0            
  0            
1102             }
1103             }
1104              
1105             #
1106             # loop though the whole thing and push it into the array for return
1107             #
1108 0           my $alphaOrd = 0;
1109 0           while (@elementArray) {
1110 0           my %elementHash;
1111 0           $alphaOrd++;
1112 0           $elementHash{ord} = shift @elementArray;
1113 0           $elementHash{plugin} = shift @elementArray;
1114 0           $elementHash{adminGroup} = shift @elementArray;
1115 0           $elementHash{rootElement} = shift @elementArray;
1116 0           $elementHash{siteGUID} = shift @elementArray;
1117 0           $elementHash{guid} = shift @elementArray;
1118 0           $elementHash{type} = shift @elementArray;
1119 0           $elementHash{parent} = shift @elementArray;
1120 0           $elementHash{title} = shift @elementArray;
1121 0           $elementHash{schemaDevel} = shift @elementArray;
1122 0           $elementHash{scriptDevel} = shift @elementArray;
1123 0           $elementHash{checkedout} = shift @elementArray;
1124 0           $elementHash{alphaOrd} = $alphaOrd;
1125 0           $elementHash{label} = $elementHash{type} . ' - ' . $elementHash{title};
1126 0 0         if ( !$elementHash{type} ) { $elementHash{label} = 'element' . $elementHash{label} }
  0            
1127              
1128 0           push @elementArrayReturn, {%elementHash};
1129             }
1130              
1131 0           return @elementArrayReturn;
1132             }
1133              
1134              
1135             =head2 elementHash
1136              
1137             Return the hash for an element from cache, plugin for element database
1138              
1139             =cut
1140              
1141             sub elementHash {
1142 0     0 1   my ( $self, %paramHash ) = @_;
1143              
1144 0 0         if ( !$self->{elementHash}->{$paramHash{guid}}{guid} ) {
1145              
1146             #
1147             # add to element guid or type
1148             #
1149 0           my $addToWhere = "guid='" . $self->safeSQL( $paramHash{guid} ) . "'";
1150 0 0         if ( $paramHash{guid} ) { $addToWhere .= " or type='" . $self->safeSQL( $paramHash{guid} ) . "'" }
  0            
1151              
1152             #
1153             # get tha hash from the DB
1154             #
1155 0           my (@scriptArray) = @{$self->runSQL( SQL => "select 'plugin', plugin, 'jsDevel', js_devel, 'cssDevel', css_devel, 'adminGroup', admin_group, 'classPrefix', class_prefix, 'siteGUID', site_guid, 'guid', guid, 'ord', ord, 'tags', tags, 'public', public, 'rootElement', root_element, 'type', type, 'parent', parent, 'title', title, 'schemaDevel', schema_devel, 'scriptDevel', script_devel, 'checkedout', checkedout from element where " . $addToWhere . " order by ord limit 1" )};
  0            
1156              
1157             #
1158             # create the hash and return it
1159             #
1160 0           %{$self->{elementHash}->{$paramHash{guid}}} = @scriptArray;
  0            
1161             }
1162              
1163 0           return %{$self->{elementHash}->{$paramHash{guid}}};
  0            
1164             }
1165              
1166             =head2 exportCSV
1167              
1168             Return a hash array in a csv format.
1169              
1170             my $csv = $fws->exportCSV( dataArray => [@someArray] );
1171              
1172             =cut
1173              
1174             sub exportCSV {
1175 0     0 1   my ( $self, %paramHash ) = @_;
1176              
1177             #
1178             # pull the array out of the hash and find out the keys
1179             #
1180 0           my @dataArray = @{$paramHash{dataArray}};
  0            
1181 0           my %theKeys;
1182 0           for my $i (0 .. $#dataArray) {
1183 0           for my $key ( keys %{$dataArray[$i]}) {
  0            
1184 0 0         if ( $key !~ /^(guid|killSession)$/ ) { $theKeys{$key} =1 }
  0            
1185             }
1186             }
1187              
1188             #
1189             # create the header
1190             #
1191 0           my $returnString = 'guid,';
1192 0           for my $key ( sort keys %theKeys) { $returnString .= $key . ',' }
  0            
1193 0           $returnString .= "\n";
1194              
1195             #
1196             # create the list for everything else
1197             #
1198 0           for my $i (0 .. $#dataArray) {
1199 0           $returnString .= $dataArray[$i]{guid} . ',';
1200              
1201             #
1202             # kill anything that is a blank date and aggressivly clean up anything
1203             # could break a csv
1204             #
1205 0           for my $key ( sort keys %theKeys) {
1206 0           $dataArray[$i]{$key} =~ s/(,|;)/ /sg;
1207 0           $dataArray[$i]{$key} =~ s/(\n|\r)//sg;
1208 0           $dataArray[$i]{$key} =~ s/^(0000.00.00.*|'|")//sg;
1209 0           $returnString .= $dataArray[$i]{$key} . ',';
1210             }
1211 0           $returnString .= "\n";
1212             }
1213              
1214             #
1215             # kill the trailing comma and return the string
1216             #
1217 0           $returnString =~ s/,$//sg;
1218 0           return $returnString . "\n";
1219             }
1220              
1221              
1222             =head2 flushSearchCache
1223              
1224             Delete all cached data and rebuild it from scratch. Will return the number of records it optimized. If no siteGUID was passed then the one from the current site being rendered is used
1225              
1226             print $fws->flushSearchCache( $fws->{siteGUID} );
1227              
1228             This also will set the parent id of the data record if it is not already set
1229              
1230             =cut
1231              
1232             sub flushSearchCache {
1233 0     0 1   my ( $self, $siteGUID ) = @_;
1234              
1235             #
1236             # set the site guid if it wasn't passed
1237             #
1238 0   0       $siteGUID ||= $self->{siteGUID};
1239              
1240             #
1241             # before we do anything lets get the cache fields reset
1242             #
1243 0           $self->setCacheIndex();
1244              
1245             #
1246             # drop the current data
1247             #
1248 0           $self->runSQL( SQL => "delete from data_cache where site_guid='" . $self->safeSQL( $siteGUID ) . "'" );
1249              
1250             #
1251             # lets make the stuff we might need
1252             #
1253 0           my %dataCacheFields = %{$self->{dataCacheFields}};
  0            
1254 0           foreach my $key ( keys %dataCacheFields ) {
1255 0           $self->alterTable( table => "data_cache", field => $key, type => "text", key => "FULLTEXT", default => "" );
1256             }
1257              
1258             #
1259             # have a counter so we can see how much work we did
1260             #
1261 0           my $dataUnits = 0;
1262              
1263             #
1264             # get a list of the current data, and update the cache for each one
1265             #
1266 0           my $dataArray = $self->runSQL( SQL => "select guid from data where site_guid='" . $self->safeSQL( $siteGUID ) . "'");
1267 0           while (@$dataArray) {
1268 0           my $guid = shift @{$dataArray};
  0            
1269 0           my %dataHash = $self->dataHash( guid => $guid );
1270 0           $self->updateDataCache( %dataHash );
1271 0           $dataUnits++;
1272             }
1273 0           return $dataUnits;
1274             }
1275              
1276              
1277             =head2 getSiteGUID
1278              
1279             Get the site GUID for a site by passing the SID of that site. If the SID does not exist it will return an empty string.
1280              
1281             print $fws->getSiteGUID( 'somesite' );
1282              
1283             NOTE: This should not be used and will eventually be pulled in as a FWS internal method only, but is available for legacy reasons.
1284              
1285             =cut
1286              
1287             sub getSiteGUID {
1288 0     0 1   my ( $self, $sid ) = @_;
1289             #
1290             # get the ID to the sid for site ids these always match the corrisponding sid
1291             #
1292 0           my ( $guid ) = @{$self->runSQL( SQL => "select guid from site where sid='" . $self->safeSQL( $sid ) . "'" )};
  0            
1293 0           return $guid;
1294             }
1295              
1296              
1297             =head2 hashArray
1298              
1299             Return a FWS Hash in its array format.
1300              
1301             =cut
1302              
1303             sub hashArray {
1304 0     0 1   my ( $self, %paramHash ) = @_;
1305              
1306 1     1   15 use Storable qw(nfreeze thaw);
  1         2  
  1         3427  
1307              
1308 0 0         if ( $paramHash{hashArray} ) {
1309             #
1310             # get the current array, and clear the loc string
1311             #
1312 0           return @{thaw( $paramHash{hashArray} )};
  0            
1313             }
1314              
1315 0           return;
1316             }
1317              
1318              
1319             =head2 createFWSDatabase
1320              
1321             Do a new database check and then create the base records for a new install of FWS if the database doesn't have an admin record. The return is the HTML that would render for a browser to let them know what just happened.
1322              
1323             This will auto trigger a flag to only it allow it to execute once so it doesn't recurse itself.
1324              
1325             =cut
1326              
1327             sub createFWSDatabase {
1328 0     0 1   my ( $self ) = @_;
1329              
1330             #
1331             # make sure I didn't do this yet
1332             #
1333 0 0         if ( !$self->{createFWSDatabaseRan} ) {
1334            
1335             #
1336             # Set this flag so we know if we changed anything
1337             # if we did the return will be the message of what happened
1338             #
1339 0           my $somethingNew = 0;
1340              
1341             #
1342             # make the admin record if not there
1343             #
1344 0           my ( $adminGUID ) = @{$self->runSQL( SQL => "select guid from site where sid='admin'", noUpdate => 1 )};
  0            
1345 0 0         if ( !$adminGUID ) {
1346            
1347             #
1348             # because we don't have an admin we probably don't have a DB at all, lets make it
1349             #
1350 0           $self->updateDatabase();
1351              
1352             #
1353             # now that the db is there, lets do this!
1354             #
1355 0           $adminGUID = $self->createGUID( 's' );
1356 0           $self->runSQL( SQL => "insert into site (guid, sid, site_guid) values ('" . $adminGUID . "', 'admin', '" . $adminGUID . "')" );
1357 0           $somethingNew++;
1358             }
1359            
1360             #
1361             # make the FWS record if not there
1362             #
1363 0           my ( $fwsGUID ) = @{$self->runSQL( SQL => "select guid from site where sid='fws'", noUpdate => 1 )};
  0            
1364 0 0         if ( !$fwsGUID ) {
1365 0           $fwsGUID = $self->createGUID( 'f' );
1366 0           $self->runSQL( SQL => "insert into site (guid, sid, site_guid) values ('" . $fwsGUID . "', 'fws', '" . $adminGUID . "')" );
1367 0           $somethingNew++;
1368             }
1369            
1370             #
1371             # make the default site record if not there
1372             #
1373 0           my ( $siteGUID ) = @{$self->runSQL( SQL => "select guid from site where sid='site'", noUpdate => 1 )};
  0            
1374 0 0         if ( !$siteGUID ) {
1375 0           $siteGUID = $self->createGUID( 's' );
1376 0           $self->runSQL( SQL => "insert into site (guid, sid, default_site, site_guid) values ('" . $siteGUID . "', 'site', '1', '" . $adminGUID . "')" );
1377            
1378             #
1379             # create new home page GUID
1380             #
1381 0           $self->homeGUID( $siteGUID );
1382 0           $somethingNew++;
1383             }
1384            
1385             #
1386             # because there was something new, redirect to the script again now that
1387             # things should be present
1388             #
1389 0 0         if ( $somethingNew ) {
1390 0           print "Status: 302 Found\n";
1391 0           print "Location: " . $self->{scriptName} . "\n\n";
1392             }
1393             }
1394              
1395             #
1396             # in case of DB Recursion we don't want to run this again, flag it up
1397             #
1398 0           $self->{createFWSDatabaseRan} = 1;
1399 0           return;
1400             }
1401              
1402             =head2 queueArray
1403              
1404             Return a hash array of the current items in the processing queue.
1405              
1406             =cut
1407              
1408             sub queueArray {
1409 0     0 1   my ( $self, %paramHash ) = @_;
1410              
1411             #
1412             # set PH's for sql statement
1413             #
1414 0           my $whereStatement = "1 = 1 ";
1415 0           my $keywordSQL;
1416              
1417             #
1418             # Add keywords if they exist to select statement
1419             #
1420 0 0         if ( $paramHash{keywords} ) {
1421 0           $keywordSQL = $self->_getKeywordSQL( $paramHash{keywords}, "queue_from", "queue_to", "from_name", "subject" );
1422 0 0         if ( $keywordSQL ) { $keywordSQL = " and ( " . $keywordSQL . " ) " }
  0            
1423             }
1424              
1425             #
1426             # queuery by directory or user if needed
1427             # add other criteria if applicable
1428             #
1429 0 0         if ( $paramHash{directoryGUID} ) { $whereStatement .= " and directory_guid = '" . $self->safeSQL( $paramHash{directoryGUID} ) . "'" }
  0            
1430 0 0         if ( $paramHash{userGUID} ) { $whereStatement .= " and profile_guid = '" . $self->safeSQL( $paramHash{userGUID} ) . "'" }
  0            
1431 0 0         if ( $paramHash{from} ) { $whereStatement .= " and queue_from = '" . $self->safeSQL( $paramHash{from} ) . "'" }
  0            
1432 0 0         if ( $paramHash{to} ) { $whereStatement .= " and queue_to = '" . $self->safeSQL( $paramHash{to} ) . "'" }
  0            
1433 0 0         if ( $paramHash{fromName} ) { $whereStatement .= " and from_name = '" . $self->safeSQL( $paramHash{fromName} ) . "'" }
  0            
1434 0 0         if ( $paramHash{subject} ) { $whereStatement .= " and subject = '" . $self->safeSQL( $paramHash{subject} ) . "'" }
  0            
1435 0 0         if ( $paramHash{type} ) { $whereStatement .= " and type = '" . $self->safeSQL( $paramHash{type} ) . "'" }
  0            
1436              
1437             #
1438             # add date critiria if appicable
1439             #
1440 0   0       $paramHash{dateFrom} ||= "0000-00-00 00:00:00";
1441 0   0       $paramHash{dateTo} ||= $self->formatDate( format => 'SQL' );
1442 0           $whereStatement .= " and scheduled_date <= '" . $self->safeSQL( $paramHash{dateTo} ) . "'";
1443 0           $whereStatement .= " and scheduled_date >= '" . $self->safeSQL( $paramHash{dateFrom} ) . "'";
1444              
1445 0           my $arrayRef = $self->runSQL( SQL => "select profile_guid,directory_guid,guid,type,hash,draft,from_name,queue_from,queue_to,body,subject,digital_assets,transfer_encoding,mime_type,scheduled_date from queue where " . $whereStatement . $keywordSQL . " ORDER BY scheduled_date DESC" );
1446 0           my @queueArray;
1447 0           while ( @{$arrayRef} ) {
  0            
1448 0           my %sendHash;
1449 0           $sendHash{userGUID} = shift @{$arrayRef};
  0            
1450 0           $sendHash{directoryGUID} = shift @{$arrayRef};
  0            
1451 0           $sendHash{guid} = shift @{$arrayRef};
  0            
1452 0           $sendHash{type} = shift @{$arrayRef};
  0            
1453 0           $sendHash{hash} = shift @{$arrayRef};
  0            
1454 0           $sendHash{draft} = shift @{$arrayRef};
  0            
1455 0           $sendHash{fromName} = shift @{$arrayRef};
  0            
1456 0           $sendHash{from} = shift @{$arrayRef};
  0            
1457 0           $sendHash{to} = shift @{$arrayRef};
  0            
1458 0           $sendHash{body} = shift @{$arrayRef};
  0            
1459 0           $sendHash{subject} = shift @{$arrayRef};
  0            
1460 0           $sendHash{digitalAssets} = shift @{$arrayRef};
  0            
1461 0           $sendHash{transferEncoding} = shift @{$arrayRef};
  0            
1462 0           $sendHash{mimeType} = shift @{$arrayRef};
  0            
1463 0           $sendHash{scheduledDate} = shift @{$arrayRef};
  0            
1464 0           push @queueArray, {%sendHash};
1465             }
1466 0 0         if ( $paramHash{ref} ) { return \@queueArray }
  0            
1467 0           return @queueArray;
1468             }
1469              
1470             =head2 queueHash
1471              
1472             Return a hash or reference to the a queue hash.
1473              
1474             =cut
1475              
1476             sub queueHash {
1477 0     0 1   my ( $self, %paramHash ) = @_;
1478              
1479             #
1480             # get an array of the all stuff we need, in a name\value pair format
1481             #
1482 0           my $arrayRef = $self->runSQL( SQL => "select 'directoryGUID',directory_guid,'userGUID',profile_guid,'hash',hash,'guid',guid,'draft',draft,'fromName',from_name,'from',queue_from,'to',queue_to,'body',body,'subject',subject,'digitalAssets',digital_assets,'transferEncoding',transfer_encoding,'mimeType',mime_type,'scheduledDate',scheduled_date from queue where guid='" . $self->safeSQL( $paramHash{guid} ) . "'" );
1483              
1484             #
1485             # convert the array to a hash
1486             #
1487 0           my %itemHash = @$arrayRef;
1488              
1489 0 0         if ( $paramHash{ref} ) { return \%itemHash }
  0            
1490 0           return %itemHash;
1491             }
1492              
1493              
1494             =head2 queueHistoryArray
1495              
1496             Return a hash array of the history items from the processing queue.
1497              
1498             Parmeters to constrain data:
1499              
1500             =over 4
1501              
1502             =item * limit
1503              
1504             Maximum number of records to return.
1505              
1506             =item * email
1507              
1508             Only items that were sent to or from an email account specified.
1509              
1510             =item * synced
1511              
1512             Only items that match the sync flaged that is passed. [0|1]
1513              
1514             =item * userGUID
1515              
1516             Only items created from this user.
1517              
1518             =item * directoryGUID
1519              
1520             Only items referencing this directory record.
1521              
1522             =back
1523              
1524             =cut
1525              
1526             sub queueHistoryArray {
1527 0     0 1   my ( $self, %paramHash ) = @_;
1528              
1529             #
1530             # set SQL PH's
1531             #
1532 0           my $whereStatement = '1=1';
1533 0           my $limitSQL;
1534            
1535             #
1536             # create sql where and limits
1537             #
1538 0 0         if ( $paramHash{limit} ) { $limitSQL = ' LIMIT ' . $self->safeSQL( $paramHash{limit} ) }
  0            
1539 0 0         if ( $paramHash{email} ) { $whereStatement .= " and (queue_from like '" . $self->safeSQL( $paramHash{email} ) . "' or queue_to like '" . $self->safeSQL( $paramHash{email} ) . "')" }
  0            
1540 0 0         if ( $paramHash{userGUID} ) { $whereStatement .= " and profile_guid='" . $self->safeSQL( $paramHash{userGUID} ) . "'" }
  0            
1541 0 0         if ( $paramHash{directoryGUID} ) { $whereStatement .= " and directory_guid='" . $self->safeSQL( $paramHash{directoryGUID} ) . "'" }
  0            
1542 0 0         if ( $paramHash{synced} ) { $whereStatement .= " and synced='" . $self->safeSQL( $paramHash{synced} ) . "'" }
  0            
1543              
1544 0           my @queueHistoryArray;
1545 0           my $arrayRef = $self->runSQL( SQL => "select queue_guid, profile_guid, queue_guid, directory_guid, guid, hash, queue_from, queue_to, type, subject, success, synced, failure_code, response, sent_date, scheduled_date from queue_history where " . $whereStatement . " order by sent_date desc" . $limitSQL );
1546              
1547 0           while ( @{$arrayRef} ) {
  0            
1548 0           my %sendHash;
1549 0           $sendHash{guidGUID} = shift @{$arrayRef};
  0            
1550 0           $sendHash{userGUID} = shift @{$arrayRef};
  0            
1551 0           $sendHash{queueGUID} = shift @{$arrayRef};
  0            
1552 0           $sendHash{directoryGUID} = shift @{$arrayRef};
  0            
1553 0           $sendHash{guid} = shift @{$arrayRef};
  0            
1554 0           $sendHash{hash} = shift @{$arrayRef};
  0            
1555 0           $sendHash{from} = shift @{$arrayRef};
  0            
1556 0           $sendHash{to} = shift @{$arrayRef};
  0            
1557 0           $sendHash{type} = shift @{$arrayRef};
  0            
1558 0           $sendHash{subject} = shift @{$arrayRef};
  0            
1559 0           $sendHash{success} = shift @{$arrayRef};
  0            
1560 0           $sendHash{synced} = shift @{$arrayRef};
  0            
1561 0           $sendHash{failureCode} = shift @{$arrayRef};
  0            
1562 0           $sendHash{response} = shift @{$arrayRef};
  0            
1563 0           $sendHash{sentDate} = shift @{$arrayRef};
  0            
1564 0           $sendHash{scheduledDate} = shift @{$arrayRef};
  0            
1565 0           push @queueHistoryArray, {%sendHash};
1566             }
1567 0 0         if ( $paramHash{ref} ) { return \@queueHistoryArray }
  0            
1568 0           return @queueHistoryArray;
1569             }
1570              
1571             =head2 queueHistoryHash
1572              
1573             Return a hash or reference to the a queue history hash. History hashes will be referenced by passing a guid key or if present a queueGUID key from the derived queue record it was created from.
1574              
1575             =cut;
1576              
1577             sub queueHistoryHash {
1578 0     0 1   my ( $self, %paramHash ) = @_;
1579              
1580             #
1581             # get the historyHash based on the queueGUID it was dirived from if that what is being used for
1582             # if not just treat it like any ole hash lookup
1583             #
1584 0           my $whereStatement = "guid='" . $self->safeSQL( $paramHash{guid} ) . "'";
1585 0 0         if ( $paramHash{queueGUID} ) { $whereStatement = "queue_guid='" . $self->safeSQL( $paramHash{queueGUID} ) . "'" }
  0            
1586              
1587             #
1588             # get an array of the all stuff we need, in a name\value pair format
1589             #
1590 0           my $arrayRef = $self->runSQL( SQL => "select 'hash',hash,'guid',guid,'scheduledDate',scheduled_date,'queueGUID',queue_guid,'from',queue_from,'to',queue_to,'failureCode',failure_code,'body',body,'synced',synced,'success',success,'response',response,'subject',subject,'sentDate',sent_date from queue_history where " . $whereStatement );
1591              
1592             #
1593             # convert the array
1594             #
1595 0           my %itemHash = @$arrayRef;
1596              
1597 0 0         if ( $paramHash{ref} ) { return \%itemHash }
  0            
1598 0           return %itemHash;
1599             }
1600              
1601              
1602             =head2 processQueue
1603              
1604             Process the internal sending queue
1605              
1606             #
1607             # process the internal queue
1608             #
1609             $fws->processQueue();
1610              
1611             =cut
1612              
1613             sub processQueue {
1614 0     0 1   my ( $self ) = @_;
1615             #
1616             # get the queue
1617             #
1618 0           my @queueArray = $self->queueArray();
1619              
1620             #
1621             # make sure its not a draft, or if the type is
1622             # blank and sendmail, then ship it off!
1623             #
1624 0           for my $i (0 .. $#queueArray) {
1625 0 0 0       if ( !$queueArray[$i]{draft} && ( !$queueArray[$i]{type} || $queueArray[$i]{type} eq 'sendmail')) {
      0        
1626 0           $queueArray[$i]{fromQueue} = 1;
1627 0           $self->send( %{$queueArray[$i]} );
  0            
1628 0           $self->deleteQueue( %{$queueArray[$i]} );
  0            
1629             }
1630             }
1631 0           return;
1632             }
1633              
1634              
1635             =head2 runSQL
1636              
1637             Return an reference to an array that contains the results of the SQL ran. In addition if you pass noUpdate => 1 the method will not run updateDatabase on errors. This is important if you doing something that could create a recursion problem.
1638              
1639             #
1640             # retrieve a reference to an array of data we asked for
1641             #
1642             my $dataArray = $fws->runSQL( SQL => "select id,type from id_and_type_table" ); # Any SQL statement or query
1643              
1644             #
1645             # loop though the array
1646             #
1647             while ( @$dataArray ) {
1648              
1649             #
1650             # collect the data each row at a time
1651             #
1652             my $id = shift @{$dataArray};
1653             my $type = shift @{$dataArray};
1654              
1655             #
1656             # display or do something with the data
1657             #
1658             print "ID: " . $id . " - " . $type . "\n";
1659             }
1660              
1661              
1662             =cut
1663              
1664             sub runSQL {
1665 0     0 1   my ( $self, %paramHash ) = @_;
1666              
1667             #
1668             # Make sure we are connected to the default DBH
1669             #
1670 0           $self->connectDBH();
1671              
1672             #
1673             # if we pass a DBH lets use it
1674             #
1675 0   0       $paramHash{DBH} ||= $self->{'_DBH_' . $self->{DBName} . $self->{DBHost}};
1676              
1677             #
1678             # Get this data array ready to slurp
1679             # and set the failFlag for future use to autocreate a dB schema
1680             # based on a default setting
1681             #
1682 0           my @data;
1683              
1684             #
1685             # send this off to the log
1686             #
1687 0           $self->SQLLog( $paramHash{SQL} );
1688              
1689             #
1690             # prepare the SQL and loop though the arrays
1691             #
1692 0           my $sth = $paramHash{DBH}->prepare( $paramHash{SQL} );
1693 0 0         if ( $sth ) {
1694              
1695             #
1696             # ensure errors are turned off and execute
1697             #
1698 0           $sth->{PrintError} = 0;
1699 0           $sth->execute();
1700              
1701             #
1702             # only continue if there is no errors
1703             # and we are doing something warrents fetching
1704             #
1705 0 0 0       if ( !$sth->errstr && $paramHash{SQL} =~ /^[\n\r\s]*(select|desc|show) /is ) {
1706              
1707             #
1708             # SQL lite gathing and normilization
1709             #
1710 0 0         if ( $self->{DBType} =~ /^SQLite$/i ) {
1711 0           while ( my @row = $sth->fetchrow ) {
1712 0           my @cleanRow;
1713 0           while ( @row ) {
1714 0           my $clean = shift @row;
1715 0 0         $clean = '' if !defined $clean;
1716 0           $clean =~ s/\\\\/\\/sg;
1717 0           push @cleanRow, $clean;
1718             }
1719 0           push @data, @cleanRow;
1720             }
1721             }
1722            
1723             #
1724             # Fault to MySQL if we didn't find another type
1725             #
1726             else {
1727 0           while ( my @row = $sth->fetchrow ) {
1728 0           my @cleanRow;
1729 0           while ( @row ) {
1730 0           my $clean = shift @row;
1731 0 0         $clean = '' if !defined $clean;
1732 0           push @cleanRow, $clean;
1733             }
1734 0           push @data, @cleanRow;
1735             }
1736             }
1737             }
1738             }
1739              
1740             #
1741             # if errstr is populated, lets EXPLODE!
1742             # but not if its fetch without windows 7 will give this genericly when
1743             # returns without records are passed
1744             #
1745 0 0         if ( $sth->errstr ){
1746 0           $self->FWSLog( 'DB SQL error: ' . $paramHash{SQL} . ': ' . $sth->errstr );
1747              
1748             #
1749             # run update DB on an error to fix anything that was broke :(
1750             # if noUpdate is passed lets not do this, so we do recurse!
1751             #
1752 0 0         if ( !$paramHash{noUpdate} ) { $self->FWSLog( 'DB update ran: ' . $self->updateDatabase() ) }
  0            
1753             }
1754              
1755             #
1756             # return this back as a normal array
1757             #
1758 0           return \@data;
1759             }
1760              
1761             =head2 saveData
1762              
1763             Update or create a new data record. If guid is not provided then a new record will be created. If you pass "newGUID" as a parameter for a new record, the new guid will not be auto generated, newGUID will be used.
1764              
1765             %dataHash = $fws->saveData( %dataHash );
1766              
1767             Required hash keys if the data is new:
1768              
1769             =over 4
1770              
1771             =item * parent: This is the reference to where the data belongs
1772              
1773             =item * name: This is the reference id for the record
1774              
1775             =item * type: A valid element type
1776              
1777             =back
1778              
1779             Not required hash keys:
1780              
1781             =over 4
1782              
1783             =item * $active: 0 or 1. Default is 0 if not specified
1784              
1785             =item * newGUID: If this is a new record, use this guid (Note: There is no internal checking to make sure this is unique)
1786              
1787             =item * lang: Two letter language definition. (Not needed for most multi-lingual sites, only if the code has a requirement that it is splitting language based on other criteria in the control)
1788              
1789             =item * ... Any other extended data fields you want to save with the data element
1790              
1791             =back
1792              
1793              
1794             Example of adding a data record
1795              
1796             my %paramHash;
1797             $paramHash{parent} = $fws->formValue( 'guid' );
1798             $paramHash{active} = 1;
1799             $paramHash{name} = $fws->formValue( 'name' );
1800             $paramHash{title} = $fws->formValue( 'title' );
1801             $paramHash{type} = 'site_myElement';
1802             $paramHash{color} = 'red';
1803              
1804             %paramHash = $fws->saveData(%paramHash);
1805              
1806             Example of adding the same data record to a "data container"
1807              
1808             my %paramHash;
1809             $paramHash{containerId} = 'thisReference';
1810             $paramHash{active} = 1;
1811             $paramHash{name} = $fws->formValue( 'name' );
1812             $paramHash{type} = 'site_thisType';
1813             $paramHash{title} = $fws->formValue( 'title' );
1814             $paramHash{color} = 'red';
1815              
1816             %paramHash = $fws->saveData(%paramHash);
1817              
1818             Note: If the containerId does not match or exist, then one will be created in the root of your site, and the data will be added to the new one.
1819              
1820             Example of updating a data record:
1821              
1822             $guid = 'someGUIDaaaaabbbbccccc';
1823            
1824             #
1825             # get the original hash
1826             #
1827             my %dataHash = $fws->dataHash(guid=>$guid);
1828            
1829             #
1830             # make some changes
1831             #
1832             $dataHash{name} = "New Reference Name";
1833             $dataHash{color} = "blue";
1834            
1835             #
1836             # Give the altered hash to the update procedure
1837             #
1838             $fws->saveData( %dataHash );
1839              
1840             =cut
1841              
1842             sub saveData {
1843 0     0 1   my ( $self, %paramHash ) = @_;
1844              
1845             #
1846             # run any pre scripts and return what we were passed
1847             #
1848 0           %paramHash = $self->runScript('preSaveData',%paramHash);
1849              
1850             #
1851             # if siteGUID is blank, lets set it to the site we are looking at
1852             #
1853 0   0       $paramHash{siteGUID} ||= $self->{siteGUID};
1854              
1855             #
1856             # transform the containerId to the parent id
1857             #
1858 0 0         if ( $paramHash{containerId} ) {
1859             #
1860             # if we don't have a container for it already, lets make one!
1861             #
1862 0           ( $paramHash{parent} ) = @{$self->runSQL( SQL => "select guid from data where name='" . $self->safeSQL( $paramHash{containerId} ) . "' and element_type='data' LIMIT 1" )};
  0            
1863 0 0         if ( !$paramHash{parent} ) {
1864              
1865             #
1866             # recursive!!!! but because containerId isn't passed we are good :)
1867             #
1868 0           my %parentHash = $self->saveData( name => $paramHash{containerId}, type => 'data', parent => $self->siteValue( 'homeGUID' ), layout => '0' );
1869              
1870             #
1871             # set the parent to the new guid
1872             #
1873 0           $paramHash{parent} = $parentHash{guid};
1874             }
1875              
1876             #
1877             # get rid of the containerId, and lets continue with a normal update
1878             #
1879 0           delete( $paramHash{containerId} );
1880             }
1881              
1882             #
1883             # check to see if its already used;
1884             #
1885 0           my %usedHash = $self->dataHash( guid => $paramHash{guid} );
1886              
1887             #
1888             # Lets check the "new guid" if there is one, if it matches, this is an update also
1889             #
1890 0 0 0       if ( !$usedHash{guid} && !$paramHash{newGUID} ) {
1891 0           %usedHash = $self->dataHash( guid => $paramHash{newGUID} );
1892 0 0         if ( $usedHash{guid} ) { $paramHash{guid} = $paramHash{newGUID} }
  0            
1893             }
1894              
1895             #
1896             # if there is no ID this is an add, else, its really just an updateData
1897             #
1898 0 0         if ( !$usedHash{guid} ) {
1899             #
1900             # set the active to false if its not specified
1901             #
1902 0 0         if ( !$paramHash{active} ) { $paramHash{active} = '0' }
  0            
1903              
1904             #
1905             # get the intial ID and insert the record
1906             #
1907 0 0         if ( $paramHash{newGUID} ) { $paramHash{guid} = $paramHash{newGUID} }
  0 0          
1908 0           elsif ( !$paramHash{guid} ) { $paramHash{guid} = $self->createGUID( 'd' ) }
1909              
1910             #
1911             # if title is blank make it the name;
1912             #
1913 0 0         if ( !$paramHash{title} ) { $paramHash{title} = $paramHash{name} }
  0            
1914              
1915              
1916             #
1917             # insert the record
1918             #
1919 0           $self->runSQL( SQL => "insert into data (guid,site_guid,created_date) values ('" . $self->safeSQL( $paramHash{guid} ) . "','" . $self->safeSQL( $paramHash{siteGUID} ) . "','" . $self->formatDate( format => 'SQL' ) . "')");
1920             }
1921              
1922             #
1923             # get the next in the org, so it will be at the end of the list
1924             #
1925 0 0         if ( !$paramHash{ord} ) {
1926 0           ( $paramHash{ord} ) = @{$self->runSQL( SQL => "select max( ord ) + 1 from guid_xref where site_guid='" . $self->safeSQL( $paramHash{siteGUID} ) . "' and parent='" . $self->safeSQL( $paramHash{parent} ) . "'")};
  0            
1927             }
1928            
1929             #
1930             # if layout is ever blank, set it to main as a default
1931             #
1932 0   0       $paramHash{layout} ||= 'main';
1933              
1934             #
1935             # if we are talking a type of page or home, set layout to 0 because it should not be used
1936             #
1937 0 0 0       if ( $paramHash{type} eq 'page' || $paramHash{type} eq 'home' ) {
1938 0           $paramHash{layout} = '0';
1939             }
1940              
1941             #
1942             # add the xref record if it needs to... BUT! only pages are aloud to have blank parents, everything else needs a parent
1943             #
1944 0 0 0       if ( $paramHash{type} eq 'home' || $paramHash{parent} ) {
1945 0           $self->_saveXRef( $paramHash{guid}, $paramHash{layout}, $paramHash{ord}, $paramHash{parent}, $paramHash{siteGUID} );
1946             }
1947              
1948             #
1949             # if we are talking about a home page, then we actually need to set this as "page"
1950             #
1951 0 0         if ( $paramHash{type} eq 'home' ) { $paramHash{type} ='page' }
  0            
1952            
1953             #
1954             # now before we added something new we might need a new index, lets reset it for good measure
1955             #
1956 0           $self->setCacheIndex();
1957            
1958             #
1959             # set default to ensure we don't explode with SQL errors from default defs
1960             #
1961 0   0       $paramHash{showMobile} ||= 0;
1962 0   0       $paramHash{showLogin} ||= 0;
1963 0   0       $paramHash{default_element} ||= 0;
1964 0   0       $paramHash{disableTitle} ||= 0;
1965 0   0       $paramHash{disableEditMode} ||= 0;
1966              
1967             #
1968             # Save the data minus the extra fields
1969             #
1970 0           $self->runSQL( SQL => "update data set " .
1971             "extra_value = ''" .
1972             ", show_mobile = '" . $self->safeSQL( $paramHash{showMobile} ) . "'" .
1973             ", show_login = '" . $self->safeSQL( $paramHash{showLogin} ) . "'" .
1974             ", default_element = '" . $self->safeSQL( $paramHash{default_element} ) . "'" .
1975             ", disable_title = '" . $self->safeSQL( $paramHash{disableTitle} ) . "'" .
1976             ", disable_edit_mode = '" . $self->safeSQL( $paramHash{disableEditMode} ) . "'" .
1977             ", disable_title = '" . $self->safeSQL( $paramHash{disableTitle} ) . "'" .
1978             ", lang = '" . $self->safeSQL( $paramHash{lang} ) . "'" .
1979             ", friendly_url = '" . $self->safeSQL( $paramHash{friendlyURL} ) . "'" .
1980             ", page_friendly_url = '" . $self->safeSQL( $paramHash{pageFriendlyURL} ) . "'" .
1981             ", active = '" . $self->safeSQL( $paramHash{active} ) . "'" .
1982             ", nav_name = '" . $self->safeSQL( $paramHash{navigationName} ) . "'" .
1983             ", name = '" . $self->safeSQL( $paramHash{name} ) . "'" .
1984             ", title = '" . $self->safeSQL( $paramHash{title} ) . "'" .
1985             ", element_type = '" . $self->safeSQL( $paramHash{type} ) . "' " .
1986             "where guid = '" . $self->safeSQL( $paramHash{guid} ) . "' and site_guid = '" . $self->safeSQL( $paramHash{siteGUID}) . "'"
1987             );
1988              
1989             #
1990             # loop though and update every one that is diffrent
1991             #
1992 0           for my $key ( keys %paramHash ) {
1993 0 0         if ( $key !~ /^ord|pageIdOfElement|keywordScore|navigationName|showResubscribe|default_element|guid_xref_site_guid|groupId|lang|friendlyURL|pageFriendlyURL|type|guid|siteGUID|newGUID|showMobile|name|element_type|active|title|disableTitle|disableEditMode|defaultElement|showLogin|parent|layout|site_guid$/ ) {
1994 0           $self->saveExtra( table => 'data', siteGUID => $paramHash{siteGUID}, guid => $paramHash{guid}, field => $key, value => $paramHash{$key} );
1995             }
1996             }
1997              
1998             #
1999             # update the modified stamp
2000             #
2001 0           $self->updateModifiedDate(%paramHash);
2002              
2003             #
2004             # update the cache data directly
2005             #
2006 0           $self->updateDataCache(%paramHash);
2007              
2008             #
2009             # run any post scripts
2010             #
2011 0           %paramHash = $self->runScript('postSaveData',%paramHash);
2012              
2013             #
2014             # return anything created in the paramHash that was changed and already present
2015             #
2016 0           return %paramHash;
2017             }
2018              
2019              
2020             =head2 saveExtra
2021              
2022             Save data that is part of the extra hash for a FWS table.
2023              
2024             $self->saveExtra(
2025             table => 'table_name',
2026             siteGUID => 'site_guid_not_required',
2027             guid => 'some_guid',
2028             field => 'table_field',
2029             value => 'the value we are setting it to'
2030             );
2031              
2032             =cut
2033              
2034             sub saveExtra {
2035 0     0 1   my ( $self, %paramHash ) = @_;
2036              
2037             #
2038             # set site GUID if it wasn't passed to us
2039             #
2040 0   0       $paramHash{siteGUID} ||= $self->{siteGUID};
2041              
2042             #
2043             # set up the site_sid restriction... but a lot of table types don't use
2044             #
2045 0           my $addToWhere = " and site_guid='" . $self->safeSQL( $paramHash{siteGUID} ) . "'";
2046 0 0         if ( $self->{dataSchema}{$paramHash{table}}{site_guid}{noSite} ) { $addToWhere = '' }
  0            
2047              
2048             #
2049             # get the hash from the id we are pulling from
2050             #
2051 0           my ( $extraValue ) = @{$self->runSQL( SQL => "select extra_value from " . $self->safeSQL( $paramHash{table} ) . " where guid='" . $self->safeSQL( $paramHash{guid} ) . "'" . $addToWhere )};
  0            
2052              
2053             #
2054             # if crypt password is set, then crypt it up!
2055             #
2056 0 0         if ( $self->{dataSchema}{$paramHash{table}}{extra_value}{encrypt} ) { $extraValue = $self->FWSDecrypt( $extraValue ) }
  0            
2057              
2058             #
2059             # pull the hash out
2060             #
2061 1     1   15 use Storable qw(nfreeze thaw);
  1         3  
  1         7650  
2062 0           my %extraHash;
2063 0 0         if ( $extraValue ) { %extraHash = %{thaw( $extraValue )} }
  0            
  0            
2064              
2065             #
2066             # add the new one
2067             #
2068 0           $extraHash{$paramHash{field}} = $paramHash{value};
2069              
2070             #
2071             # convert back to a hash string
2072             #
2073 0           my $hash = nfreeze(\%extraHash);
2074              
2075             #
2076             # encrypt if we are the trans table
2077             #
2078 0 0         if ( $self->{dataSchema}{$paramHash{table}}{extra_value}{encrypt} ) { $hash = $self->FWSEncrypt( $hash ) }
  0            
2079              
2080             #
2081             # update the hash in the db
2082             #
2083 0           $self->runSQL( SQL => "update " . $self->safeSQL( $paramHash{table} ) . " set extra_value='" . $self->safeSQL( $hash ) . "' where guid='" . $self->safeSQL( $paramHash{guid} ) . "'" . $addToWhere );
2084              
2085             #
2086             # update the cache table if we are on the data table
2087             #
2088 0 0         if ( $paramHash{table} eq 'data' ) {
2089              
2090             #
2091             # pull the data has, update it, then send it to the cache
2092             #
2093 0           $self->updateDataCache( $self->dataHash( guid => $paramHash{guid} ) );
2094             }
2095 0           return;
2096             }
2097              
2098              
2099             =head2 saveHash
2100              
2101             Save a generic hash to a hash object in the same fasion as other FWS save objects. If the object exists already it will udpate it, or add a new one if it did not exist
2102              
2103             #
2104             # add a new object
2105             #
2106             $someHash{someArray} = $fws->saveHash( hashArray => $someHash{someArray},
2107             date => $fws->dateTime( format => 'SQL' ),
2108              
2109             #
2110             # update a object that contains its perspective guid
2111             #
2112             $someHash{someArray} = $fws->saveHash( hashArray => $someHash{someArray}, %existingDataThatIsUpdated );
2113              
2114             =cut
2115              
2116             sub saveHash {
2117 0     0 1   my ( $self, %paramHash ) = @_;
2118              
2119             #
2120             # get the current array, and clear the loc string
2121             #
2122 0           my @hashArray = $self->hashArray(%paramHash);
2123 0           my @newArray;
2124 0           my $hashUpdated = 0;
2125              
2126             #
2127             # lets not keep the refrence to the hashArray itself, that would be nasty if we saved it!
2128             #
2129 0           delete $paramHash{hashArray};
2130              
2131             #
2132             # go though each one of the shippingLocation items, figure out what one is being updated and update it!
2133             #
2134 0           for my $i (0 .. $#hashArray) {
2135              
2136             #
2137             # update the loc with the same guid with the new hash
2138             #
2139 0 0         if ( $paramHash{guid} eq $hashArray[$i]{guid} ) {
2140              
2141             #
2142             # update the flag, to know we are NOT talking about adding a new one and append to the line
2143             #
2144 0           push @newArray, {%paramHash};
2145 0           $hashUpdated = 1;
2146             }
2147             #
2148             # update the loc with the same thing but repackaged (no change was made)
2149             #
2150 0           else { push @newArray, {%{$hashArray[$i]}} }
  0            
2151             }
2152              
2153             #
2154             # if we dindn't update then this is an add
2155             #
2156 0 0         if (!$hashUpdated) {
2157 0           $paramHash{guid} = $self->createGUID( 'h' );
2158 0           push @newArray, {%paramHash};
2159             }
2160 0           return ( nfreeze(\@newArray) );
2161             }
2162              
2163              
2164             =head2 saveQueue
2165              
2166             Save a hash to the process and message queue.
2167              
2168             %queueHash = $fws->saveQueue( %queueHash );
2169              
2170             =cut
2171              
2172             sub saveQueue {
2173 0     0 1   my ( $self, %paramHash ) = @_;
2174              
2175 0           %paramHash = $self->runScript( 'preSaveQueue', %paramHash );
2176              
2177 0           %paramHash = $self->_recordInit(
2178             '_guidLeader' => 'q',
2179             '_table' => 'queue',
2180             %paramHash,
2181             );
2182              
2183 0           %paramHash = $self->_recordSave(
2184             '_fields' => 'directory_guid|profile_guid|queue_from|hash|queue_to|from_name|draft|type|subject|digital_assets|transfer_encoding|mime_type|body|scheduled_date',
2185             '_keys' => 'directoryGUID|userGUID|from|hash|to|fromName|draft|type|subject|digitalAssets|transferEncoding|mimeType|body|scheduledDate',
2186             '_table' => 'queue',
2187             '_noExtra' => '1',
2188             %paramHash,
2189             );
2190              
2191              
2192 0           %paramHash = $self->runScript('postSaveQueue',%paramHash);
2193              
2194 0           return %paramHash;
2195             }
2196              
2197             =head2 saveQueueHistory
2198              
2199             Save a hash to the process and message queue history.
2200              
2201             %queueHash = $fws->saveQueueHistory( %queueHash );
2202              
2203             =cut
2204              
2205             sub saveQueueHistory {
2206 0     0 1   my ( $self, %paramHash ) = @_;
2207              
2208 0           %paramHash = $self->runScript('preSaveQueueHistory',%paramHash);
2209              
2210             #
2211             # if sent date isn't set, lets set it to NOW
2212             #
2213 0 0 0       if ( !$paramHash{sentDate} || $paramHash{sentDate} =~ /^0000.00.00/ ) { $paramHash{sentDate} = $self->safeSQL( $self->formatDate( format => "SQL" ) ) }
  0            
2214              
2215 0           %paramHash = $self->_recordInit(
2216             '_guidLeader' => 'q',
2217             '_table' => 'queue_history',
2218             %paramHash);
2219              
2220 0           %paramHash = $self->_recordSave(
2221             '_fields' => 'synced|queue_guid|directory_guid|profile_guid|hash|scheduled_date|queue_from|from_name|queue_to|body|type|subject|success|failure_code|response|sent_date',
2222             '_keys' => 'synced|queueGUID|directoryGUID|profileGUID|hash|scheduledDate|from|fromName|to|body|type|subject|success|failureCode|response|sentDate',
2223             '_table' => 'queue_history',
2224             '_noExtra' => '1',
2225             %paramHash);
2226              
2227 0           %paramHash = $self->runScript('postSaveQueueHistory',%paramHash);
2228              
2229 0           return %paramHash;
2230             }
2231              
2232              
2233             =head2 saveUser
2234              
2235             Save a user and return its hash.
2236              
2237             %userHash = $fws->saveUser( %userHash );
2238              
2239             =cut
2240              
2241             sub saveUser {
2242 0     0 1   my ( $self, %paramHash ) = @_;
2243 0           %paramHash = $self->runScript('preSaveUser',%paramHash);
2244              
2245 0 0         if ( !$paramHash{guid} ) {
2246             #
2247             # if we are not going to make a duplicate lets rock
2248             #
2249 0 0 0       if ( !@{$self->runSQL( SQL => "select 1 from profile where email like '" . $self->safeSQL( $paramHash{email} ) . "' LIMIT 1" )} && $paramHash{email} && $paramHash{password} ) {
  0   0        
2250             #
2251             # make sure name will be something
2252             #
2253 0 0         if ( !$paramHash{name} ) { $paramHash{name} = $paramHash{billingName} }
  0            
2254 0 0         if ( !$paramHash{name} ) { $paramHash{name} = $paramHash{shippingName} }
  0            
2255              
2256             #
2257             # if the active is blank or undef lets make it 1
2258             #
2259 0 0         if ( !defined $paramHash{active} ) { $paramHash{active} = 1 }
  0            
2260 0 0         if ( $paramHash{active} eq '' ) { $paramHash{active} = 1 }
  0            
2261              
2262             #
2263             # lets match these so the update procedure will treat it like a new update
2264             #
2265 0           $paramHash{passwordConfirm} = $paramHash{password};
2266              
2267             #
2268             # do the inital insert
2269             #
2270 0           $paramHash{guid} = $self->createGUID('u');
2271 0           $self->runSQL( SQL => "insert into profile (guid,email,name,active) values ('" . $paramHash{guid} . "','" . $self->safeSQL( $paramHash{email} ) . "','" . $self->safeSQL( $paramHash{name} ) . "','" . $self->safeSQL( $paramHash{active} ) . "')" );
2272              
2273             #
2274             # if the profile is new lets send the admin an email
2275             #
2276 0 0         if ( $self->siteValue('profileCreationEmail') ) {
2277 0           $self->send( to => $self->siteValue('profileCreationEmail'), fromName => $self->{email},from => $self->{email}, subject => "New User Created", mimeType => "text/plain", body => 'Name: ' . $paramHash{name} . "\nEmail: " . $paramHash{email} . "\n" );
2278             }
2279             }
2280             }
2281              
2282             #
2283             # see if the password needs to be updated and one last check to see if its strong enough
2284             #
2285 0           my $insertSQL;
2286 0 0 0       if ( $paramHash{password} && $paramHash{passwordConfirm} eq $paramHash{password} ) {
2287              
2288             #
2289             # crypt the password
2290             #
2291 0           $paramHash{password} = $self->cryptPassword( $paramHash{password} );
2292              
2293             #
2294             # add to the insert statement
2295             #
2296 0           $insertSQL .= ",profile_password='" . $self->safeSQL( $paramHash{password} ) . "'";
2297             }
2298              
2299             #
2300             # set the dirived stuff so nobody gets sneeky and tries to pass it to the procedure
2301             #
2302 0   0       $paramHash{pin} ||= $self->createPin();
2303              
2304             #
2305             # update the core of the record
2306             #
2307 0           $self->runSQL( SQL => "update profile set fb_id='" . $self->safeSQL( $paramHash{FBId} ) . "',fb_access_token='" . $self->safeSQL( $paramHash{FBAccessToken} ) . "', pin='" . $self->safeSQL( $paramHash{pin} ) . "',active='" . $self->safeSQL( $paramHash{active} ) . "',name='" . $self->safeSQL( $paramHash{name} ) . "' " . $insertSQL . " where guid='" . $paramHash{guid} . "'" );
2308              
2309             #
2310             # loop though and update every one that is diffrent, but you can't touch for security reasons
2311             #
2312 0           for my $key ( keys %paramHash ) {
2313 0 0         if ( $key !~ /^(FBId|FBAccessToken|googleId|password|passwordConfirm|group|name|guid|active|pin|active|email|profile_password|passwordConfirm|password|site_guid)$/ ) {
2314 0           $self->saveExtra( table => 'profile', guid => $paramHash{guid}, field => $key, value => $paramHash{$key} );
2315             }
2316             }
2317              
2318             #
2319             # do a hard reset of the profile so it will load again the next time a proc asks for it
2320             #
2321 0           for ( keys %{$self->{profileHash}} ) { delete $self->{profileHash}->{$_} }
  0            
  0            
2322              
2323             #
2324             # Not sure if this is needed, but for consistance, the Update doesn't actually Update the hash so it will return its self unaltered
2325             #
2326 0           %paramHash = $self->runScript( 'postSaveUser', %paramHash );
2327 0           return %paramHash;
2328             }
2329              
2330              
2331             =head2 schemaHash
2332              
2333             Return the schema hash for an element. You can pass either the guid or the element type.
2334              
2335             my %schemaHash = $fws->schemaHash( 'someGUIDorType' );
2336              
2337             =cut
2338              
2339             sub schemaHash {
2340 0     0 1   my ( $self, $guid ) = @_;
2341              
2342             #
2343             # Get it from the element hash, (with caching enabled)
2344             #
2345 0           my %elementHash = $self->elementHash( guid => $guid );
2346              
2347             #
2348             # make sure schemaHash is defined before we run the code
2349             #
2350 0           my %dataSchema;
2351              
2352             #
2353             # run the eval and populate the hash (Including the title)
2354             #
2355             ## no critic (RequireCheckingReturnValueOfEval ProhibitStringyEval)
2356 0           eval $elementHash{schemaDevel};
2357             ## use critic
2358 0           my $errorCode = $@;
2359 0 0         if ( $errorCode ) { $self->FWSLog( 'DB schema error: ' . $guid . ' - ' . $errorCode ) }
  0            
2360              
2361 0           return %dataSchema;
2362             }
2363              
2364              
2365             =head2 setCacheIndex
2366              
2367             Set a sites cache index for its site. you can bas a siteGUID as a hash parameter if you wish to update the index for a site not currently being rendered.
2368              
2369             $fws->setCacheIndex();
2370              
2371             =cut
2372              
2373             sub setCacheIndex {
2374 0     0 1   my ( $self, %paramHash ) = @_;
2375              
2376             #
2377             # set site GUID if it wasn't passed to us
2378             #
2379 0   0       $paramHash{siteGUID} ||= $self->{siteGUID};
2380              
2381 0           my @indexArray;
2382 0           my %elementHash = $self->_fullElementHash();
2383 0           for my $elementGUID ( keys %elementHash ) {
2384 0           my %schemaHash = $self->schemaHash( $elementGUID );
2385              
2386             #
2387             # loop though each one and if the index is set to one, add it to the index list
2388             #
2389 0           for my $key ( keys %schemaHash) {
2390 0 0         if ( $schemaHash{$key}{index} ) { push @indexArray, $key }
  0            
2391             }
2392             }
2393              
2394             #
2395             # create a comma delemited list that is the inexed fields
2396             #
2397 0           my $cacheValue = join( ',', @indexArray );
2398              
2399             #
2400             # update the extra table of what the cacheIndex is
2401             #
2402 0 0         if ( $self->siteValue( 'dataCacheIndex' ) ne $cacheValue ) {
2403 0           $self->FWSLog( "Adding data cache index: ".$cacheValue );
2404 0           $self->saveExtra( table => 'site', guid => $paramHash{siteGUID}, field => 'dataCacheIndex', value => $cacheValue );
2405             }
2406 0           return;
2407             }
2408              
2409              
2410             =head2 sortArray
2411              
2412             Return a sorted array reference by passing the array reference, what key to sort by, and numrical or alpha sort.
2413              
2414             #
2415             # type: alpha|number
2416             # key: the key you are sorting by
2417             # array: an array reference
2418             #
2419             my $arrayRef = $fws->sortArray( key => 'id', type => 'alpha', array => \@someArray );
2420              
2421             =cut
2422              
2423             sub sortArray {
2424 0     0 1   my ( $self, %paramHash ) = @_;
2425 0           my @returnArray = @{$paramHash{array}};
  0            
2426              
2427 0 0         if ( $paramHash{type} eq 'number' ) {
2428 0           @returnArray = ( map{$_->[1]} sort {$a->[0] <=> $b->[0]} map{[$_->{$paramHash{key}},$_]} @returnArray )
  0            
  0            
  0            
2429             }
2430             else {
2431 0           @returnArray = ( map{$_->[1]} sort {$a->[0] cmp $b->[0]} map{[$_->{$paramHash{key}},$_]} @returnArray )
  0            
  0            
  0            
2432             }
2433 0           return \@returnArray;
2434             }
2435              
2436             =head2 tableFieldHash
2437              
2438             Return a multi-dimensional hash of all the fields in a table with its properties. This usually isn't used by anything but internal table alteration methods, but it could be useful if you are making conditionals to determine the data structure before adding or changing data. The method is CPU intensive so it should only be used when performance is not a requirement.
2439              
2440             $tableFieldHashRef = $fws->tableFieldHash( 'the_table' );
2441              
2442             The return dump will have the following structure:
2443              
2444             $tableFieldHashRef->{field}{type}
2445             $tableFieldHashRef->{field}{ord}
2446             $tableFieldHashRef->{field}{null}
2447             $tableFieldHashRef->{field}{default}
2448             $tableFieldHashRef->{field}{extra}
2449              
2450             If the field is indexed it will return a unique table field combination key equal to MUL or FULLTEXT:
2451              
2452             $tableFieldHashRef->{thetable_field}{key}
2453              
2454             =cut
2455              
2456             sub tableFieldHash {
2457 0     0 1   my ( $self, $table ) = @_;
2458              
2459             #
2460             # set an order counter so we can sort by this if needed
2461             #
2462 0           my $fieldOrd = 0;
2463              
2464             #
2465             # if we have a cached version lets make one
2466             #
2467 0 0         if (!keys %{$self->{'_' . $table . 'FieldCache'}}) {
  0            
2468              
2469             #
2470             # grab the table def hash for mysql
2471             #
2472 0 0         if ( $self->{DBType} =~ /^mysql$/i ) {
2473 0           my $tableData = $self->runSQL( SQL => "desc " . $self->safeSQL( $table ) );
2474 0           while ( @$tableData ) {
2475 0           $fieldOrd++;
2476 0           my $fieldInc = shift @{$tableData};
  0            
2477 0           $self->{'_' . $table . 'FieldCache'}->{$fieldInc}{type} = shift @{$tableData};
  0            
2478 0           $self->{'_' . $table . 'FieldCache'}->{$fieldInc}{ord} = $fieldOrd;
2479 0           $self->{'_' . $table . 'FieldCache'}->{$fieldInc}{null} = shift @{$tableData};
  0            
2480 0           $self->{'_' . $table . 'FieldCache'}->{$table . "_" . $fieldInc}{key} = shift @{$tableData};
  0            
2481 0           $self->{'_' . $table . 'FieldCache'}->{$fieldInc}{default} = shift @{$tableData};
  0            
2482 0           $self->{'_' . $table . 'FieldCache'}->{$fieldInc}{extra} = shift @{$tableData};
  0            
2483             }
2484             }
2485              
2486             #
2487             # grab the table def hash for sqlite
2488             #
2489 0 0         if ( $self->{DBType} =~ /^sqlite$/i ) {
2490 0           my $tableData = $self->runSQL( SQL => "PRAGMA table_info(" . $self->safeSQL( $table ) . ")");
2491 0           while (@$tableData) {
2492 0           $fieldOrd++;
2493 0           shift @{$tableData};
  0            
2494 0           my $fieldInc = shift @{$tableData};
  0            
2495 0           shift @{$tableData};
  0            
2496 0           shift @{$tableData};
  0            
2497 0           shift @{$tableData};
  0            
2498              
2499 0           $self->{'_' . $table . 'FieldCache'}->{$fieldInc}{type} = shift @{$tableData};
  0            
2500 0           $self->{'_' . $table . 'FieldCache'}->{$fieldInc}{ord} = $fieldOrd;
2501             }
2502              
2503 0           $tableData = $self->runSQL( SQL => "PRAGMA index_list(" . $self->safeSQL( $table ) . ")" );
2504 0           while (@$tableData) {
2505 0           shift @{$tableData};
  0            
2506 0           my $fieldInc = shift @{$tableData};
  0            
2507 0           shift @{$tableData};
  0            
2508              
2509 0           $self->{'_' . $table . 'FieldCache'}->{$fieldInc}{key} = 'MUL';
2510             }
2511             }
2512             }
2513 0           return %{$self->{'_' . $table . 'FieldCache'}};
  0            
2514              
2515             }
2516              
2517             =head2 templateArray
2518              
2519             Return a hash array of all the templates available.
2520              
2521             =cut
2522              
2523             sub templateArray {
2524 0     0 1   my ( $self ) = @_;
2525             #
2526             # Get the Template array
2527             #
2528 0           my $templateArray = $self->runSQL( SQL => "select guid,title,site_guid,template_devel,css_devel,js_devel,default_template from templates where site_guid='" . $self->safeSQL( $self->{siteGUID} ) . "'" );
2529              
2530 0           my @templateHashArray;
2531 0           while (@$templateArray) {
2532             #
2533             # create the hash and return it
2534             #
2535 0           my %templateHash;
2536 0           $templateHash{guid} = shift @{$templateArray};
  0            
2537 0           $templateHash{title} = shift @{$templateArray};
  0            
2538 0           $templateHash{siteGUID} = shift @{$templateArray};
  0            
2539 0           $templateHash{template} = shift @{$templateArray};
  0            
2540 0           $templateHash{css} = shift @{$templateArray};
  0            
2541 0           $templateHash{js} = shift @{$templateArray};
  0            
2542 0           $templateHash{default} = shift @{$templateArray};
  0            
2543              
2544 0           push @templateHashArray, {%templateHash};
2545             }
2546 0           return @templateHashArray;
2547             }
2548              
2549              
2550             =head2 templateHash
2551              
2552             Return a hash of all the information about a template.
2553              
2554             =cut
2555              
2556             sub templateHash {
2557              
2558 0     0 1   my ( $self, %paramHash ) = @_;
2559              
2560 0           my $pageId = $paramHash{pageGIUD};
2561              
2562 0           my $template;
2563             my $css;
2564 0           my $js;
2565 0           my $title;
2566              
2567             #
2568             # get the default template Id
2569             #
2570 0           my ( $defaultGUID ) = @{$self->runSQL( SQL => "select guid from templates where default_template = '1' and site_guid='" . $self->safeSQL( $self->{siteGUID} ) . "'" )};
  0            
2571              
2572             #
2573             # get the home page template ID
2574             #
2575 0           my ( $homePageTemplateId ) = @{$self->runSQL( SQL => "select layout from guid_xref where child='" . $self->safeSQL( $self->homeGUID() ) . "'" )};
  0            
2576              
2577             #
2578             # if this is the home page then set the page id to the actual home page templates ID
2579             #
2580 0 0 0       if ( $pageId eq $self->homeGUID() && !$paramHash{templateGUID} ) { $paramHash{templateGUID} = $homePageTemplateId }
  0            
2581              
2582             #
2583             # set some sql defaults
2584             #
2585 0           my $returnFields = 'title, template_devel, css_devel, js_devel, templates.guid';
2586              
2587             #
2588             # we have a page id, lets see if we can get the template from it. but if the
2589             # page id was 0 we know that its the home page template id we want not the "0" template id
2590             #
2591 0 0         if ( $pageId ) {
    0          
2592 0           ( $title, $template, $css, $js, $paramHash{templateGUID} ) = @{$self->runSQL( SQL => "select " . $returnFields . " from templates left join guid_xref on layout=templates.guid where guid_xref.child='" . $self->safeSQL( $pageId ) . "' and guid_xref.site_guid='" . $self->safeSQL( $self->{siteGUID} ) . "'" )};
  0            
2593             }
2594              
2595             #
2596             # we wern't given a page lets grab it from the templateGUID
2597             #
2598             elsif ( !$paramHash{templateGUID} ) {
2599 0           ( $title, $template, $css, $js, $paramHash{templateGUID} ) = @{$self->runSQL( SQL => "select " . $returnFields . " from templates where guid='" . $self->safeSQL( $paramHash{templateGUID} ) . "'" )};
  0            
2600             }
2601              
2602             #
2603             # man, this sucks, we didn't find one yet lets get the default one
2604             #
2605 0 0         if ( !$paramHash{templateGUID} ) {
2606 0           ( $title, $template, $css, $js, $paramHash{templateGUID} ) = @{$self->runSQL( SQL => "select " . $returnFields . " from templates where guid='" . $self->safeSQL( $defaultGUID ) . "'" )};
  0            
2607             }
2608              
2609             #
2610             # wtf, still didn't get one yet???? lets build out a basic one so the page will render
2611             #
2612 0 0         if ( !$paramHash{templateGUID} ) {
2613 0           $title = "FWS template";
2614 0           $template = "\n".
2615             "\n" .
2616             "\n" .
2617             "#FWSHead#" .
2618             "\n" .
2619             "\n" .
2620             "#FWSMenu#" .
2621             "
" .
2622             "
" .
2623             "
" .
2624             "
" .
2625             "
" .
2626             "
#FWSShow-header#
" .
2627             "" .
2628             "" .
2629             "" .
2630             "
" .
2631             "
" .
2632             "
" .
2633             "
#FWSShow-main#
" .
2634             "" .
2635             "" .
2636             "" .
2637             "
" .
2638             "
" .
2639             "
" .
2640             "
#FWSShow-footer#
" .
2641             "" .
2642             "" .
2643             "" .
2644             "" .
2645             "" .
2646             "
\n" .
2647             "#FWSJavaLoad#" .
2648             "\n" .
2649             "";
2650             }
2651              
2652              
2653             #
2654             # create the hash and return it
2655             #
2656 0           my %templateHash;
2657 0           $templateHash{guid} = $paramHash{templateGUID};
2658 0           $templateHash{homeGUID} = $homePageTemplateId;
2659 0           $templateHash{title} = '';
2660 0           $templateHash{siteGUID} = $self->{siteGUID};
2661 0           $templateHash{template} = $template;
2662 0           $templateHash{css} = $css;
2663 0           $templateHash{js} = $js;
2664 0           $templateHash{defaultGUID} = $defaultGUID;
2665              
2666 0           return %templateHash;
2667             }
2668              
2669              
2670              
2671             =head2 updateDataCache
2672              
2673             Update the cache version of the data record. This is called automatically when saveData is called.
2674              
2675             $fws->updateDataCache(%theDataHash);
2676              
2677             =cut
2678              
2679             sub updateDataCache {
2680 0     0 1   my ( $self, %dataHash ) = @_;
2681              
2682             #
2683             # get the field hash so we don't have to try to add fields that might not be there EVERY time
2684             #
2685 0           my %tableFieldHash = $self->tableFieldHash( 'data_cache' );
2686              
2687             #
2688             # set the page id of the guid for easy access on search pages
2689             #
2690 0           $dataHash{pageIdOfElement} = $self->_setPageGUID( guid => $dataHash{guid} );
2691            
2692             #
2693             # get the page hash of the page, and update the page description to the data for easy access on search pages
2694             #
2695 0           my %pageHash = $self->dataHash( guid => $dataHash{pageIdOfElement} );
2696 0           $dataHash{pageDescription} = $pageHash{pageDescription};
2697              
2698             #
2699             # get what fields we are aloud to use
2700             #
2701 0           my %dataCacheFields = %{$self->{dataCacheFields}};
  0            
2702              
2703             #
2704             # we will be building these up while we loop
2705             #
2706 0           my $fields;
2707             my $values;
2708              
2709             #
2710             # make any fields that "might" be needed
2711             #
2712 0           foreach my $key ( keys %dataHash ) {
2713 0 0 0       if ( $dataCacheFields{$key} || $key =~ /^(site_guid|guid|name|title|pageIdOfElement|pageDescription)$/ ) {
2714              
2715             #
2716             # if the type is blank, then this is new
2717             #
2718 0 0         if ( !$tableFieldHash{$key}{type} ) {
2719             #
2720             # alter tha table
2721             #
2722 0           $self->alterTable( table => 'data_cache', field => $key, type => 'text', key => 'FULLTEXT', default => '' );
2723             }
2724              
2725              
2726              
2727             #
2728             # append the new data to the strings we are using to create the insert statement
2729             #
2730 0           $fields .= $self->safeSQL( $key ) . ',';
2731 0           $values .= "'" . $self->safeSQL( $dataHash{$key} ) . "',";
2732             }
2733             }
2734              
2735             #
2736             # clean up the commas at the end of values and fields
2737             #
2738 0           $fields =~ s/,$//sg;
2739 0           $values =~ s/,$//sg;
2740              
2741             #
2742             # remove the one that "might" be there
2743             #
2744 0           $self->runSQL( SQL => "delete from data_cache where guid='" . $self->safeSQL( $dataHash{guid} )."'" );
2745              
2746             #
2747             # add the the new one
2748             #
2749 0           $self->runSQL( SQL => "insert into data_cache (" . $fields . ") values (" . $values . ")" );
2750              
2751 0           return;
2752             }
2753              
2754             =head2 userArray
2755              
2756             Return an array or reference to an array of the users on an installation. You can pass the keywords parameter and it will look though name and email address.
2757              
2758             =cut
2759              
2760             sub userArray {
2761 0     0 1   my ( $self, %paramHash ) = @_;
2762 0           my @userHashArray;
2763              
2764             #
2765             # add keyword Search
2766             #
2767             my $whereStatement;
2768 0           my $keywordsSQL = $self->_getKeywordSQL( $paramHash{keywords}, "name", "email", "extra_value" );
2769 0 0         if ( $keywordsSQL ) { $whereStatement = 'where ' . $keywordsSQL };
  0            
2770              
2771             #
2772             # get the data from the database and push it into the hash array
2773             #
2774 0           my $userArray = $self->runSQL( SQL => "select fb_id,fb_access_token,name,email,guid,active,extra_value from profile " . $whereStatement );
2775 0           while ( @$userArray ) {
2776             #
2777             # fill in the hash
2778             #
2779 0           my %userHash;
2780 0           $userHash{FBId} = shift @{$userArray};
  0            
2781 0           $userHash{FBAccessToken} = shift @{$userArray};
  0            
2782 0           $userHash{name} = $self->removeHTML( shift @{$userArray} );
  0            
2783 0           $userHash{email} = shift @{$userArray};
  0            
2784 0           $userHash{guid} = shift @{$userArray};
  0            
2785 0           $userHash{active} = shift @{$userArray};
  0            
2786              
2787             #
2788             # add the extra stuff to the hash
2789             #
2790 0           my $extra_value = shift @{$userArray};
  0            
2791 0           %userHash = $self->mergeExtra( $extra_value, %userHash );
2792              
2793             #
2794             # push it into the array
2795             #
2796 0           push @userHashArray, {%userHash};
2797             }
2798 0 0         if ( $paramHash{ref} ) { return \@userHashArray }
  0            
2799 0           return @userHashArray;
2800             }
2801              
2802              
2803             =head2 userHash
2804              
2805             Return the hash for a user.
2806              
2807             %userHash = $fws->userHash( guid => 'guid' );
2808              
2809             =cut
2810              
2811             sub userHash {
2812 0     0 1   my ( $self, %paramHash ) = @_;
2813              
2814             #
2815             # store the guid in this, till we figure out what one we are looking up
2816             #
2817 0           my $lookupGUID;
2818             my $lookupSQL;
2819              
2820             #
2821             # if user isn't logged in and we are not passing anything just return - nothing to see here
2822             #
2823 0 0 0       if ( !keys %paramHash && !$self->isUserLoggedIn() ) { return }
  0 0          
2824             #
2825             # if we have a pin lets do the lookup that way and skip the rest of this crap that is amix of old and new
2826             # but make sure we set the lookupGUID to something so we don't do any caching and treat it as disposable
2827             #
2828 0           elsif ( $paramHash{pin} ) { $lookupGUID = '_'; $lookupSQL = "pin like '" . $self->safeSQL( $paramHash{pin} ) . "'" }
  0            
2829             else {
2830              
2831             #
2832             #
2833             # do some fanageling for old code to see if it is being called the old way, or the new way
2834             #
2835 0 0         if ( $paramHash{guid} ) { $lookupGUID = $paramHash{guid} }
  0 0          
2836              
2837             #
2838             # if guid isn't defined, then set it to the email address, or the only thing passed
2839             #
2840 0           elsif ( !$paramHash{email} ) { $lookupGUID = each %paramHash } else { $lookupGUID = $paramHash{email} }
  0            
2841              
2842             #
2843             # if its still blank after that, then we are talking about looking up the guy who is logged in currently
2844             #
2845 0 0         if ( !$lookupGUID ) { $lookupSQL = "email like '" . $self->safeSQL( $self->{userLoginId} ) . "'" }
  0 0          
2846              
2847             #
2848             # if the lookupGUID has an @ in it, then look up the guid - least efficient but old stuff still looks for stuff this way
2849             #
2850 0           elsif ( $lookupGUID =~ /@/ ) { $lookupSQL = "email like '" . $self->safeSQL( $lookupGUID ) . "'" }
2851              
2852             #
2853             # if it doesn't have a @ in it, then we must have a guid to work with, lets find that
2854             #
2855 0           else { $lookupSQL = "guid='" . $self->safeSQL( $lookupGUID ) . "'" }
2856              
2857             }
2858              
2859             #
2860             # create a new variable but leave it blank unless we are using a persistant one
2861             #
2862 0           my %userHash;
2863              
2864             #
2865             # if your not logged in.. lets skip this But, if we are looking for one thing - then lets do it
2866             #
2867 0 0 0       if ( $self->isUserLoggedIn() || $lookupGUID ) {
2868              
2869             #
2870             # the profile hash is not disposable see if we already have it if we do, just populate it from the cached
2871             # version because this is the current guy logged in
2872             #
2873 0 0         if ( !$lookupGUID ) { %userHash = %{$self->{profileHash}} }
  0            
  0            
2874              
2875             #
2876             # see if it is populated, if it is, skip this and return it.
2877             #
2878 0 0         if ( !keys %userHash ) {
2879              
2880             #
2881             # get the goods from the profile table and grab the ID from the front,
2882             # so we can use it to get the profile;
2883             #
2884 0           my @profileExtArray = @{$self->runSQL( SQL => "select profile.extra_value, profile.guid, 'pin', profile.pin, 'guid', profile.guid, 'googleId', profile.google_id, 'name', profile.name, 'FBId', fb_id, 'FBAccessToken', fb_access_token, 'email', profile.email, 'active', profile.active from profile where " . $lookupSQL )};
  0            
2885 0           my $extraValue = shift @profileExtArray;
2886 0           my $guid = shift @profileExtArray;
2887              
2888             #
2889             # convert it into the hash
2890             #
2891 0           %userHash = @profileExtArray;
2892              
2893             #
2894             # add extra Hash
2895             #
2896 0           %userHash = $self->mergeExtra( $extraValue, %userHash );
2897              
2898             #
2899             # add all the groups I have access too
2900             #
2901 0           my @groups = @{$self->runSQL( SQL => "select profile_groups_xref.groups_guid from profile left join profile_groups_xref on profile_groups_xref.profile_guid = profile.guid where profile.guid = '" . $self->safeSQL( $guid ) . "'" )};
  0            
2902 0           while (@groups) {
2903 0           $userHash{group}{ shift @groups } = 1;
2904             }
2905              
2906             #
2907             # if not logged or we are not looking for a particular guid that is disposable
2908             # set the id to 0 and active to 0 and destroy what we have
2909             #
2910 0 0 0       if ( !$self->isUserLoggedIn() && !$lookupGUID ) {
2911 0           for ( keys %{$self->{profileHash}} ) { delete $self->{profileHash}->{$_} }
  0            
  0            
2912 0           $userHash{guid} = '';
2913 0           $userHash{active} = '0';
2914             }
2915              
2916             #
2917             # set the default for radio buttons
2918             #
2919 0   0       $userHash{active} ||= 0;
2920              
2921             #
2922             # if are a disposable record, don't save it as the profile hash, just return it
2923             #
2924 0 0         if ( !$lookupGUID ) { %{$self->{profileHash}} = %userHash }
  0            
  0            
2925             }
2926             }
2927              
2928             #
2929             # make sure nobody is putting anything dangrous in the user name
2930             #
2931 0           $userHash{name} = $self->removeHTML( $userHash{name} );
2932              
2933 0           return %userHash;
2934             }
2935              
2936              
2937             =head2 userGroupHash
2938              
2939             Return the hash for a user group by passing the groups guid.
2940              
2941             %userGroupHash = $fws->userGroupHash('somegroupguid');
2942              
2943             =cut
2944              
2945             sub userGroupHash {
2946 0     0 1   my ( $self, $guid ) = @_;
2947 0           my ( $name, $description ) = @{$self->runSQL( SQL => "select name,description from groups where guid='" . $self->safeSQL( $guid ) . "'" )};
  0            
2948 0           my %userGroupHash;
2949 0           $userGroupHash{name} = $name;
2950 0           $userGroupHash{description} = $description;
2951 0           $userGroupHash{guid} = $guid;
2952              
2953             #
2954             # get a list of users and add that to the hash
2955             #
2956 0           my @userList = @{$self->runSQL( SQL => "select profile_guid from profile_groups_xref where groups_guid='" . $self->safeSQL( $guid ) . "'" )};
  0            
2957 0           while (@userList) {
2958 0           my $userId = shift @userList;
2959 0           $userGroupHash{user}{$userId} = '1';
2960             }
2961              
2962 0           return %userGroupHash;
2963             }
2964              
2965              
2966             =head2 userGroupArray
2967              
2968             Return the hash array for all of the user groups;
2969              
2970             my @userGroupArray = $fws->userGroupArray();
2971              
2972             =cut
2973              
2974             sub userGroupArray {
2975 0     0 1   my ( $self ) = @_;
2976 0           my @userGroupHashArray;
2977              
2978             #
2979             # get the data from the database and push it into the hash array
2980             #
2981 0           my @userGroupArray = @{$self->runSQL( SQL => "select name,description,guid from groups" )};
  0            
2982 0           while (@userGroupArray) {
2983              
2984             #
2985             # fill in the hash
2986             #
2987 0           my %userGroupHash;
2988 0           $userGroupHash{name} = shift @userGroupArray;
2989 0           $userGroupHash{description} = shift @userGroupArray;
2990 0           $userGroupHash{guid} = shift @userGroupArray;
2991              
2992             #
2993             # push it into the array
2994             #
2995 0           push @userGroupHashArray, {%userGroupHash};
2996             }
2997 0           return @userGroupHashArray;
2998             }
2999              
3000              
3001             =head2 updateDatabase
3002              
3003             Alter the database to match the schema for FWS 2. The return will print the SQL statements used to adjust the tables.
3004              
3005             print $fws->updateDatabase()."\n";
3006              
3007             This method is automatically called when on the web optimized version of FWS when rendering the 'System' screen. This will also auto trigger a flag to only it allow it to execute once so it doesn't recurse itself.
3008              
3009             =cut
3010              
3011             sub updateDatabase {
3012 0     0 1   my ( $self ) = @_;
3013              
3014             #
3015             # our passback for what we did
3016             #
3017 0           my $dbResponse;
3018            
3019             #
3020             # make sure I didn't do this yet
3021             #
3022 0 0         if ( !$self->{upadateDatabaseRan} ) {
3023            
3024             #
3025             # loop though the records and make or update the tables
3026             #
3027 0           for my $table ( keys %{$self->{dataSchema}} ) {
  0            
3028              
3029 0           for my $field ( keys %{$self->{dataSchema}{$table}} ) {
  0            
3030            
3031 0           my $type = $self->{dataSchema}{$table}{$field}{type};
3032 0           my $key = $self->{dataSchema}{$table}{$field}{key};
3033 0           my $default = $self->{dataSchema}{$table}{$field}{default};
3034            
3035             #
3036             # make sure this isn't a bad record. It at least needs a table name
3037             #
3038 0 0         if ( $table ) { $dbResponse .= $self->alterTable( table => $table, field => $field, type => $type, key => $key, default => $default ) }
  0            
3039             }
3040             }
3041             }
3042            
3043 0           $self->{upadateDatabaseRan} = 1;
3044 0           return $dbResponse;
3045             }
3046              
3047              
3048             =head2 updateModifiedDate
3049              
3050             Update the modified date of the page a dataHash element resides on.
3051              
3052             $fws->updateModifiedDate(%dataHash);
3053              
3054             Note: By updating anything that is persistant against multiple pages all pages will have thier date updated as it is considered a site wide change.
3055              
3056             =cut
3057              
3058             sub updateModifiedDate {
3059 0     0 1   my ( $self, %paramHash ) = @_;
3060              
3061             #
3062             # it is default or not
3063             #
3064 0   0       $paramHash{siteGUID} ||= $self->{siteGUID};
3065              
3066             #
3067             # set the type to page if the id itself is a page
3068             #
3069 0           my ( $type ) = @{$self->runSQL( SQL => "select element_type from data where guid='" . $self->safeSQL( $paramHash{guid} ) . "' and site_guid='" . $self->safeSQL( $paramHash{siteGUID} ) . "'" )};
  0            
3070              
3071             #
3072             # if its not page loop though till it finds what page its on
3073             #
3074 0           my $isDefault = 0;
3075 0           my $recurCap = 0;
3076 0   0       while ( $paramHash{guid} && ( $type ne 'page' || $type ne 'home' ) && $recurCap < 100 ) {
      0        
      0        
3077 0           my ( $defaultElement ) = @{$self->runSQL( SQL => "select default_element from data where guid='" . $self->safeSQL( $paramHash{guid} ) . "' and site_guid='" . $self->safeSQL( $paramHash{siteGUID} ) . "'" )};
  0            
3078 0           ( $paramHash{guid}, $type ) = @{$self->runSQL( SQL => "select parent,data.element_type from guid_xref left join data on data.guid=parent where child='" . $self->safeSQL( $paramHash{guid} ) . "' and guid_xref.site_guid='" . $self->safeSQL( $paramHash{siteGUID} ) . "'")};
  0            
3079 0 0 0       if ( !$isDefault && $defaultElement ) { $isDefault = 1 }
  0            
3080 0           $recurCap++;
3081             }
3082              
3083             #
3084             # if id is blank that means we are updating a home page element
3085             #
3086 0 0 0       if ( !$type || $isDefault > 0 || $isDefault < 0) {
      0        
3087 0           $self->saveExtra( table => 'data', siteGUID => $paramHash{siteGUID}, field => 'dateUpdated', value => time );
3088             }
3089              
3090             #
3091             # if is default then update ALL pages
3092             #
3093 0 0         if ( $isDefault ) {
3094 0           $self->saveExtra( table => 'data', siteGUID => $paramHash{siteGUID}, field => 'dateUpdated', value => time );
3095 0           my @pageList = @{$self->runSQL( SQL => "select guid from data where data.site_guid='" . $self->safeSQL( $paramHash{siteGUID} ) . "' and (data.element_type='page' or data.element_type='home')" )};
  0            
3096 0           while ( @pageList ) {
3097 0           my $pageId = shift @pageList;
3098 0           $self->saveExtra( table => 'data', siteGUID => $paramHash{siteGUID}, guid => $pageId, field => 'dateUpdated', value => time );
3099             }
3100             }
3101              
3102             #
3103             # if the type is page, then just update that page
3104             #
3105 0 0 0       if ( $type eq 'page' || $type eq 'home' ) {
3106 0           $self->saveExtra( table => 'data', siteGUID => $paramHash{siteGUID}, guid => $paramHash{guid}, field => 'dateUpdated', value => time );
3107             }
3108 0           return;
3109             }
3110              
3111              
3112             =head2 homeGUID
3113              
3114             Return the guid for the home page. Without any paramanters it will return the home page guid for the current site.
3115              
3116             =cut
3117              
3118             sub homeGUID {
3119 0     0 1   my ( $self, $site_guid ) = @_;
3120              
3121             #
3122             # blindly get the homeGUID of site that isn't our own potently
3123             #
3124 0 0         if ( $site_guid ) {
3125 0           my ( $homeGUID ) = @{$self->runSQL( SQL => "select home_guid from site where guid='" . $self->safeSQL( $site_guid ) . "'" )};
  0            
3126 0           return $homeGUID;
3127             }
3128              
3129             #
3130             # if is not set, set it and create the page
3131             #
3132 0           return $self->siteValue('homeGUID');
3133             }
3134              
3135              
3136             =head2 randomizeArray
3137              
3138             need doc
3139              
3140             =cut
3141              
3142             sub randomizeArray {
3143 0     0 1   my ( $self, $dataRef ) = @_;
3144 0           my $i = @$dataRef;
3145 0           while ( $i-- ) {
3146 0           my $j = int rand ( $i + 1 );
3147 0           @$dataRef[$i,$j] = @$dataRef[$j,$i];
3148             }
3149 0           return $dataRef;
3150             }
3151              
3152              
3153             =head2 sortDataByAlpha
3154              
3155             need doc
3156              
3157             =cut
3158              
3159             sub sortDataByAlpha {
3160 0     0 1   my ( $self, $sortId, @data ) = @_;
3161 0           return ( map{$_->[1]} sort {$a->[0] cmp $b->[0]} map{[$_->{$sortId},$_]} @data )
  0            
  0            
  0            
3162             }
3163              
3164              
3165             =head2 sortDataByNumber
3166              
3167             need doc
3168              
3169             =cut
3170              
3171             sub sortDataByNumber {
3172 0     0 1   my ( $self, $sortId, @data ) = @_;
3173 0           return (map{$_->[1]} sort {$a->[0] <=> $b->[0]} map{[$_->{$sortId},$_]} @data)
  0            
  0            
  0            
3174             }
3175              
3176              
3177              
3178             #
3179             # Set the data records current parent. If more than one
3180             # parent, one will be chosen at random
3181             #
3182             sub _setPageGUID {
3183 0     0     my ( $self, %paramHash ) =@_;
3184              
3185 0           my $guid = $paramHash{guid};
3186 0           my $depth = $paramHash{depth};
3187              
3188             #
3189             # hang on to this so we can do a DB update to this
3190             #
3191 0           my $updateGUID = $guid;
3192              
3193             #
3194             # set the depth to how far you will look before giving up
3195             #
3196 0   0       $depth ||= 10;
3197              
3198             #
3199             # set the cap counter
3200             #
3201 0           my $recurCap = 0;
3202              
3203             #
3204             # get the inital type
3205             #
3206 0           my $pageGUID = 0;
3207 0           my ( $type ) = @{$self->runSQL( SQL => "select element_type from data where guid='" . $self->safeSQL( $guid ) . "'" )};
  0            
3208              
3209             #
3210             # recursivly head down till you get "page" or "" as refrence.
3211             #
3212 0   0       while ( $type ne 'page' && $type ne 'home' && $guid ) {
      0        
3213 0           my @idsAndTypes = @{$self->runSQL( SQL => "select parent,element_type from guid_xref left join data on data.guid=parent where child='" . $self->safeSQL( $guid ) . "'" )};
  0            
3214 0           while (@idsAndTypes) {
3215 0           $guid = shift @idsAndTypes;
3216 0           my $listType = shift @idsAndTypes;
3217 0 0         if ( $listType eq 'page' ) {
3218 0           $pageGUID = $guid;
3219 0           $type = 'page';
3220             }
3221             }
3222              
3223             #
3224             # give up after 5
3225             #
3226 0 0         if ( $recurCap > 5 ) { $type = 'page'; $pageGUID = 0 }
  0            
  0            
3227 0           $recurCap++;
3228             }
3229              
3230             #
3231             # set the data record
3232             #
3233 0           $self->runSQL( SQL => "update data set page_guid='". $self->safeSQL( $pageGUID ) . "' where guid='" . $self->safeSQL( $updateGUID ) . "'" );
3234              
3235 0           return $pageGUID;
3236             }
3237              
3238              
3239             #
3240             # remove all the data orphaned by a delete
3241             #
3242             sub _deleteOrphanedData {
3243 0     0     my ( $self, $table, $field, $refTable, $refField, $extraWhere, $DBH ) = @_;
3244              
3245             #
3246             # get the vars set for pre-processing
3247             #
3248 0           my $keepDeleting = 1;
3249              
3250             #
3251             # keep looping till either we are endless or
3252             #
3253 0           while ( $keepDeleting ) {
3254              
3255             #
3256             # create the SQL that will be used for the delete and the reflective query
3257             #
3258 0           my $fromSQL = "from " . $table . " where " . $table . " . " . $field . " in (select " . $field . " from (select distinct " . $table . "." . $field . " from " . $table . " left join " . $refTable . " on " . $refTable . "." . $refField . " = " . $table . "." . $field . " where " . $refTable . "." . $refField . " is null ".$extraWhere.") as delete_list)";
3259              
3260             #
3261             # do the actual delete
3262             #
3263 0           $self->runSQL( DBH => $DBH, SQL => "delete " . $fromSQL );
3264              
3265             #
3266             # if we are talking about the data field, lets do the same thing to the data cache table
3267             #
3268 0 0         if ( $table eq 'data' ) {
3269 0           $self->runSQL( DBH => $DBH, SQL => "delete from " . $table . "_cache where " . $table . "_cache . " . $field . " in (select " . $field . " from (select distinct " . $table . "_cache." . $field . " from " . $table . "_cache left join " . $refTable . " on " . $refTable . "." . $refField . " = " . $table . "_cache." . $field . " where " . $refTable . "." . $refField . " is null " . $extraWhere . ") as delete_list)" );
3270             }
3271              
3272             #
3273             # run the same fromSQL and see if anything is left
3274             #
3275 0           ( $keepDeleting ) = @{$self->runSQL( DBH => $DBH, SQL => "select 1 " . $fromSQL )};
  0            
3276             }
3277              
3278 0           return;
3279             }
3280              
3281              
3282             #
3283             # Delete a guid XRef
3284             #
3285             sub _deleteXRef {
3286 0     0     my ( $self, $child, $parent, $siteGUID ) = @_;
3287 0           return $self->runSQL( SQL => "delete from guid_xref where child='" . $self->safeSQL( $child ) . "' and parent='" . $self->safeSQL( $parent ) . "' and site_guid='" . $self->safeSQL( $siteGUID ) . "'");
3288             }
3289              
3290              
3291             #
3292             # Lookup all the elements and return the hash
3293             # This does NOT pull back schema and scripts. This is for lean element lookups
3294             #
3295             sub _fullElementHash {
3296 0     0     my ( $self, %paramHash ) = @_;
3297              
3298 0 0         if ( !keys %{$self->{_fullElementHashCache}} ) {
  0            
3299              
3300             #
3301             # if your in an admin page, you will need this so you can see the stuff in scope for the tree views
3302             # it doesn't matter if it caches it, because these are ajax calls limited only to themselves
3303             #
3304              
3305             #
3306             # get the elementArray
3307             #
3308 0           my $elementArray = $self->runSQL( SQL => "select guid, plugin, type, class_prefix, css_devel, js_devel, title, tags, parent, ord, site_guid, root_element, public, checkedout from element" );
3309              
3310             #
3311             # Push the elementHash into the Cache
3312             #
3313 0           %{$self->{_fullElementHashCache}} = %{$self->{elementHash}};
  0            
  0            
3314              
3315              
3316 0           while ( @{$elementArray} ) {
  0            
3317 0           my $guid = shift @{$elementArray};
  0            
3318 0           $self->{_fullElementHashCache}->{$guid}{guid} = $guid;
3319 0           $self->{_fullElementHashCache}->{$guid}{plugin} = shift @{$elementArray};
  0            
3320 0           $self->{_fullElementHashCache}->{$guid}{type} = shift @{$elementArray};
  0            
3321 0           $self->{_fullElementHashCache}->{$guid}{classPrefix} = shift @{$elementArray};
  0            
3322 0           $self->{_fullElementHashCache}->{$guid}{cssDevel} = shift @{$elementArray};
  0            
3323 0           $self->{_fullElementHashCache}->{$guid}{jsDevel} = shift @{$elementArray};
  0            
3324 0           $self->{_fullElementHashCache}->{$guid}{title} = shift @{$elementArray};
  0            
3325 0           $self->{_fullElementHashCache}->{$guid}{tags} = shift @{$elementArray};
  0            
3326 0           $self->{_fullElementHashCache}->{$guid}{parent} = shift @{$elementArray};
  0            
3327 0           $self->{_fullElementHashCache}->{$guid}{ord} = shift @{$elementArray};
  0            
3328 0           $self->{_fullElementHashCache}->{$guid}{siteGUID} = shift @{$elementArray};
  0            
3329 0           $self->{_fullElementHashCache}->{$guid}{rootElement} = shift @{$elementArray};
  0            
3330 0           $self->{_fullElementHashCache}->{$guid}{public} = shift @{$elementArray};
  0            
3331 0           $self->{_fullElementHashCache}->{$guid}{checkedout} = shift @{$elementArray};
  0            
3332             }
3333              
3334             #
3335             # Do alpha sorting and add parent refernces if needed
3336             #
3337 0           my $alphaOrd = 0;
3338 0           for my $guid ( sort { $self->{_fullElementHashCache}->{$a}{title} cmp $self->{_fullElementHashCache}->{$b}{title} } keys %{$self->{_fullElementHashCache}}) {
  0            
  0            
3339 0           $alphaOrd++;
3340 0           $self->{_fullElementHashCache}->{$guid}{alphaOrd} = $alphaOrd;
3341 0           my $type = $self->{_fullElementHashCache}->{$guid}{type};
3342              
3343 0 0         if ( $type ) {
3344 0           $self->{_fullElementHashCache}->{$type}{guid} = $guid;
3345 0           $self->{_fullElementHashCache}->{$type}{parent} = $self->{_fullElementHashCache}->{$guid}{parent};
3346             }
3347             }
3348             }
3349 0           return %{$self->{_fullElementHashCache}};
  0            
3350             }
3351              
3352              
3353             #
3354             # creation of a record if needed, and also set pins and guids
3355             #
3356             sub _recordInit {
3357 0     0     my ( $self, %paramHash ) = @_;
3358              
3359             #
3360             # lets make sure we are not updateing the same record or adding a new one we shouldn't
3361             #
3362 0 0         if ( !$paramHash{guid} ) {
3363              
3364             #
3365             # set the dirived stuff so nobody gets sneeky and tries to pass it to the procedure
3366             #
3367 0   0       $paramHash{siteGUID} ||= $self->{siteGUID};
3368 0   0       $paramHash{_guidLeader} ||= 'r';
3369 0           $paramHash{siteGUID} = $self->safeSQL( $paramHash{siteGUID} );
3370 0           $paramHash{guid} = $self->createGUID( $paramHash{_guidLeader} );
3371              
3372             #
3373             # if newGUID is set, lets use that as the guid
3374             #
3375 0 0         if ( $paramHash{newGUID} ) {
3376 0           $paramHash{guid} = $paramHash{newGUID};
3377             }
3378              
3379 0           $self->runSQL( DBH => $paramHash{DBH}, SQL => "insert into " . $self->safeSQL( $paramHash{_table} ) . " (guid,site_guid,created_date) values ('" . $self->safeSQL( $paramHash{guid} ) . "','" . $self->safeSQL( $paramHash{siteGUID} ) . "','" . $self->formatDate( format => 'SQL' ) . "')" );
3380              
3381              
3382             #
3383             # Global pin support, if you have a pin field, but its not populated, populate it.
3384             #
3385 0 0 0       if ( !$paramHash{pin} && $self->{dataSchema}{$paramHash{_table}}{pin}{type} ) {
3386            
3387             #
3388             # set the dirived stuff so nobody gets sneeky and tries to pass it to the procedure
3389             #
3390 0           $paramHash{pin} = $self->createPin();
3391 0           $self->runSQL( DBH => $paramHash{DBH}, SQL => "update " . $self->safeSQL( $paramHash{_table} ) . " set pin='" . $self->safeSQL( $paramHash{pin} ) . "' where guid='" . $self->safeSQL( $paramHash{guid} ) . "'" );
3392             }
3393             }
3394 0           return %paramHash;
3395             }
3396              
3397              
3398             #
3399             # return a generic record hash
3400             # Pass: table, where
3401             #
3402             sub _recordHash {
3403 0     0     my ( $self, %paramHash ) = @_;
3404              
3405             #
3406             # eat 's in table for safety
3407             #
3408 0           $paramHash{table} =~ s/'//sg;
3409              
3410             #
3411             # define the SQL starter statement
3412             #
3413 0           my $SQL = "select ";
3414              
3415             #
3416             # if fields was not passed, we assume we have matching field and keys based on the schema
3417             #
3418 0           for my $field ( keys %{$self->{dataSchema}{$paramHash{table}}} ) {
  0            
3419 0 0         if ( $self->{dataSchema}{$paramHash{table}}{$field}{name} ) {
3420             # for safety lets eat any tic in the field name
3421 0           $field =~ s/'//sg;
3422 0           $SQL .= "'" . $self->safeSQL( $self->{dataSchema}{$paramHash{table}}{$field}{name} ) . "'," . $field . ",";
3423             }
3424             }
3425 0           $SQL =~ s/,$//sg;
3426              
3427             #
3428             # do extra value if this table has one
3429             #
3430 0 0         if ( $self->{dataSchema}{$paramHash{_table}}{extra_value}{type} ) { $SQL .= ',extra_value' }
  0            
3431              
3432             #
3433             # get the hash
3434             #
3435 0           my @returnArray = @{$self->runSQL( DBH => $paramHash{DBH}, SQL => $SQL . " from " . $paramHash{table} . " where " . $paramHash{where} )};
  0            
3436              
3437             #
3438             # pop off the ext values
3439             #
3440 0 0         if ( $self->{dataSchema}{$paramHash{_table}}{extra_value}{type} ) {
3441 0           my $extraValue = pop( @returnArray );
3442 0           return $self->mergeExtra( $extraValue, @returnArray );
3443             }
3444              
3445             #
3446             # if no ext value, then return the whole thing
3447             #
3448 0           return @returnArray;
3449             }
3450              
3451              
3452             #
3453             # save a record with generic record structure
3454             #
3455             sub _recordSave {
3456 0     0     my ( $self, %paramHash ) = @_;
3457              
3458             #
3459             # for completeness lets hold on to this so we can return it
3460             #
3461 0           my %paramHolder = %paramHash;
3462              
3463             #
3464             # define the SQL starter statement
3465             #
3466 0           my $SQL = "update ".$self->safeSQL( $paramHash{_table} )." set ";
3467              
3468             #
3469             # if fields was not passed, we assume we have matching field and keys based on the schema
3470             #
3471 0 0 0       if ( !$paramHash{_keys} || !$paramHash{_fields} ) {
3472 0           for my $field ( keys %{$self->{dataSchema}{$paramHash{_table}}} ) {
  0            
3473 0 0         if ( $self->{dataSchema}{$paramHash{_table}}{$field}{save} ) {
3474 0           $paramHash{_keys} .= $self->{dataSchema}{$paramHash{_table}}{$field}{name} . '|';
3475 0           $paramHash{_fields} .= $field . '|';
3476             }
3477             }
3478 0           $paramHash{_keys} =~ s/\|$//sg;
3479 0           $paramHash{_fields} =~ s/\|$//sg;
3480             }
3481              
3482             #
3483             # make arrays usable
3484             #
3485 0           my @fields = split( /\|/, $paramHash{_fields} );
3486 0           my @fieldKeys = split( /\|/, $paramHash{_keys} );
3487              
3488             #
3489             # add each field thats a core field
3490             #
3491 0           for my $i ( 0 .. $#fields ) {
3492 0           $SQL .= $fields[$i] . "='" . $self->safeSQL( $paramHash{$fieldKeys[$i]} ) . "'," ;
3493             #
3494             # for the next step delete the keys that should not be updated
3495             #
3496 0           delete $paramHash{$fieldKeys[$i]};
3497             }
3498              
3499             #
3500             # trim off last ,
3501             #
3502 0           $SQL =~ s/,$//sg;
3503              
3504             #
3505             # default key is guid
3506             #
3507 0   0       $paramHash{keyField} ||= 'guid';
3508 0   0       $paramHash{keyValueKey} ||= 'guid';
3509              
3510             #
3511             # add scope to the statement
3512             #
3513 0           $SQL .= " where " . $self->safeSQL( $paramHash{keyField} ) . "='" . $self->safeSQL( $paramHash{$paramHash{keyValueKey}} ) . "'";
3514              
3515 0           $self->runSQL( DBH => $paramHash{DBH}, SQL => $SQL );
3516              
3517             #
3518             # save the keys in the ext field;
3519             #
3520 0           my $keyReg = $paramHash{_keys};
3521 0           for my $key ( keys %paramHash ) {
3522 0 0 0       if ( $key !~ /^_/ && $key !~ /^(guid|site_guid|created_date|createdDate|siteGUID|pin)$/ ) {
3523 0 0         if ( $self->{dataSchema}{$paramHash{_table}}{extra_value}{type} ) {
3524 0           $self->saveExtra( DBH => $paramHash{DBH}, table => $paramHash{_table}, guid => $paramHash{guid}, field => $key, value => $paramHash{$key} );
3525             }
3526             }
3527             }
3528 0           return %paramHolder;
3529             }
3530              
3531              
3532             #
3533             # Pass keywords and field list, and create a wellformed where statement for keyword
3534             # searches
3535             #
3536             sub _getKeywordSQL {
3537 0     0     my ( $self, $keywords, @likeFields ) = @_;
3538             #
3539             # Grab everything that is in quotes
3540             #
3541 0           my @exactMatches;
3542 0           while ( $keywords =~ /"/ ) {
3543 0           $keywords =~ /(".*?")/g;
3544 0           my $currentMatch = $1;
3545 0           $keywords =~ s/$currentMatch//g;
3546 0           $currentMatch =~ s/"//g;
3547 0           push @exactMatches, $currentMatch;
3548             }
3549              
3550             #
3551             # split them up and add the exact matches
3552             #
3553 0           my @keywordsSplit = split( ' ', $keywords );
3554 0           push @keywordsSplit, @exactMatches;
3555              
3556             #
3557             # build the SQL
3558             #
3559 0           my $keywordSQL;
3560 0           foreach my $keyword ( @keywordsSplit ) {
3561 0 0         if ( $keyword ) {
3562 0           my $fieldSQL;
3563 0           foreach my $likeField ( @likeFields ) {
3564 0           $fieldSQL .= $self->safeSQL( $likeField ) . " LIKE '%".
3565             $self->safeSQL( $keyword ) . "%' or ";
3566             }
3567 0           $fieldSQL =~ s/ or $//sg;
3568 0 0         if ( $fieldSQL ) { $keywordSQL .= "( " . $fieldSQL . " ) and " }
  0            
3569             }
3570             }
3571              
3572             #
3573             # kILL THE last and and then wrap it in parans so it will fit will in sql statements
3574             #
3575 0           $keywordSQL =~ s/\s*and\s*$//sg;
3576 0           return $keywordSQL;
3577             }
3578              
3579              
3580             #
3581             # Save a guid XRef
3582             #
3583             sub _saveXRef {
3584 0     0     my ( $self, $child, $layout, $ord, $parent, $siteGUID ) = @_;
3585              
3586             #
3587             # set defaults to ensure the insert dosen't fail
3588             #
3589 0   0       $ord ||= 0;
3590            
3591             #
3592             # delete the old one if its there
3593             #
3594 0           $self->_deleteXRef( $child, $parent, $siteGUID );
3595            
3596             #
3597             # add the new one
3598             #
3599 0           return $self->runSQL( SQL => "insert into guid_xref (child,layout,ord,parent,site_guid) values ('" . $self->safeSQL( $child ) . "','" . $self->safeSQL( $layout ) . "','" . $self->safeSQL( $ord ) . "','".$self->safeSQL( $parent ) . "','" . $self->safeSQL( $siteGUID ) . "')" );
3600             }
3601              
3602              
3603             =head1 AUTHOR
3604              
3605             Nate Lewis, C<< >>
3606              
3607             =head1 BUGS
3608              
3609             Please report any bugs or feature requests to C, or through
3610             the web interface at L. I will be notified, and then you'll
3611             automatically be notified of progress on your bug as I make changes.
3612              
3613              
3614              
3615              
3616             =head1 SUPPORT
3617              
3618             You can find documentation for this module with the perldoc command.
3619              
3620             perldoc FWS::V2::Database
3621              
3622              
3623             You can also look for information at:
3624              
3625             =over 4
3626              
3627             =item * RT: CPAN's request tracker (report bugs here)
3628              
3629             L
3630              
3631             =item * AnnoCPAN: Annotated CPAN documentation
3632              
3633             L
3634              
3635             =item * CPAN Ratings
3636              
3637             L
3638              
3639             =item * Search CPAN
3640              
3641             L
3642              
3643             =back
3644              
3645              
3646             =head1 ACKNOWLEDGEMENTS
3647              
3648              
3649             =head1 LICENSE AND COPYRIGHT
3650              
3651             Copyright 2013 Nate Lewis.
3652              
3653             This program is free software; you can redistribute it and/or modify it
3654             under the terms of either: the GNU General Public License as published
3655             by the Free Software Foundation; or the Artistic License.
3656              
3657             See http://dev.perl.org/licenses/ for more information.
3658              
3659              
3660             =cut
3661              
3662             1; # End of FWS::V2::Database