Passed
Push — dpa_warnings3 ( 07faf2...85d2bf )
by David
19:22 queued 09:32
created

app_form()   B

Complexity

Conditions 7
Paths 2

Size

Total Lines 34
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 26
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 34
rs 8.5706
1
<?php
2
// This file is part of BOINC.
3
// https://boinc.berkeley.edu
4
// Copyright (C) 2024 University of California
5
//
6
// BOINC is free software; you can redistribute it and/or modify it
7
// under the terms of the GNU Lesser General Public License
8
// as published by the Free Software Foundation,
9
// either version 3 of the License, or (at your option) any later version.
10
//
11
// BOINC is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
// See the GNU Lesser General Public License for more details.
15
//
16
// You should have received a copy of the GNU Lesser General Public License
17
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
18
19
// interface for:
20
//      - viewing details of BUDA science apps and variants
21
//      - managing these if user has permission
22
//
23
// in the following, 'app' means BUDA science app
24
// and 'variant' means a variant of one of these (e.g. CPU, GPU)
25
26
require_once('../inc/util.inc');
27
require_once('../inc/sandbox.inc');
28
require_once('../inc/keywords.inc');
29
require_once('../inc/submit_util.inc');
30
require_once('../inc/buda.inc');
31
32
display_errors();
33
34
$buda_root = "../../buda_apps";
35
36
// scan BUDA apps and variants, and write a file 'buda_plan_classes'
37
// in the project dir with list of plan classes
38
//
39
function write_plan_class_file() {
40
    $pcs = [];
41
    global $buda_root;
42
    $apps = get_buda_apps();
43
    foreach ($apps as $app) {
44
        $vars = get_buda_variants($app);
45
        $pcs = array_merge($pcs, $vars);
46
    }
47
    $pcs = array_unique($pcs);
48
    file_put_contents(
49
        "../../buda_plan_classes",
50
        implode("\n", $pcs)."\n"
51
    );
52
}
53
54
// show list of BUDA apps and variants,
55
// w/ buttons for adding and deleting
56
//
57
function app_list($notice=null) {
58
    global $buda_root;
59
    if (!is_dir($buda_root)) {
60
        mkdir($buda_root);
61
    }
62
    page_head('Manage BUDA apps');
63
    if ($notice) {
64
        echo "$notice <p>\n";
65
    }
66
    text_start();
67
    echo "
68
        <p>BUDA lets you submit Docker jobs using a web interface.
69
        <a href=https://github.com/BOINC/boinc/wiki/BUDA-overview>Learn more</a>.
70
        <p>
71
        <h3>BUDA science apps</h3>
72
    ";
73
74
    $apps = get_buda_apps();
75
    foreach ($apps as $app) {
76
        show_app($app);
77
    }
78
    echo '<hr>';
79
    show_button_small('buda.php?action=app_form', 'Add science app');
80
    text_end();
81
    page_tail();
82
}
83
84
function show_app($dir) {
85
    global $buda_root;
86
    $desc = null;
87
    $desc_path = "$buda_root/$dir/desc.json";
88
    $desc = json_decode(file_get_contents($desc_path));
89
    echo '<hr>';
90
    echo sprintf('<h3>%s</h3>', $desc->long_name);
91
    echo sprintf('<a href=buda.php?action=app_details&name=%s>Details</a>',
92
        $desc->name
93
    );
94
    $vars = get_buda_variants($dir);
95
    if ($vars) {
96
        echo "<p>Variants:<ul>";
97
        foreach ($vars as $var) {
98
            echo sprintf(
99
                '<li><a href=buda.php?action=variant_view&app=%s&variant=%s>%s</a>',
100
                $dir, $var, $var
101
            );
102
        }
103
        echo '</ul>';
104
    } else {
105
        echo '<p>No variants';
106
    }
107
    echo "<p>";
108
}
109
110
function file_row($app, $variant, $dir, $f) {
111
    [$md5, $size] = parse_info_file("$dir/.md5/$f");
112
    table_row(
113
        "<a href=buda.php?action=view_file&app=$app&variant=$variant&fname=$f>$f</a>",
114
        $size,
115
        $md5
116
    );
117
}
118
119
function variant_view() {
120
    global $buda_root, $manage_access;
121
    $app = get_str('app');
122
    if (!is_valid_filename($app)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
123
    $variant = get_str('variant');
124
    if (!is_valid_filename($variant)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
125
    page_head("BUDA: variant '$variant' of science app '$app'");
126
    $dir = "$buda_root/$app/$variant";
127
    $desc = json_decode(file_get_contents("$dir/variant.json"));
128
    echo "<h3>Files</h3>";
129
    start_table();
130
    table_header('Dockerfile', 'size', 'md5');
131
    file_row($app, $variant, $dir, $desc->dockerfile);
132
    table_header('App files', '', '');
133
    foreach ($desc->app_files as $f) {
134
        file_row($app, $variant, $dir, $f);
135
    }
136
    table_header('Auto-generated files', '', '');
137
    file_row($app, $variant, $dir, 'template_in');
138
    file_row($app, $variant, $dir, 'template_out');
139
    file_row($app, $variant, $dir, 'variant.json');
140
    end_table();
141
    echo '<hr>';
142
143
    start_table();
144
    row2(
145
        'Input filenames:',
146
        implode(',', $desc->input_file_names)
147
    );
148
    row2(
149
        'Output filenames:',
150
        implode(',', $desc->output_file_names)
151
    );
152
    if (!empty($desc->max_total)) {
153
        row2('Max total instances per job:', $desc->max_total);
154
    } else {
155
        row2('Max total instances per job:', '1');
156
    }
157
    if (!empty($desc->min_nsuccess)) {
158
        row2('Target successful instances per job:', $desc->min_nsuccess);
159
    } else {
160
        row2('Target successful instances per job:', '1');
161
    }
162
    if (!empty($desc->max_delay_days)) {
163
        row2('Max job turnaround time, days:', $desc->max_delay_days);
164
    } else {
165
        row2('Max job turnaround time, days:', '7');
166
    }
167
    end_table();
168
169
    if ($manage_access) {
170
        echo '<p>';
171
        show_button(
172
            "buda.php?action=variant_delete&app=$app&variant=$variant",
173
            'Delete variant',
174
            null,
175
            'btn btn-xs btn-warning'
176
        );
177
    }
178
    page_tail();
179
}
180
181
// form for creating app variant.
182
// Currently doesn't support indirect files.
183
// doing this would require checkboxes for indirect
184
//
185
// Could have other stuff like
186
//      - min_quorum, max_total_results
187
//      - rsc_disk_bound, rsc_memory_bound
188
// or does this belong in job submission?
189
//
190
function variant_form($user) {
191
    $sbitems = sandbox_select_items($user);
192
    $app = get_str('app');
193
    if (!is_valid_filename($app)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
194
195
    page_head_select2("Create a variant of BUDA app $app");
196
    echo "
197
        Details are <a href=https://github.com/BOINC/boinc/wiki/BUDA-job-submission#adding-a-variant>here</a>.
198
    ";
199
    $sb = '<br><small>From your <a href=sandbox.php>file sandbox</a></small>';
200
    $pc = '<br><small>Specify
201
    <a href=https://github.com/BOINC/boinc/wiki/AppPlan>GPU and other requirements</a>';
202
    form_start('buda.php');
203
    form_input_hidden('app', $app);
204
    form_input_hidden('action', 'variant_action');
205
    form_input_text("Plan class$pc", 'variant');
206
    form_select("Dockerfile$sb", 'dockerfile', $sbitems);
207
    form_select2_multi("Application files$sb", 'app_files', $sbitems, null);
208
    form_input_text(
209
        'Input file names<br><small>Space-separated</small>',
210
        'input_file_names'
211
    );
212
    form_input_text(
213
        'Output file names<br><small>Space-separated</small>',
214
        'output_file_names'
215
    );
216
    form_input_text(
217
        'Run at most this many total instances of each job',
218
        'max_total',
219
        '1'
220
    );
221
    form_input_text(
222
        'Get this many successful instances of each job
223
            <br><small>(subject to the above limit)</small>
224
        ',
225
        'min_nsuccess',
226
        '1'
227
    );
228
    form_input_text(
229
        'Max job turnaround time, days',
230
        'max_delay_days',
231
        '7'
232
    );
233
    form_submit('OK');
234
    form_end();
235
    page_tail();
236
}
237
238
function buda_file_phys_name($app, $variant, $md5) {
239
    return sprintf('buda_%s_%s_%s', $app, $variant, $md5);
240
}
241
242
// copy file from sandbox to variant dir, and stage to download hier
243
//
244
function copy_and_stage_file($user, $fname, $dir, $app, $variant) {
245
    copy_sandbox_file($user, $fname, $dir);
246
    [$md5, $size] = parse_info_file("$dir/.md5/$fname");
247
    $phys_name = buda_file_phys_name($app, $variant, $md5);
248
    stage_file_aux("$dir/$fname", $md5, $size, $phys_name);
249
    return $phys_name;
250
}
251
252
// create templates and put them in variant dir
253
//
254
function create_templates($variant, $variant_desc, $dir) {
255
    // input template
256
    //
257
    $x = "<input_template>\n";
258
    $ninfiles = 1 + count($variant_desc->input_file_names) + count($variant_desc->app_files);
259
    for ($i=0; $i<$ninfiles; $i++) {
260
        $x .= "   <file_info>\n      <sticky/>\n      <no_delete/>\n      <executable/>\n   </file_info>\n";
261
    }
262
    $x .= "   <workunit>\n";
263
    $x .= file_ref_in($variant_desc->dockerfile);
264
    foreach ($variant_desc->app_files as $fname) {
265
        $x .= file_ref_in($fname);
266
    }
267
    foreach ($variant_desc->input_file_names as $fname) {
268
        $x .= file_ref_in($fname);
269
    }
270
    if (strstr($variant, 'cpu')) {
271
        $x .= "      <plan_class></plan_class>\n";
272
    } else {
273
        $x .= "      <plan_class>$variant</plan_class>\n";
274
    }
275
276
    // replication params
277
    //
278
    $x .= sprintf("      <target_nresults>%d</target_nresults>\n",
279
        $variant_desc->min_nsuccess
280
    );
281
    $x .= sprintf("      <min_quorum>%d</min_quorum>\n",
282
        $variant_desc->min_nsuccess
283
    );
284
    $x .= sprintf("      <max_total_results>%d</max_total_results>\n",
285
        $variant_desc->max_total
286
    );
287
288
    $x .= sprintf("      <max_delay>%f</max_delay>\n",
289
        $variant_desc->max_delay_days * 86400.
290
    );
291
292
    $x .= "   </workunit>\n<input_template>\n";
293
    file_put_contents("$dir/template_in", $x);
294
295
    // output template
296
    //
297
    $x = "<output_template>\n";
298
    $i = 0;
299
    foreach ($variant_desc->output_file_names as $fname) {
300
        $x .= file_info_out($i++);
301
    }
302
    $x .= "   <result>\n";
303
    $i = 0;
304
    foreach ($variant_desc->output_file_names as $fname) {
305
        $x .= file_ref_out($i++, $fname);
306
    }
307
    $x .= "   </result>\n</output_template>\n";
308
    file_put_contents("$dir/template_out", $x);
309
}
310
311
// create variant
312
//
313
function variant_action($user) {
314
    global $buda_root;
315
    $variant = get_str('variant');
316
    if (!$variant) $variant = 'cpu';
317
    if (!is_valid_filename($variant)) {
318
        error_page(filename_rules());
319
    }
320
    $app = get_str('app');
321
    if (!is_valid_filename($app)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
322
    $dockerfile = get_str('dockerfile');
323
    if (!is_valid_filename($dockerfile)) {
324
        error_page("Invalid dockerfile name: ".filename_rules());
325
    }
326
    $app_files = get_array('app_files');
327
    foreach ($app_files as $fname) {
328
        if (!is_valid_filename($fname)) {
329
            error_page("Invalid app file name: ".filename_rules());
330
        }
331
    }
332
    $min_nsuccess = get_int('min_nsuccess');
333
    if ($min_nsuccess <= 0) {
334
        error_page('Must specify a positive number of successful instances.');
335
    }
336
    $max_total = get_int('max_total');
337
    if ($max_total <= 0) {
338
        error_page('Must specify a positive max number of instances.');
339
    }
340
    if ($min_nsuccess > $max_total) {
341
        error_page('Target # of successful instances must be <= max total');
342
    }
343
    $max_delay_days = get_str('max_delay_days');
344
    if (!is_numeric($max_delay_days)) {
345
        error_page('Must specify max delay');
346
    }
347
    $max_delay_days = floatval($max_delay_days);
348
    if ($max_delay_days <= 0) {
349
        error_page('Must specify positive max delay');
350
    }
351
    $input_file_names = get_str('input_file_names', true);
352
    $output_file_names = explode(' ', get_str('output_file_names'));
353
    if ($input_file_names) {
354
        $input_file_names = explode(' ', $input_file_names);
355
        foreach ($input_file_names as $fname) {
356
            if (!is_valid_filename($fname)) {
357
                error_page("Invalid input file name: ".filename_rules());
358
            }
359
        }
360
    } else {
361
        $input_file_names = [];
362
    }
363
    foreach ($output_file_names as $fname) {
364
        if (!is_valid_filename($fname)) {
365
            error_page("Invalid output file name: ".filename_rules());
366
        }
367
    }
368
369
    if (file_exists("$buda_root/$app/$variant")) {
370
        error_page("Variant '$variant' already exists.");
371
    }
372
    $dir = "$buda_root/$app/$variant";
373
    mkdir($dir);
374
    mkdir("$dir/.md5");
375
376
    // collect variant params into a struct
377
    //
378
    $desc = new StdClass;
379
    $desc->dockerfile = $dockerfile;
380
    $desc->app_files = $app_files;
381
    $desc->input_file_names = $input_file_names;
382
    $desc->output_file_names = $output_file_names;
383
    $desc->min_nsuccess = $min_nsuccess;
384
    $desc->max_total = $max_total;
385
    $desc->max_delay_days = $max_delay_days;
386
387
    // copy files from sandbox to variant dir
388
    //
389
    $pname = copy_and_stage_file($user, $dockerfile, $dir, $app, $variant);
390
    $desc->dockerfile_phys = $pname;
391
    $desc->app_files_phys = [];
392
    foreach ($app_files as $fname) {
393
        $pname = copy_and_stage_file($user, $fname, $dir, $app, $variant);
394
        $desc->app_files_phys[] = $pname;
395
    }
396
397
    // write variant params to a JSON file
398
    //
399
    file_put_contents(
400
        "$dir/variant.json",
401
        json_encode($desc, JSON_PRETTY_PRINT)
402
    );
403
404
    create_templates($variant, $desc, $dir);
405
406
    // Note: we don't currently allow indirect file access.
407
    // If we did, we'd need to create job.toml to mount project dir
408
409
    app_list("Variant $variant added for app $app.");
410
}
411
412
function variant_delete() {
413
    global $buda_root;
414
    $app = get_str('app');
415
    if (!is_valid_filename($app)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
416
    $variant = get_str('variant');
417
    if (!is_valid_filename($variant)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
418
    $confirmed = get_str('confirmed', true);
419
    if ($confirmed) {
420
        $dir = "$buda_root/$app/$variant";
421
        if (!file_exists($dir)) error_page('no such variant');
422
        // delete staged files
423
        //
424
        foreach (scandir("$dir/.md5") as $fname) {
425
            if ($fname[0] == '.') continue;
426
            [$md5, $size] = parse_info_file("$dir/.md5/$fname");
427
            $phys_name = buda_file_phys_name($app, $variant, $md5);
428
            $phys_path = download_hier_path($phys_name);
429
            unlink($phys_path);
430
            unlink("$phys_path.md5");
431
        }
432
        system("rm -r $buda_root/$app/$variant", $ret);
433
        if ($ret) {
434
            error_page("delete failed");
435
        }
436
        $notice = "Variant $variant of app $app removed.";
437
        app_list($notice);
438
    } else {
439
        page_head("Confirm");
440
        echo "<p>Are you sure you want to delete variant $variant of BUDA app $app?  <p>";
441
        show_button(
442
            "buda.php?action=variant_delete&app=$app&variant=$variant&confirmed=yes",
443
            "Yes"
444
        );
445
        page_tail();
446
    }
447
}
448
449
function app_delete() {
450
    global $buda_root;
451
    $app = get_str('app');
452
    if (!is_valid_filename($app)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
453
    $confirmed = get_str('confirmed', true);
454
    if ($confirmed) {
455
        $dir = "$buda_root/$app";
456
        if (!file_exists($dir)) error_page('no such app');
457
        $vars = get_buda_variants($app);
458
        if ($vars) {
459
            error_page("You must delete all variants first.");
460
        }
461
        system("rm $buda_root/$app/desc.json", $ret);
462
        system("rmdir $buda_root/$app", $ret);
463
        if ($ret) {
464
            error_page('delete failed');
465
        }
466
        $notice = "App $app removed.";
467
        app_list($notice);
468
    } else {
469
        page_head('Confirm');
470
        echo "<p>Are you sure you want to delete BUDA science app $app?  <p>";
471
        show_button(
472
            "buda.php?action=app_delete&app=$app&confirmed=yes",
473
            "Yes"
474
        );
475
        page_tail();
476
    }
477
}
478
479
function app_form($desc=null) {
480
    page_head_select2($desc?"Edit BUDA app $desc->name":'Create BUDA app');
481
    form_start('buda.php');
482
    form_input_hidden('action', 'app_action');
483
    if ($desc) {
484
        form_input_hidden('edit_name', $desc->name);
485
        form_input_hidden('user_id', $desc->user_id);
486
        form_input_hidden('create_time', $desc->create_time);
487
    } else {
488
        form_input_text('Internal name<br><small>No spaces</small>', 'name');
489
    }
490
    form_input_text('User-visible name', 'long_name',
491
        $desc?$desc->long_name:null
492
    );
493
    form_input_textarea(
494
        'Description<br><small>... of what the app does and of the research goals</small>',
495
        'description',
496
        $desc?$desc->description:null
497
    );
498
    form_select2_multi('Science keywords',
499
        'sci_kw',
500
        keyword_select_options(KW_CATEGORY_SCIENCE),
501
        $desc?$desc->sci_kw:null
502
    );
503
    form_input_text(
504
        'URL of web page describing app',
505
        'url',
506
        !empty($desc->url)?$desc->url:''
507
    );
508
    // don't include location keywords;
509
    // various people may submit jobs to this app
510
    form_submit('OK');
511
    form_end();
512
    page_tail();
513
}
514
515
function app_action($user) {
516
    global $buda_root;
517
    $edit_name = get_str('edit_name', true);
518
    $desc = new StdClass;
519
    if ($edit_name) {
520
        $dir = "$buda_root/$edit_name";
521
        $name = $edit_name;
522
        $desc->user_id = get_int('user_id');
523
        $desc->create_time = get_int('create_time');
524
    } else {
525
        $name = get_str('name');
526
        if (!is_valid_filename($name)) {
527
            error_page(filename_rules());
528
        }
529
        $dir = "$buda_root/$name";
530
        if (file_exists($dir)) {
531
            error_page("App $name already exists.");
532
        }
533
        mkdir($dir);
534
        $desc->user_id = $user->id;
535
        $desc->create_time = time();
536
    }
537
    $desc->name = $name;
538
    $desc->long_name = get_str('long_name');
539
    $desc->description = get_str('description');
540
    $desc->sci_kw = array_map('intval', get_array('sci_kw'));
541
    file_put_contents("$dir/desc.json", json_encode($desc, JSON_PRETTY_PRINT));
542
    header("Location: buda.php");
543
}
544
545
function view_file() {
546
    global $buda_root;
547
    $app = get_str('app');
548
    if (!is_valid_filename($app)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
549
    $variant = get_str('variant');
550
    if (!is_valid_filename($variant)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
551
    $fname = get_str('fname');
552
    if (!is_valid_filename($fname)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
553
    echo "<pre>\n";
554
    $x = file_get_contents("$buda_root/$app/$variant/$fname");
555
    echo htmlspecialchars($x);
556
    echo "</pre>\n";
557
}
558
559
function handle_app_edit() {
560
    global $buda_root;
561
    $name = get_str('name');
562
    app_form(get_buda_desc($name));
563
}
564
565
function app_details() {
566
    global $buda_root, $manage_access;
567
    $name = get_str('name');
568
    $desc = get_buda_desc($name);
569
    if (!$desc) error_page("no desc file $path");
570
    page_head("BUDA app: $desc->long_name");
571
    start_table();
572
    row2('Internal name', $desc->name);
573
    $user = BoincUser::lookup_id($desc->user_id);
574
    row2('Creator',
575
        sprintf('<a href=show_user.php?userid=%d>%s</a>',
576
            $user->id,
577
            $user->name
578
        )
579
    );
580
    row2('Created', date_str($desc->create_time));
581
    row2('Description', $desc->description);
582
    row2('Science keywords', kw_array_to_str($desc->sci_kw));
583
    if ($manage_access) {
584
        row2('',
585
            button_text_small(
586
                sprintf('buda.php?action=%s&name=%s', 'app_edit', $desc->name),
587
                'Edit app info'
588
            )
589
        );
590
    }
591
    $vars = get_buda_variants($name);
592
    if ($vars) {
593
        $x = [];
594
        foreach ($vars as $var) {
595
            $x[] = sprintf('<a href=buda.php?action=variant_view&app=%s&variant=%s>%s</a>',
596
                $name, $var, $var
597
            );
598
        }
599
        row2('Variants', implode('<p>', $x));
600
        if ($manage_access) {
601
            row2('',
602
                button_text_small(
603
                    "buda.php?action=variant_form&app=$name",
604
                    'Add variant'
605
                )
606
            );
607
        }
608
    } else if ($manage_access) {
609
        row2('Variants',
610
            button_text_small(
611
                "buda.php?action=variant_form&app=$name",
612
                'Add variant'
613
            )
614
        );
615
        row2('',
616
            button_text(
617
                "buda.php?action=app_delete&app=$name",
618
                "Delete app",
619
                null,
620
                'btn btn-xs btn-warning'
621
            )
622
        );
623
    }
624
    end_table();
625
    page_tail();
626
}
627
628
// Users with manage access to BUDA can add/delete apps and variants.
629
// Others can just view.
630
// Might want to refine this at some point
631
632
$user = get_logged_in_user();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $user is correct as get_logged_in_user() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
633
$buda_app = BoincApp::lookup("name='buda'");
634
if (!$buda_app) error_page('no buda app');
635
$manage_access = has_manage_access($user, $buda_app->id);
636
637
$action = get_str('action', true);
638
switch ($action) {
639
case 'app_edit':
640
    if (!$manage_access) error_page('no access');
641
    handle_app_edit(); break;
642
case 'app_form':
643
    if (!$manage_access) error_page('no access');
644
    app_form(); break;
645
case 'app_action':
646
    if (!$manage_access) error_page('no access');
647
    app_action($user); break;
648
case 'app_details':
649
    app_details(); break;
650
case 'app_delete':
651
    if (!$manage_access) error_page('no access');
652
    app_delete(); break;
653
case 'variant_view':
654
    variant_view($user); break;
0 ignored issues
show
Unused Code introduced by
The call to variant_view() has too many arguments starting with $user. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

654
    /** @scrutinizer ignore-call */ 
655
    variant_view($user); break;

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
655
case 'variant_form':
656
    if (!$manage_access) error_page('no access');
657
    variant_form($user); break;
658
case 'variant_action':
659
    if (!$manage_access) error_page('no access');
660
    variant_action($user);
661
    write_plan_class_file();
662
    break;
663
case 'variant_delete':
664
    if (!$manage_access) error_page('no access');
665
    variant_delete();
666
    write_plan_class_file();
667
    break;
668
case 'view_file':
669
    view_file(); break;
670
case null:
671
    app_list(); break;
672
default:
0 ignored issues
show
Coding Style introduced by
DEFAULT keyword must be indented 4 spaces from SWITCH keyword
Loading history...
Coding Style introduced by
DEFAULT case must have a breaking statement
Loading history...
673
    error_page("unknown action");
674
}
675
676
?>
677