'
73 | } ))
74 | .pipe( gulp.dest( 'languages' ) );
75 | });
76 |
77 | /**
78 | * Task to handle the JavaScript building and sourcemap generating.
79 | */
80 | gulp.task( 'watch', function() {
81 | var args = merge( watchify.args, { debug: true } ); // Merge in default watchify args with browserify arguments.
82 | var bundler = browserify( config.js.src, args ) // Browserify.
83 | .plugin( watchify, {
84 | ignoreWatch: ['**/node_modules/**', '**/bower_components/**']
85 | } ) // Watchify to watch source file changes.
86 | .transform( babelify, {
87 | presets: ['es2015', 'react']
88 | } );
89 |
90 | livereload.listen(); // Start livereload server.
91 |
92 | bundle( bundler ); // Run the bundle the first time (required for Watchify to kick in).
93 |
94 | bundler.on( 'update', function() {
95 | bundle( bundler ); // Re-run bundle on source updates.
96 | });
97 | } );
98 |
99 | // Completes the final file outputs.
100 | function bundle( bundler ) {
101 | var bundleTimer = duration( 'Javascript bundle time' );
102 |
103 | return bundler
104 | .bundle()
105 | .on( 'error', function( err ) {
106 | console.error( err ); this.emit( 'end' );
107 | })
108 | .pipe( source( 'batch.jsx' ) ) // Set source name.
109 | .pipe( buffer() ) // Convert to gulp pipeline.
110 | .pipe( rename( config.js.outputFile ) ) // Rename the output file.
111 | .pipe( sourcemaps.init( { loadMaps: true } ) ) // Extract the inline sourcemaps.
112 | .pipe( uglify() ) // Minify the JS.
113 | .pipe( sourcemaps.write( './map' ) ) // Set folder for sourcemaps to output to.
114 | .pipe( gulp.dest( config.js.outputDir ) ) // Set the output folder.
115 | .pipe( notify( {
116 | message: 'Generated file: <%= file.relative %>'
117 | } ) ) // Output the file being created.
118 | .pipe( bundleTimer ) // Output time timing of the file creation.
119 | .pipe( livereload() ); // Reload the view in the browser.
120 | }
121 |
122 | // Verify PHP Coding Standards.
123 | gulp.task( 'phpcs', function() {
124 | return gulp.src( [
125 | '**/*.php',
126 | '!node_modules/**/*.*',
127 | '!tests/**/*.*',
128 | '!vendor/**/*.*'
129 | ] )
130 | .pipe( phpcs( {
131 | bin: 'vendor/bin/phpcs',
132 | standard: 'ruleset.xml'
133 | } ) )
134 | .pipe( phpcs.reporter( 'log' ) )
135 | .pipe( phpcs.reporter( 'fail' ) );
136 | } );
137 |
138 | // Lint PHP.
139 | gulp.task( 'phplint', function( cb ) {
140 | phplint( [
141 | '**/*.php',
142 | '!node_modules/**/*.*',
143 | '!tests/**/*.*',
144 | '!vendor/**/*.*'
145 | ], { limit: 10 }, function( err, stdout, stderr ) {
146 | if ( err ) {
147 | cb( err );
148 | process.exit( 1 );
149 | }
150 | cb();
151 | } );
152 | } );
153 |
154 | // Run single site PHPUnit tests.
155 | gulp.task( 'phpunit-single', shell.task( [ 'vendor/bin/phpunit -c phpunit.xml.dist' ] ) );
156 |
157 | // Run multisite PHPUnit tests.
158 | gulp.task( 'phpunit-multisite', shell.task( [ 'vendor/bin/phpunit -c multisite.xml.dist' ] ) );
159 |
160 | // Run single site PHPUnit tests with code coverage.
161 | gulp.task( 'phpunit-codecoverage', shell.task( [ 'vendor/bin/phpunit -c codecoverage.xml.dist' ] ) );
162 |
163 | // Gulp task for build
164 | gulp.task( 'default', [ 'eslint', 'build' ] );
165 |
166 | // Lint files.
167 | gulp.task( 'lint', [ 'phplint', 'phpcs', 'eslint' ] );
168 |
169 | // Run PHP tests.
170 | gulp.task( 'phpunit', function() {
171 | runSequence( 'phpunit-single', 'phpunit-multisite' );
172 | } );
173 |
174 | // Run full build and test.
175 | gulp.task( 'test', function() {
176 | runSequence( 'build', 'lint', 'phpunit' );
177 | } );
178 |
--------------------------------------------------------------------------------
/locomotive.php:
--------------------------------------------------------------------------------
1 | id ) || 'tools_page_locomotive' !== $screen->id ) {
75 | return;
76 | }
77 |
78 | // Load our actual help tab.
79 | $screen->add_help_tab( array(
80 | 'id' => 'help-overview',
81 | 'title' => esc_html__( 'Overview', 'locomotive' ),
82 | 'content' => '' . esc_html__( 'Locomotive is a batch processing library that can be used to write a single or set of functions to be processed across a large data set, right from the WordPress admin. You can use it to add meta values to posts based on arbitrary data, process and delete spam comments and revisions, submit posts through external API\'s, or simply change data on a large amount of posts at the same time.', 'locomotive' ) . '
',
83 | ) );
84 |
85 | // Set up the text for the sidebar.
86 | $side = '' . esc_html__( 'More on GitHub:', 'locomotive' ) . '
';
87 | $side .= '';
93 |
94 | // Send through our filter.
95 | $side = apply_filters( 'loco_help_tab_sidebar', $side );
96 |
97 | // Load the sidebar portion of the help tab.
98 | $screen->set_help_sidebar( $side );
99 | }
100 |
101 | /**
102 | * Load in all the files we need.
103 | */
104 | public function load_includes() {
105 | require_once( LOCO_PLUGIN_DIR . 'includes/abstracts/abstract-batch.php' );
106 | require_once( LOCO_PLUGIN_DIR . 'includes/batches/class-batch-posts.php' );
107 | require_once( LOCO_PLUGIN_DIR . 'includes/batches/class-batch-users.php' );
108 | require_once( LOCO_PLUGIN_DIR . 'includes/batches/class-batch-sites.php' );
109 | require_once( LOCO_PLUGIN_DIR . 'includes/batches/class-batch-terms.php' );
110 | require_once( LOCO_PLUGIN_DIR . 'includes/batches/class-batch-comments.php' );
111 | require_once( LOCO_PLUGIN_DIR . 'includes/functions.php' );
112 | }
113 |
114 | /**
115 | * Handle hooks.
116 | */
117 | public function attach_hooks() {
118 | add_action( 'admin_menu', array( $this, 'add_dashboard' ) );
119 | add_action( 'after_setup_theme', array( $this, 'loaded' ) );
120 | add_action( 'admin_enqueue_scripts', array( $this, 'scripts' ) );
121 |
122 | add_action( 'wp_ajax_run_batch', array( $this, 'run' ) );
123 | add_action( 'wp_ajax_reset_batch', array( $this, 'reset' ) );
124 | }
125 |
126 | /**
127 | * Plugin stylesheet and JavaScript.
128 | *
129 | * @param string $hook The current page loaded in the WP admin.
130 | */
131 | public function scripts( $hook ) {
132 |
133 | // Exclude our scripts and CSS files from loading globally.
134 | if ( 'tools_page_locomotive' !== $hook ) {
135 | return;
136 | }
137 |
138 | wp_enqueue_style( 'batch-process-styles', LOCO_PLUGIN_URL . 'assets/main.css' );
139 | wp_enqueue_script( 'batch-js', LOCO_PLUGIN_URL . 'assets/dist/batch.min.js', array( 'jquery' ), '0.1.0', true );
140 |
141 | wp_localize_script( 'batch-js', 'batch', array(
142 | 'nonce' => wp_create_nonce( 'run-batch-process' ),
143 | 'ajaxurl' => admin_url( 'admin-ajax.php' ),
144 | 'batches' => locomotive_get_all_batches(),
145 | 'page_title' => esc_html( get_admin_page_title() ),
146 | ) );
147 | }
148 |
149 | /**
150 | * Let everyone know we are loaded and ready to go.
151 | */
152 | public function loaded() {
153 | if ( is_admin() ) {
154 | locomotive_clear_existing_batches();
155 | do_action( 'locomotive_init' );
156 | }
157 | }
158 |
159 | /**
160 | * AJAX handler for running a batch.
161 | *
162 | * @todo Move this to it's own AJAX class.
163 | */
164 | public function run() {
165 | $batch_process = '';
166 | $step = 0;
167 | $errors = array();
168 |
169 | check_ajax_referer( 'run-batch-process', 'nonce' );
170 |
171 | if ( empty( $_POST['batch_process'] ) ) {
172 | $errors[] = __( 'Batch process not specified.', 'locomotive' );
173 | } else {
174 | $batch_process = sanitize_text_field( wp_unslash( $_POST['batch_process'] ) );
175 | }
176 |
177 | if ( empty( $_POST['step'] ) ) {
178 | $errors[] = __( 'Step must be defined.', 'locomotive' );
179 | } else {
180 | $step = absint( $_POST['step'] );
181 | }
182 |
183 | if ( ! empty( $errors ) ) {
184 | wp_send_json( array(
185 | 'success' => false,
186 | 'errors' => $errors,
187 | ) );
188 | }
189 |
190 | do_action( 'loco_batch_' . $batch_process, $step );
191 | }
192 |
193 | /**
194 | * AJAX handler for running a batch.
195 | *
196 | * @todo Move this to it's own AJAX class.
197 | */
198 | public function reset() {
199 | $batch_process = '';
200 | $errors = array();
201 |
202 | check_ajax_referer( 'run-batch-process', 'nonce' );
203 |
204 | if ( empty( $_POST['batch_process'] ) ) {
205 | $errors[] = __( 'Batch process not specified.', 'locomotive' );
206 | } else {
207 | $batch_process = sanitize_text_field( wp_unslash( $_POST['batch_process'] ) );
208 | }
209 |
210 | if ( ! empty( $errors ) ) {
211 | wp_send_json( array(
212 | 'success' => false,
213 | 'errors' => $errors,
214 | ) );
215 | }
216 |
217 | do_action( 'loco_batch_' . $batch_process . '_reset' );
218 |
219 | wp_send_json( array( 'success' => true ) );
220 | }
221 |
222 | /**
223 | * Init.
224 | */
225 | public function init() {
226 | $this->define_constants();
227 | $this->load_includes();
228 | $this->attach_hooks();
229 | }
230 | }
231 |
232 | $batch_processing = new Loader();
233 | $batch_processing->init();
234 |
--------------------------------------------------------------------------------
/assets/src/js/batch.jsx:
--------------------------------------------------------------------------------
1 | var React = require( 'react' );
2 | var ReactDOM = require( 'react-dom' );
3 | var $ = jQuery; // We are loading this file after jQuery through `wp_enqueue_script`.
4 |
5 | /**
6 | * Application components.
7 | */
8 | import BatchPicker from './components/BatchPicker';
9 | import Modal from './components/Modal';
10 | import ModalReset from './components/ModalReset';
11 |
12 | /**
13 | * Our Locomotive App.
14 | */
15 | var App = React.createClass( {
16 | getInitialState : function () {
17 | return {
18 | // Batches that can be run. Loaded through `wp_localize_script()`.
19 | batches: batch.batches,
20 | page_title: batch.page_title,
21 |
22 | // Object to hold data relating to running a migration (in the modal).
23 | processing: {
24 | active: false,
25 | batch: false,
26 |
27 | // Remote data is data that is retrieved via Ajax calls during a
28 | // batch process.
29 | remote_data: {
30 | batch_title: '',
31 | status: '',
32 | error: false,
33 | progress: 0,
34 | current_step: 0,
35 | total_steps: 0,
36 | total_num_results: 0
37 | }
38 | },
39 | errors: [],
40 | resetActive: false
41 | };
42 | },
43 |
44 | /**
45 | * Update which batch is currently selected.
46 | *
47 | * @param key Currently selected batch key.
48 | */
49 | updateSelectedBatch : function ( key ) {
50 | if ( this.state.processing.active ) {
51 | return;
52 | }
53 |
54 | this.state.processing.batch = key;
55 | this.setState( { processing: this.state.processing } );
56 | },
57 |
58 | /**
59 | * Function to handle flipping the switches for the modal.
60 | *
61 | * @param bool active Whether or not we are processing a batch.
62 | */
63 | toggleProcessing : function ( active ) {
64 | if ( false === active || true === active ) {
65 | this.state.processing.active = active;
66 | this.setState( { processing: this.state.processing } );
67 | }
68 | },
69 |
70 | /**
71 | * Run the currently selected batch process.
72 | */
73 | runBatch : function ( currentStep ) {
74 | if ( '' === this.state.processing.batch ) {
75 | return;
76 | }
77 |
78 | var self = this,
79 | batchSlug = self.state.processing.batch,
80 | totalResults = self.state.processing.remote_data.total_num_results;
81 |
82 | // If we open the modal and it was previously complete, clear it.
83 | if ( 100 === this.state.processing.remote_data.progress ) {
84 | this.state.processing.batch = '';
85 | this.state.processing.remote_data = {
86 | progress: 0
87 | };
88 |
89 | this.setState( { processing: this.state.processing, errors: [] } );
90 | }
91 |
92 |
93 |
94 | $.ajax( {
95 | type: 'POST',
96 | url: batch.ajaxurl,
97 | data: {
98 | batch_process: batchSlug,
99 | nonce: batch.nonce,
100 | step: currentStep,
101 | total_num_results: totalResults,
102 | action: 'run_batch',
103 | },
104 | dataType: 'json',
105 | success: function ( response ) {
106 | // Update our state with the processing status and progress, which will update the modal.
107 | self.state.processing.batch = batchSlug;
108 | self.state.processing.remote_data = {
109 | batch_title: response.batch,
110 | status: response.status,
111 | progress: response.progress,
112 | current_step: response.current_step,
113 | total_steps: response.total_steps,
114 | total_num_results: response.total_num_results,
115 | error: response.error
116 | };
117 |
118 | // Update our batches, which will update the batch listing.
119 | self.state.batches[ batchSlug ].last_run = 'just ran';
120 | self.state.batches[ batchSlug ].status = self.state.processing.remote_data.status;
121 |
122 | // Check for errors.
123 | if ( response.error ) {
124 | self.setState( { errors: self.state.errors.concat( response.errors ) } );
125 | self.setState( { processing: self.state.processing } );
126 | }
127 |
128 | self.setState( {
129 | processing: self.state.processing,
130 | batches: self.state.batches
131 | } );
132 | // Determine if we have to run another step in the batch. Checks if there are more steps
133 | // that need to run and makes sure the 'status' from the server is still 'running'.
134 | if ( response.currentStep !== response.total_steps && 'running' === response.status.toLowerCase() ) {
135 | self.runBatch( response.current_step + 1 );
136 | }
137 | }
138 | } ).fail( function () {
139 | alert( 'Something went wrong.' );
140 | } );
141 |
142 | this.toggleProcessing( true );
143 | },
144 |
145 | toggleResetModal : function ( active ) {
146 | if ( false === active || true === active ) {
147 | this.setState( { resetActive: active } );
148 | }
149 | },
150 | /**
151 | * Reset the selected batch process.
152 | */
153 | resetBatch : function () {
154 | if ( '' === this.state.processing.batch ) {
155 | return;
156 | }
157 |
158 | this.setState( { resetActive: false } );
159 |
160 | var self = this,
161 | batchSlug = self.state.processing.batch.toString();
162 |
163 | $.ajax( {
164 | type: 'POST',
165 | url: batch.ajaxurl,
166 | data: {
167 | batch_process: batchSlug,
168 | nonce: batch.nonce,
169 | action: 'reset_batch',
170 | },
171 | dataType: 'json',
172 | success: function ( response ) {
173 | if ( response.success ) {
174 | // Update our batches, which will update the batch listing.
175 | self.state.batches[ self.state.processing.batch ].last_run = 'never';
176 | self.state.batches[ self.state.processing.batch ].status = 'new';
177 |
178 | self.setState( {
179 | processing: self.state.processing,
180 | batches: self.state.batches
181 | } );
182 | } else {
183 | alert( 'Reset batch failed.' );
184 | }
185 | }
186 | } ).fail( function () {
187 | alert( 'Something went wrong.' );
188 | } );
189 | },
190 |
191 | /**
192 | * Decides if `Run Batch` button is enabled or disabled.
193 | *
194 | * @returns {boolean} Can we run a batch?
195 | */
196 | canInteractWithBatch : function () {
197 | // Default to being able to run a batch.
198 | var canRun = true;
199 | var processingState = this.state.processing;
200 |
201 | // If we don't have a batch selected.
202 | if ( false === processingState.batch ) {
203 | canRun = false;
204 | }
205 |
206 | // If we are have the modal open.
207 | if ( processingState.active ) {
208 | canRun = false;
209 | }
210 |
211 | // If we are currently processing a batch and there are results.
212 | if ( processingState.remote_data.current_step !== processingState.remote_data.total_steps && 0 !== processingState.remote_data.total_num_results ) {
213 | canRun = false;
214 | }
215 |
216 | return canRun;
217 | },
218 |
219 | /**
220 | * Render our batch application.
221 | *
222 | * @returns {JSX}
223 | */
224 | render : function () {
225 | var selectedBatch = '';
226 | if ( this.state.processing.batch ) {
227 | selectedBatch = this.state.batches[ this.state.processing.batch ].name;
228 | }
229 |
230 | return (
231 |
232 |
{ this.state.page_title }
233 |
240 |
241 |
248 |
249 |
254 |
255 | );
256 | }
257 | } );
258 |
259 | ReactDOM.render( , document.getElementById( 'batch-main' ) );
260 |
--------------------------------------------------------------------------------
/tests/test-batch.php:
--------------------------------------------------------------------------------
1 | register( array(
28 | 'slug' => 'test-anot22h12er-batch',
29 | 'type' => 'post',
30 | 'callback' => 'my_callback_function',
31 | 'args' => array(
32 | 'posts_per_page' => 10,
33 | 'post_type' => 'post',
34 | ),
35 | ) );
36 | } catch ( Exception $e ) {
37 | $this->assertEquals( 'Batch name must be defined.', $e->getMessage() );
38 | }
39 |
40 | }
41 |
42 | /**
43 | * Test type is included.
44 | */
45 | public function test_register_batch_includes_type() {
46 | try {
47 | $batch_process = new Posts();
48 | $batch_process->register( array(
49 | 'name' => 'Hey',
50 | 'slug' => 'test-anot22h12er-batch',
51 | 'callback' => 'my_callback_function',
52 | 'args' => array(
53 | 'posts_per_page' => 10,
54 | 'post_type' => 'post',
55 | ),
56 | ) );
57 | } catch ( Exception $e ) {
58 | $this->assertEquals( 'Batch type must be defined.', $e->getMessage() );
59 | }
60 | }
61 |
62 | /**
63 | * Test callback defined
64 | */
65 | public function test_register_batch_includes_callback() {
66 | try {
67 | $batch_process = new Posts();
68 | $batch_process->register( array(
69 | 'name' => 'Hey',
70 | 'type' => 'post',
71 | 'slug' => 'test-anot22h12er-batch',
72 | 'args' => 0,
73 | ) );
74 | } catch ( Exception $e ) {
75 | $this->assertEquals( 'A callback must be defined.', $e->getMessage() );
76 | }
77 | }
78 |
79 | /**
80 | * Test without arguments
81 | */
82 | public function test_register_batch_doesnt_require_args() {
83 | $batch_process = new Posts();
84 | $batch_process->register( array(
85 | 'name' => 'Hey there',
86 | 'type' => 'post',
87 | 'callback' => 'my_callback_function',
88 | ) );
89 |
90 | $this->assertNotNull( $batch_process->currently_registered['hey-there'] );
91 | }
92 |
93 | /**
94 | * Make sure slugs get slashes.
95 | */
96 | public function test_register_batch_no_slug_gets_name() {
97 | $batch_process = new Posts();
98 | $batch_process->register( array(
99 | 'name' => 'Hey there',
100 | 'type' => 'post',
101 | 'callback' => 'my_callback_function',
102 | 'args' => array(
103 | 'posts_per_page' => 10,
104 | 'post_type' => 'post',
105 | ),
106 | ) );
107 |
108 | $this->assertNotNull( $batch_process->currently_registered['hey-there'] );
109 | }
110 |
111 | /**
112 | * Make sure adding batch adds to currently registered.
113 | */
114 | public function test_register_overwrites_currently_registered_if_same_slug() {
115 | $this->register_successful_batch( 'hey' );
116 |
117 | $batch = new Posts();
118 | $batch->register( array(
119 | 'name' => 'My Test Batch process OVERWRITE',
120 | 'slug' => 'hey',
121 | 'type' => 'post',
122 | 'callback' => 'my_callback_function',
123 | 'args' => array(
124 | 'posts_per_page' => 10,
125 | 'post_type' => 'post',
126 | ),
127 | ) );
128 |
129 | $this->assertEquals( 'My Test Batch process OVERWRITE', $batch->currently_registered['hey']['name'] );
130 | }
131 |
132 | /**
133 | * Make sure that when a batch process is registered that `currently_registered`
134 | * is an array.
135 | */
136 | public function test_empty_currently_registered_is_array_when_new_batch_added() {
137 | locomotive_clear_existing_batches();
138 |
139 | $batch_process = new Posts();
140 | $this->assertTrue( is_array( $batch_process->currently_registered ) );
141 | }
142 |
143 | /**
144 | * Test that status gets updated on a batch to no results found.
145 | */
146 | public function test_no_results_found() {
147 | $post_batch = new Posts();
148 |
149 | $post_batch->register( array(
150 | 'name' => 'Hey there',
151 | 'type' => 'post',
152 | 'callback' => 'my_callback_function_test',
153 | 'args' => array(
154 | 'posts_per_page' => 10,
155 | 'post_type' => 'post',
156 | ),
157 | ) );
158 |
159 | $batch_status = get_option( 'loco_batch_' . $post_batch->slug );
160 | $this->assertFalse( $batch_status );
161 |
162 | $post_batch->run( 1 );
163 |
164 | $batch_status = get_option( 'loco_batch_' . $post_batch->slug );
165 | $this->assertEquals( 'no results found', $batch_status['status'] );
166 | }
167 |
168 | /**
169 | * Test that batch gets run.
170 | */
171 | public function test_running_run() {
172 | // Create 5 posts.
173 | for ( $x = 0; $x < 15; $x++ ) {
174 | $this->factory->post->create();
175 | }
176 |
177 | $post_batch = new Posts();
178 |
179 | $post_batch->register( array(
180 | 'name' => 'Hey there',
181 | 'type' => 'post',
182 | 'callback' => 'my_callback_function_test',
183 | 'args' => array(
184 | 'posts_per_page' => 10,
185 | 'post_type' => 'post',
186 | ),
187 | ) );
188 |
189 | $batch_status = get_option( 'loco_batch_' . $post_batch->slug );
190 | $this->assertFalse( $batch_status );
191 |
192 | $post_batch->run( 1 );
193 |
194 | $batch_status = get_option( 'loco_batch_' . $post_batch->slug );
195 | $this->assertEquals( 'running', $batch_status['status'] );
196 | }
197 |
198 | /**
199 | * Test that offset is applied properly to each step
200 | */
201 | public function test_for_proper_offset() {
202 | $this->factory->post->create_many( 10 );
203 |
204 | $post_batch = new Posts();
205 |
206 | $post_batch->register( array(
207 | 'name' => 'Hey there',
208 | 'type' => 'post',
209 | 'callback' => __NAMESPACE__ . '\\my_post_callback_function_test',
210 | 'args' => array(
211 | 'posts_per_page' => 5,
212 | 'post_type' => 'post',
213 | ),
214 | ) );
215 |
216 | $first_run = $post_batch->run( 1 );
217 | $second_run = $post_batch->run( 2 );
218 |
219 | // Results from the first and second run should NOT match.
220 | $this->assertNotEquals( $second_run['query_results'][0]->ID, $first_run['query_results'][0]->ID );
221 |
222 | }
223 |
224 | /**
225 | * Test that batch gets run.
226 | */
227 | public function test_run_with_error() {
228 | $posts = array();
229 |
230 | // Create 5 posts.
231 | for ( $x = 0; $x < 5; $x++ ) {
232 | $posts[] = $this->factory->post->create();
233 | }
234 |
235 | $post_batch = new Posts();
236 |
237 | $post_batch->register( array(
238 | 'name' => 'Hey there',
239 | 'type' => 'post',
240 | 'callback' => __NAMESPACE__ . '\\my_callback_function_test_false',
241 | 'args' => array(
242 | 'posts_per_page' => 10,
243 | 'post_type' => 'post',
244 | ),
245 | ) );
246 |
247 | $batch_status = get_option( 'loco_batch_' . $post_batch->slug );
248 | $this->assertFalse( $batch_status );
249 |
250 | $run = $post_batch->run( 1 );
251 |
252 | // Error is returned.
253 | $this->assertArrayHasKey( 'errors', $run );
254 |
255 | // Errors return matches class errors object.
256 | $this->assertCount( 5, $run['errors'] );
257 | $this->assertCount( 5, $post_batch->result_errors );
258 |
259 | // Sample message is returned properly.
260 | $this->assertEquals( 'Not working', $run['errors'][0]['message'] );
261 |
262 | $batch_status = get_option( 'loco_batch_' . $post_batch->slug );
263 | $this->assertEquals( 'finished', $batch_status['status'] );
264 | }
265 |
266 |
267 | /**
268 | * Helper function to register a successful batch.
269 | *
270 | * @param string $slug Slug of test batch.
271 | */
272 | private function register_successful_batch( $slug = 'test-batch' ) {
273 | $batch = new Posts();
274 | $batch->register( array(
275 | 'name' => 'My Test Batch process',
276 | 'slug' => $slug,
277 | 'type' => 'post',
278 | 'callback' => 'my_callback_function',
279 | 'args' => array(
280 | 'posts_per_page' => 10,
281 | 'post_type' => 'post',
282 | ),
283 | ) );
284 |
285 | return $batch;
286 | }
287 |
288 | }
289 |
290 | /**
291 | * My callback function test.
292 | *
293 | * @param WP_Post $result Result item.
294 | */
295 | function my_callback_function_test( $result ) {
296 | update_post_meta( $result->ID, 'custom-key', 'my-value' );
297 | }
298 |
299 | /**
300 | * My callback function test.
301 | *
302 | * @param object $result Result item.
303 | * @throws \Exception Not working.
304 | */
305 | function my_callback_function_test_false( $result ) {
306 | throw new \Exception( 'Not working' );
307 | }
308 |
--------------------------------------------------------------------------------
/includes/abstracts/abstract-batch.php:
--------------------------------------------------------------------------------
1 | args = wp_parse_args( $this->args, $this->default_args );
158 | $this->batch_get_results();
159 | $this->calculate_offset();
160 |
161 | // Run query again, but this time with the new offset calculated.
162 | $results = $this->batch_get_results();
163 | return $results;
164 | }
165 |
166 | /**
167 | * Set the total number of results
168 | *
169 | * Uses a number passed from the client to the server and compares it to the total objects
170 | * pulled by the latest query. If the dataset is larger, we increase the total_num_results number.
171 | * Otherwise, keep it at the original (to account for deletion / changes).
172 | *
173 | * @param int $total_from_query Total number of results from latest query.
174 | */
175 | public function set_total_num_results( $total_from_query ) {
176 | // If this is past step 1, the client is passing back the total number of results.
177 | // This accounts for deletion / destructive actions to the data.
178 | $total_from_request = isset( $_POST['total_num_results'] ) ? absint( $_POST['total_num_results'] ) : 0; // Input var okay.
179 |
180 | // In all cases we want to ensure that we use the higher of the two results total (from client or query).
181 | // We go with the higher number because we want to lock the total number of steps calculated at it's highest total.
182 | // With a destructive action, that would be total from request. If addivitve action, it would be total from query.
183 | // In all other cases, these two numbers are equal, so either would work.
184 | if ( $total_from_query > $total_from_request ) {
185 | $this->total_num_results = (int) $total_from_query;
186 | } else {
187 | $this->total_num_results = (int) $total_from_request;
188 | }
189 |
190 | $this->record_change_if_totals_differ( $total_from_request, $total_from_query );
191 | }
192 |
193 | /**
194 | * If the amount of total records has changed, the amount is recorded so that it can
195 | * be applied to the offeset when it is calculated. This ensures that the offset takes into
196 | * account if new objects have been added or removed from the query.
197 | *
198 | * @param int $total_from_request Total number of results passed up from client.
199 | * @param int $total_from_query Total number of results retreived from query.
200 | */
201 | public function record_change_if_totals_differ( $total_from_request, $total_from_query ) {
202 | if ( $total_from_query !== $total_from_request && $total_from_request > 0 ) {
203 | $this->difference_in_result_totals = $total_from_request - $total_from_query;
204 | }
205 | }
206 |
207 | /**
208 | * Calculate the offset for the current query.
209 | */
210 | public function calculate_offset() {
211 | if ( 1 !== $this->current_step ) {
212 | // Example: step 2: 1 * 10 = offset of 10, step 3: 2 * 10 = offset of 20.
213 | // The difference in result totals is used in case of additive or destructive actions.
214 | // if 5 posts were deleted in step 1 (20 - 15 = 5) then the offset should remain at 0 ( offset of 5 - 5) in step 2.
215 | $this->args['offset'] = ( ( $this->current_step - 1 ) * $this->args[ $this->per_batch_param ] ) - $this->difference_in_result_totals;
216 | }
217 | }
218 |
219 | /**
220 | * Register the batch process so we can run it.
221 | *
222 | * @param array $args Details about the batch you are registering.
223 | */
224 | public function register( $args ) {
225 | if ( $this->setup( $args ) ) {
226 | if ( ! defined( 'DOING_AJAX' ) ) {
227 | $this->add();
228 | }
229 | }
230 | }
231 |
232 | /**
233 | * Add a batch process to our system.
234 | */
235 | private function add() {
236 | if ( ! isset( $this->currently_registered[ $this->slug ] ) ) {
237 | $this->currently_registered[ $this->slug ] = array(
238 | 'name' => $this->name,
239 | );
240 | } else {
241 | $this->currently_registered[ $this->slug ]['name'] = $this->name;
242 | }
243 |
244 | return locomotive_update_registered_batches( $this->currently_registered );
245 | }
246 |
247 | /**
248 | * Setup our Batch object to have everything it needs (callback, name, slug,
249 | * etc).
250 | *
251 | * @todo Research the best way to handle exceptions.
252 | *
253 | * @param array $args Array of args for register.
254 | * @throws Exception Type must be provided.
255 | * @return true|exception
256 | */
257 | private function setup( $args ) {
258 | if ( empty( $args['name'] ) ) {
259 | throw new Exception( __( 'Batch name must be defined.', 'locomotive' ) );
260 | } else {
261 | $this->name = $args['name'];
262 | }
263 |
264 | if ( empty( $args['slug'] ) ) {
265 | $this->slug = sanitize_title_with_dashes( $args['name'] );
266 | } else {
267 | $this->slug = $args['slug'];
268 | }
269 |
270 | if ( empty( $args['type'] ) ) {
271 | throw new Exception( __( 'Batch type must be defined.', 'locomotive' ) );
272 | } else {
273 | $this->type = $args['type'];
274 | }
275 |
276 | if ( empty( $args['args'] ) || ! is_array( $args['args'] ) ) {
277 | $this->args = array();
278 | } else {
279 | $this->args = $args['args'];
280 | }
281 |
282 | if ( empty( $args['callback'] ) ) {
283 | throw new Exception( __( 'A callback must be defined.', 'locomotive' ) );
284 | } else {
285 | $this->callback = $args['callback'];
286 | }
287 |
288 | $this->currently_registered = locomotive_get_all_batches();
289 |
290 | add_action( 'loco_batch_' . $this->slug, array( $this, 'run_ajax' ) );
291 | add_action( 'loco_batch_' . $this->slug . '_reset', array( $this, 'clear_result_status' ) );
292 |
293 | return true;
294 | }
295 |
296 | /**
297 | * Return JSON for AJAX requests to run.
298 | *
299 | * @param int $current_step Current step.
300 | */
301 | public function run_ajax( $current_step ) {
302 | wp_send_json( $this->run( $current_step ) );
303 | }
304 |
305 | /**
306 | * Run this batch process (query for the data and process the results).
307 | *
308 | * @param int $current_step Current step.
309 | */
310 | public function run( $current_step ) {
311 | $this->current_step = $current_step;
312 |
313 | $results = $this->get_results();
314 |
315 | if ( empty( $results ) ) {
316 | $this->update_status( 'no results found' );
317 | return $this->format_ajax_details( array(
318 | 'success' => true,
319 | 'message' => __( 'No results found.', 'locomotive' ),
320 | ) );
321 | }
322 |
323 | $this->process_results( $results );
324 |
325 | $per_page = get_option( 'posts_per_page' );
326 | if ( isset( $this->per_batch_param ) ) {
327 | $per_page = $this->args[ $this->per_batch_param ];
328 | }
329 |
330 | /**
331 | * Filter the per_page number used to calculate total number of steps. You would get use
332 | * out of this if you had a custom $wpdb query that didn't paginate in one of the default
333 | * ways supported by the plugin.
334 | *
335 | * @param int $per_page The number of results per page.
336 | */
337 | $per_page = apply_filters( 'loco_batch_' . $this->slug . '_per_page', $per_page );
338 |
339 | $total_steps = ceil( $this->total_num_results / $per_page );
340 |
341 | if ( (int) $this->current_step === (int) $total_steps ) {
342 |
343 | // The difference here calcuates the gap between the original total and the most recent query.
344 | // In the case of a deletion process the final step will have a number exactly equal to the posts_per_page.
345 | // If 20 total, then the last step would have 4 for instance.
346 | // In all other cases, the difference would be the same as the total number of results (20 - 0 = 20).
347 | // The exception is a deletion process where a new object is added during the process.
348 | // In this case, then the final step would have less then the posts_per_page but never more (so <=).
349 | // We check this difference and compare it before saying that we are finished. If not, we run the last step over.
350 | $difference = $this->total_num_results - $this->difference_in_result_totals;
351 | if ( $difference <= $per_page || $difference === $this->total_num_results ) {
352 | $this->update_status( 'finished' );
353 | } else {
354 | $this->current_step = $this->current_step - 1;
355 | $this->update_status( 'running' );
356 | }
357 | } else {
358 | $this->update_status( 'running' );
359 | }
360 |
361 | $progress = ( 0 === (int) $total_steps ) ? 100 : round( ( $this->current_step / $total_steps ) * 100 );
362 |
363 | // If there are errors, return the error variable as true so front-end can handle.
364 | if ( is_array( $this->result_errors ) && count( $this->result_errors ) > 0 ) {
365 | return $this->format_ajax_details( array(
366 | 'error' => true,
367 | 'errors' => $this->result_errors,
368 | 'total_steps' => $total_steps,
369 | 'query_results' => $results,
370 | 'progress' => $progress,
371 | ) );
372 | }
373 |
374 | return $this->format_ajax_details( array(
375 | 'total_steps' => $total_steps,
376 | 'query_results' => $results,
377 | 'progress' => $progress,
378 | ) );
379 | }
380 |
381 | /**
382 | * Get details for Ajax requests.
383 | *
384 | * @param array $details Array of details to send via Ajax.
385 | */
386 | private function format_ajax_details( $details = array() ) {
387 | return wp_parse_args( $details, array(
388 | 'success' => true,
389 | 'current_step' => $this->current_step,
390 | 'callback' => $this->callback,
391 | 'status' => $this->status,
392 | 'batch' => $this->name,
393 | 'total_num_results' => $this->total_num_results,
394 | ) );
395 | }
396 |
397 | /**
398 | * Update batch timestamps.
399 | *
400 | * @param string $status Status of batch process.
401 | */
402 | private function update_status( $status ) {
403 | update_option( 'loco_batch_' . $this->slug, array(
404 | 'status' => $status,
405 | 'timestamp' => current_time( 'timestamp' ),
406 | ) );
407 |
408 | $this->status = __( ucfirst( $status ) );
409 | }
410 |
411 | /**
412 | * Loop over an array of results (posts, pages, etc) and run the callback
413 | * function that was passed through when this batch was registered.
414 | *
415 | * @param array $results Array of results from the query.
416 | */
417 | public function process_results( $results ) {
418 | /**
419 | * The key used to define the status of whether or not a result was processed successfully.
420 | *
421 | * @param string $string_text 'success'
422 | */
423 | $success_status = apply_filters( 'loco_batch_success_status', 'success' );
424 |
425 | /**
426 | * The key used to define the status of whether or not a result was not able to be processed.
427 | *
428 | * @param string $string_text 'failed'
429 | */
430 | $failed_status = apply_filters( 'loco_batch_failed_status', 'failed' );
431 |
432 | foreach ( $results as $result ) {
433 | // If this result item has been processed already, skip it.
434 | if ( $success_status === $this->get_result_status( $result ) ) {
435 | continue;
436 | }
437 |
438 | try {
439 | call_user_func_array( $this->callback, array( $result ) );
440 | $this->update_result_status( $result, $success_status );
441 | } catch ( Exception $e ) {
442 | $this->update_status( $failed_status );
443 | $this->update_result_status( $result, $failed_status );
444 | $this->result_errors[] = array(
445 | 'item' => $result->ID,
446 | 'message' => $e->getMessage(),
447 | );
448 |
449 | }
450 | }
451 | }
452 |
453 | /**
454 | * Update the meta info on a result.
455 | *
456 | * @param mixed $result The result we want to track meta data on.
457 | * @param string $status Status of this result in the batch.
458 | */
459 | public function update_result_status( $result, $status ) {
460 | /**
461 | * Action to hook into when a result gets processed and it's status is updated.
462 | *
463 | * @param mixed $result The current result.
464 | * @param string $status The status to set on a result.
465 | */
466 | do_action( 'loco_batch_' . $this->slug . '_update_result_status', $result, $status );
467 |
468 | return $this->update_result_item_status( $result, $status );
469 | }
470 |
471 | /**
472 | * Get the status of a result.
473 | *
474 | * @param mixed $result The result we want to get status of.
475 | */
476 | public function get_result_status( $result ) {
477 | /**
478 | * Action to hook into when a result is being checked for whether or not
479 | * it was updated.
480 | *
481 | * @param mixed $result The current result which is getting it's status checked.
482 | */
483 | do_action( 'loco_batch_' . $this->slug . '_get_result_status', $result );
484 |
485 | return $this->get_result_item_status( $result );
486 | }
487 |
488 | /**
489 | * Clear the result status for a batch.
490 | */
491 | public function clear_result_status() {
492 | /**
493 | * Action to hook into when the 'reset' button is clicked in the admin UI.
494 | *
495 | * @param Batch $this The current batch object.
496 | */
497 | do_action( 'loco_batch_' . $this->slug . '_clear', $this );
498 |
499 | $this->batch_clear_result_status();
500 | $this->update_status( 'reset' );
501 | }
502 | }
503 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "87646caa8aa0d83c8fdcc298d30d4f1d",
8 | "packages": [],
9 | "packages-dev": [
10 | {
11 | "name": "doctrine/instantiator",
12 | "version": "1.4.0",
13 | "source": {
14 | "type": "git",
15 | "url": "https://github.com/doctrine/instantiator.git",
16 | "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b"
17 | },
18 | "dist": {
19 | "type": "zip",
20 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b",
21 | "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b",
22 | "shasum": ""
23 | },
24 | "require": {
25 | "php": "^7.1 || ^8.0"
26 | },
27 | "require-dev": {
28 | "doctrine/coding-standard": "^8.0",
29 | "ext-pdo": "*",
30 | "ext-phar": "*",
31 | "phpbench/phpbench": "^0.13 || 1.0.0-alpha2",
32 | "phpstan/phpstan": "^0.12",
33 | "phpstan/phpstan-phpunit": "^0.12",
34 | "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
35 | },
36 | "type": "library",
37 | "autoload": {
38 | "psr-4": {
39 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
40 | }
41 | },
42 | "notification-url": "https://packagist.org/downloads/",
43 | "license": [
44 | "MIT"
45 | ],
46 | "authors": [
47 | {
48 | "name": "Marco Pivetta",
49 | "email": "ocramius@gmail.com",
50 | "homepage": "https://ocramius.github.io/"
51 | }
52 | ],
53 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
54 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
55 | "keywords": [
56 | "constructor",
57 | "instantiate"
58 | ],
59 | "funding": [
60 | {
61 | "url": "https://www.doctrine-project.org/sponsorship.html",
62 | "type": "custom"
63 | },
64 | {
65 | "url": "https://www.patreon.com/phpdoctrine",
66 | "type": "patreon"
67 | },
68 | {
69 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
70 | "type": "tidelift"
71 | }
72 | ],
73 | "time": "2020-11-10T18:47:58+00:00"
74 | },
75 | {
76 | "name": "myclabs/deep-copy",
77 | "version": "1.10.2",
78 | "source": {
79 | "type": "git",
80 | "url": "https://github.com/myclabs/DeepCopy.git",
81 | "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220"
82 | },
83 | "dist": {
84 | "type": "zip",
85 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220",
86 | "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220",
87 | "shasum": ""
88 | },
89 | "require": {
90 | "php": "^7.1 || ^8.0"
91 | },
92 | "replace": {
93 | "myclabs/deep-copy": "self.version"
94 | },
95 | "require-dev": {
96 | "doctrine/collections": "^1.0",
97 | "doctrine/common": "^2.6",
98 | "phpunit/phpunit": "^7.1"
99 | },
100 | "type": "library",
101 | "autoload": {
102 | "psr-4": {
103 | "DeepCopy\\": "src/DeepCopy/"
104 | },
105 | "files": [
106 | "src/DeepCopy/deep_copy.php"
107 | ]
108 | },
109 | "notification-url": "https://packagist.org/downloads/",
110 | "license": [
111 | "MIT"
112 | ],
113 | "description": "Create deep copies (clones) of your objects",
114 | "keywords": [
115 | "clone",
116 | "copy",
117 | "duplicate",
118 | "object",
119 | "object graph"
120 | ],
121 | "funding": [
122 | {
123 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
124 | "type": "tidelift"
125 | }
126 | ],
127 | "time": "2020-11-13T09:40:50+00:00"
128 | },
129 | {
130 | "name": "nikic/php-parser",
131 | "version": "v4.10.3",
132 | "source": {
133 | "type": "git",
134 | "url": "https://github.com/nikic/PHP-Parser.git",
135 | "reference": "dbe56d23de8fcb157bbc0cfb3ad7c7de0cfb0984"
136 | },
137 | "dist": {
138 | "type": "zip",
139 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dbe56d23de8fcb157bbc0cfb3ad7c7de0cfb0984",
140 | "reference": "dbe56d23de8fcb157bbc0cfb3ad7c7de0cfb0984",
141 | "shasum": ""
142 | },
143 | "require": {
144 | "ext-tokenizer": "*",
145 | "php": ">=7.0"
146 | },
147 | "require-dev": {
148 | "ircmaxell/php-yacc": "^0.0.7",
149 | "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
150 | },
151 | "bin": [
152 | "bin/php-parse"
153 | ],
154 | "type": "library",
155 | "extra": {
156 | "branch-alias": {
157 | "dev-master": "4.9-dev"
158 | }
159 | },
160 | "autoload": {
161 | "psr-4": {
162 | "PhpParser\\": "lib/PhpParser"
163 | }
164 | },
165 | "notification-url": "https://packagist.org/downloads/",
166 | "license": [
167 | "BSD-3-Clause"
168 | ],
169 | "authors": [
170 | {
171 | "name": "Nikita Popov"
172 | }
173 | ],
174 | "description": "A PHP parser written in PHP",
175 | "keywords": [
176 | "parser",
177 | "php"
178 | ],
179 | "time": "2020-12-03T17:45:45+00:00"
180 | },
181 | {
182 | "name": "phar-io/manifest",
183 | "version": "2.0.1",
184 | "source": {
185 | "type": "git",
186 | "url": "https://github.com/phar-io/manifest.git",
187 | "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133"
188 | },
189 | "dist": {
190 | "type": "zip",
191 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133",
192 | "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133",
193 | "shasum": ""
194 | },
195 | "require": {
196 | "ext-dom": "*",
197 | "ext-phar": "*",
198 | "ext-xmlwriter": "*",
199 | "phar-io/version": "^3.0.1",
200 | "php": "^7.2 || ^8.0"
201 | },
202 | "type": "library",
203 | "extra": {
204 | "branch-alias": {
205 | "dev-master": "2.0.x-dev"
206 | }
207 | },
208 | "autoload": {
209 | "classmap": [
210 | "src/"
211 | ]
212 | },
213 | "notification-url": "https://packagist.org/downloads/",
214 | "license": [
215 | "BSD-3-Clause"
216 | ],
217 | "authors": [
218 | {
219 | "name": "Arne Blankerts",
220 | "email": "arne@blankerts.de",
221 | "role": "Developer"
222 | },
223 | {
224 | "name": "Sebastian Heuer",
225 | "email": "sebastian@phpeople.de",
226 | "role": "Developer"
227 | },
228 | {
229 | "name": "Sebastian Bergmann",
230 | "email": "sebastian@phpunit.de",
231 | "role": "Developer"
232 | }
233 | ],
234 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
235 | "time": "2020-06-27T14:33:11+00:00"
236 | },
237 | {
238 | "name": "phar-io/version",
239 | "version": "3.0.3",
240 | "source": {
241 | "type": "git",
242 | "url": "https://github.com/phar-io/version.git",
243 | "reference": "726c026815142e4f8677b7cb7f2249c9ffb7ecae"
244 | },
245 | "dist": {
246 | "type": "zip",
247 | "url": "https://api.github.com/repos/phar-io/version/zipball/726c026815142e4f8677b7cb7f2249c9ffb7ecae",
248 | "reference": "726c026815142e4f8677b7cb7f2249c9ffb7ecae",
249 | "shasum": ""
250 | },
251 | "require": {
252 | "php": "^7.2 || ^8.0"
253 | },
254 | "type": "library",
255 | "autoload": {
256 | "classmap": [
257 | "src/"
258 | ]
259 | },
260 | "notification-url": "https://packagist.org/downloads/",
261 | "license": [
262 | "BSD-3-Clause"
263 | ],
264 | "authors": [
265 | {
266 | "name": "Arne Blankerts",
267 | "email": "arne@blankerts.de",
268 | "role": "Developer"
269 | },
270 | {
271 | "name": "Sebastian Heuer",
272 | "email": "sebastian@phpeople.de",
273 | "role": "Developer"
274 | },
275 | {
276 | "name": "Sebastian Bergmann",
277 | "email": "sebastian@phpunit.de",
278 | "role": "Developer"
279 | }
280 | ],
281 | "description": "Library for handling version information and constraints",
282 | "time": "2020-11-30T09:21:21+00:00"
283 | },
284 | {
285 | "name": "phpdocumentor/reflection-common",
286 | "version": "2.2.0",
287 | "source": {
288 | "type": "git",
289 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
290 | "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
291 | },
292 | "dist": {
293 | "type": "zip",
294 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
295 | "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
296 | "shasum": ""
297 | },
298 | "require": {
299 | "php": "^7.2 || ^8.0"
300 | },
301 | "type": "library",
302 | "extra": {
303 | "branch-alias": {
304 | "dev-2.x": "2.x-dev"
305 | }
306 | },
307 | "autoload": {
308 | "psr-4": {
309 | "phpDocumentor\\Reflection\\": "src/"
310 | }
311 | },
312 | "notification-url": "https://packagist.org/downloads/",
313 | "license": [
314 | "MIT"
315 | ],
316 | "authors": [
317 | {
318 | "name": "Jaap van Otterdijk",
319 | "email": "opensource@ijaap.nl"
320 | }
321 | ],
322 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
323 | "homepage": "http://www.phpdoc.org",
324 | "keywords": [
325 | "FQSEN",
326 | "phpDocumentor",
327 | "phpdoc",
328 | "reflection",
329 | "static analysis"
330 | ],
331 | "time": "2020-06-27T09:03:43+00:00"
332 | },
333 | {
334 | "name": "phpdocumentor/reflection-docblock",
335 | "version": "5.2.2",
336 | "source": {
337 | "type": "git",
338 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
339 | "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556"
340 | },
341 | "dist": {
342 | "type": "zip",
343 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556",
344 | "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556",
345 | "shasum": ""
346 | },
347 | "require": {
348 | "ext-filter": "*",
349 | "php": "^7.2 || ^8.0",
350 | "phpdocumentor/reflection-common": "^2.2",
351 | "phpdocumentor/type-resolver": "^1.3",
352 | "webmozart/assert": "^1.9.1"
353 | },
354 | "require-dev": {
355 | "mockery/mockery": "~1.3.2"
356 | },
357 | "type": "library",
358 | "extra": {
359 | "branch-alias": {
360 | "dev-master": "5.x-dev"
361 | }
362 | },
363 | "autoload": {
364 | "psr-4": {
365 | "phpDocumentor\\Reflection\\": "src"
366 | }
367 | },
368 | "notification-url": "https://packagist.org/downloads/",
369 | "license": [
370 | "MIT"
371 | ],
372 | "authors": [
373 | {
374 | "name": "Mike van Riel",
375 | "email": "me@mikevanriel.com"
376 | },
377 | {
378 | "name": "Jaap van Otterdijk",
379 | "email": "account@ijaap.nl"
380 | }
381 | ],
382 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
383 | "time": "2020-09-03T19:13:55+00:00"
384 | },
385 | {
386 | "name": "phpdocumentor/type-resolver",
387 | "version": "1.4.0",
388 | "source": {
389 | "type": "git",
390 | "url": "https://github.com/phpDocumentor/TypeResolver.git",
391 | "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0"
392 | },
393 | "dist": {
394 | "type": "zip",
395 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0",
396 | "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0",
397 | "shasum": ""
398 | },
399 | "require": {
400 | "php": "^7.2 || ^8.0",
401 | "phpdocumentor/reflection-common": "^2.0"
402 | },
403 | "require-dev": {
404 | "ext-tokenizer": "*"
405 | },
406 | "type": "library",
407 | "extra": {
408 | "branch-alias": {
409 | "dev-1.x": "1.x-dev"
410 | }
411 | },
412 | "autoload": {
413 | "psr-4": {
414 | "phpDocumentor\\Reflection\\": "src"
415 | }
416 | },
417 | "notification-url": "https://packagist.org/downloads/",
418 | "license": [
419 | "MIT"
420 | ],
421 | "authors": [
422 | {
423 | "name": "Mike van Riel",
424 | "email": "me@mikevanriel.com"
425 | }
426 | ],
427 | "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
428 | "time": "2020-09-17T18:55:26+00:00"
429 | },
430 | {
431 | "name": "phpspec/prophecy",
432 | "version": "1.12.1",
433 | "source": {
434 | "type": "git",
435 | "url": "https://github.com/phpspec/prophecy.git",
436 | "reference": "8ce87516be71aae9b956f81906aaf0338e0d8a2d"
437 | },
438 | "dist": {
439 | "type": "zip",
440 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/8ce87516be71aae9b956f81906aaf0338e0d8a2d",
441 | "reference": "8ce87516be71aae9b956f81906aaf0338e0d8a2d",
442 | "shasum": ""
443 | },
444 | "require": {
445 | "doctrine/instantiator": "^1.2",
446 | "php": "^7.2 || ~8.0, <8.1",
447 | "phpdocumentor/reflection-docblock": "^5.2",
448 | "sebastian/comparator": "^3.0 || ^4.0",
449 | "sebastian/recursion-context": "^3.0 || ^4.0"
450 | },
451 | "require-dev": {
452 | "phpspec/phpspec": "^6.0",
453 | "phpunit/phpunit": "^8.0 || ^9.0 <9.3"
454 | },
455 | "type": "library",
456 | "extra": {
457 | "branch-alias": {
458 | "dev-master": "1.11.x-dev"
459 | }
460 | },
461 | "autoload": {
462 | "psr-4": {
463 | "Prophecy\\": "src/Prophecy"
464 | }
465 | },
466 | "notification-url": "https://packagist.org/downloads/",
467 | "license": [
468 | "MIT"
469 | ],
470 | "authors": [
471 | {
472 | "name": "Konstantin Kudryashov",
473 | "email": "ever.zet@gmail.com",
474 | "homepage": "http://everzet.com"
475 | },
476 | {
477 | "name": "Marcello Duarte",
478 | "email": "marcello.duarte@gmail.com"
479 | }
480 | ],
481 | "description": "Highly opinionated mocking framework for PHP 5.3+",
482 | "homepage": "https://github.com/phpspec/prophecy",
483 | "keywords": [
484 | "Double",
485 | "Dummy",
486 | "fake",
487 | "mock",
488 | "spy",
489 | "stub"
490 | ],
491 | "time": "2020-09-29T09:10:42+00:00"
492 | },
493 | {
494 | "name": "phpunit/php-code-coverage",
495 | "version": "9.2.5",
496 | "source": {
497 | "type": "git",
498 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
499 | "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1"
500 | },
501 | "dist": {
502 | "type": "zip",
503 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f3e026641cc91909d421802dd3ac7827ebfd97e1",
504 | "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1",
505 | "shasum": ""
506 | },
507 | "require": {
508 | "ext-dom": "*",
509 | "ext-libxml": "*",
510 | "ext-xmlwriter": "*",
511 | "nikic/php-parser": "^4.10.2",
512 | "php": ">=7.3",
513 | "phpunit/php-file-iterator": "^3.0.3",
514 | "phpunit/php-text-template": "^2.0.2",
515 | "sebastian/code-unit-reverse-lookup": "^2.0.2",
516 | "sebastian/complexity": "^2.0",
517 | "sebastian/environment": "^5.1.2",
518 | "sebastian/lines-of-code": "^1.0.3",
519 | "sebastian/version": "^3.0.1",
520 | "theseer/tokenizer": "^1.2.0"
521 | },
522 | "require-dev": {
523 | "phpunit/phpunit": "^9.3"
524 | },
525 | "suggest": {
526 | "ext-pcov": "*",
527 | "ext-xdebug": "*"
528 | },
529 | "type": "library",
530 | "extra": {
531 | "branch-alias": {
532 | "dev-master": "9.2-dev"
533 | }
534 | },
535 | "autoload": {
536 | "classmap": [
537 | "src/"
538 | ]
539 | },
540 | "notification-url": "https://packagist.org/downloads/",
541 | "license": [
542 | "BSD-3-Clause"
543 | ],
544 | "authors": [
545 | {
546 | "name": "Sebastian Bergmann",
547 | "email": "sebastian@phpunit.de",
548 | "role": "lead"
549 | }
550 | ],
551 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
552 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
553 | "keywords": [
554 | "coverage",
555 | "testing",
556 | "xunit"
557 | ],
558 | "funding": [
559 | {
560 | "url": "https://github.com/sebastianbergmann",
561 | "type": "github"
562 | }
563 | ],
564 | "time": "2020-11-28T06:44:49+00:00"
565 | },
566 | {
567 | "name": "phpunit/php-file-iterator",
568 | "version": "3.0.5",
569 | "source": {
570 | "type": "git",
571 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
572 | "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8"
573 | },
574 | "dist": {
575 | "type": "zip",
576 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8",
577 | "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8",
578 | "shasum": ""
579 | },
580 | "require": {
581 | "php": ">=7.3"
582 | },
583 | "require-dev": {
584 | "phpunit/phpunit": "^9.3"
585 | },
586 | "type": "library",
587 | "extra": {
588 | "branch-alias": {
589 | "dev-master": "3.0-dev"
590 | }
591 | },
592 | "autoload": {
593 | "classmap": [
594 | "src/"
595 | ]
596 | },
597 | "notification-url": "https://packagist.org/downloads/",
598 | "license": [
599 | "BSD-3-Clause"
600 | ],
601 | "authors": [
602 | {
603 | "name": "Sebastian Bergmann",
604 | "email": "sebastian@phpunit.de",
605 | "role": "lead"
606 | }
607 | ],
608 | "description": "FilterIterator implementation that filters files based on a list of suffixes.",
609 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
610 | "keywords": [
611 | "filesystem",
612 | "iterator"
613 | ],
614 | "funding": [
615 | {
616 | "url": "https://github.com/sebastianbergmann",
617 | "type": "github"
618 | }
619 | ],
620 | "time": "2020-09-28T05:57:25+00:00"
621 | },
622 | {
623 | "name": "phpunit/php-invoker",
624 | "version": "3.1.1",
625 | "source": {
626 | "type": "git",
627 | "url": "https://github.com/sebastianbergmann/php-invoker.git",
628 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67"
629 | },
630 | "dist": {
631 | "type": "zip",
632 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
633 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
634 | "shasum": ""
635 | },
636 | "require": {
637 | "php": ">=7.3"
638 | },
639 | "require-dev": {
640 | "ext-pcntl": "*",
641 | "phpunit/phpunit": "^9.3"
642 | },
643 | "suggest": {
644 | "ext-pcntl": "*"
645 | },
646 | "type": "library",
647 | "extra": {
648 | "branch-alias": {
649 | "dev-master": "3.1-dev"
650 | }
651 | },
652 | "autoload": {
653 | "classmap": [
654 | "src/"
655 | ]
656 | },
657 | "notification-url": "https://packagist.org/downloads/",
658 | "license": [
659 | "BSD-3-Clause"
660 | ],
661 | "authors": [
662 | {
663 | "name": "Sebastian Bergmann",
664 | "email": "sebastian@phpunit.de",
665 | "role": "lead"
666 | }
667 | ],
668 | "description": "Invoke callables with a timeout",
669 | "homepage": "https://github.com/sebastianbergmann/php-invoker/",
670 | "keywords": [
671 | "process"
672 | ],
673 | "funding": [
674 | {
675 | "url": "https://github.com/sebastianbergmann",
676 | "type": "github"
677 | }
678 | ],
679 | "time": "2020-09-28T05:58:55+00:00"
680 | },
681 | {
682 | "name": "phpunit/php-text-template",
683 | "version": "2.0.4",
684 | "source": {
685 | "type": "git",
686 | "url": "https://github.com/sebastianbergmann/php-text-template.git",
687 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28"
688 | },
689 | "dist": {
690 | "type": "zip",
691 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
692 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
693 | "shasum": ""
694 | },
695 | "require": {
696 | "php": ">=7.3"
697 | },
698 | "require-dev": {
699 | "phpunit/phpunit": "^9.3"
700 | },
701 | "type": "library",
702 | "extra": {
703 | "branch-alias": {
704 | "dev-master": "2.0-dev"
705 | }
706 | },
707 | "autoload": {
708 | "classmap": [
709 | "src/"
710 | ]
711 | },
712 | "notification-url": "https://packagist.org/downloads/",
713 | "license": [
714 | "BSD-3-Clause"
715 | ],
716 | "authors": [
717 | {
718 | "name": "Sebastian Bergmann",
719 | "email": "sebastian@phpunit.de",
720 | "role": "lead"
721 | }
722 | ],
723 | "description": "Simple template engine.",
724 | "homepage": "https://github.com/sebastianbergmann/php-text-template/",
725 | "keywords": [
726 | "template"
727 | ],
728 | "funding": [
729 | {
730 | "url": "https://github.com/sebastianbergmann",
731 | "type": "github"
732 | }
733 | ],
734 | "time": "2020-10-26T05:33:50+00:00"
735 | },
736 | {
737 | "name": "phpunit/php-timer",
738 | "version": "5.0.3",
739 | "source": {
740 | "type": "git",
741 | "url": "https://github.com/sebastianbergmann/php-timer.git",
742 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2"
743 | },
744 | "dist": {
745 | "type": "zip",
746 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
747 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
748 | "shasum": ""
749 | },
750 | "require": {
751 | "php": ">=7.3"
752 | },
753 | "require-dev": {
754 | "phpunit/phpunit": "^9.3"
755 | },
756 | "type": "library",
757 | "extra": {
758 | "branch-alias": {
759 | "dev-master": "5.0-dev"
760 | }
761 | },
762 | "autoload": {
763 | "classmap": [
764 | "src/"
765 | ]
766 | },
767 | "notification-url": "https://packagist.org/downloads/",
768 | "license": [
769 | "BSD-3-Clause"
770 | ],
771 | "authors": [
772 | {
773 | "name": "Sebastian Bergmann",
774 | "email": "sebastian@phpunit.de",
775 | "role": "lead"
776 | }
777 | ],
778 | "description": "Utility class for timing",
779 | "homepage": "https://github.com/sebastianbergmann/php-timer/",
780 | "keywords": [
781 | "timer"
782 | ],
783 | "funding": [
784 | {
785 | "url": "https://github.com/sebastianbergmann",
786 | "type": "github"
787 | }
788 | ],
789 | "time": "2020-10-26T13:16:10+00:00"
790 | },
791 | {
792 | "name": "phpunit/phpunit",
793 | "version": "9.5.0",
794 | "source": {
795 | "type": "git",
796 | "url": "https://github.com/sebastianbergmann/phpunit.git",
797 | "reference": "8e16c225d57c3d6808014df6b1dd7598d0a5bbbe"
798 | },
799 | "dist": {
800 | "type": "zip",
801 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8e16c225d57c3d6808014df6b1dd7598d0a5bbbe",
802 | "reference": "8e16c225d57c3d6808014df6b1dd7598d0a5bbbe",
803 | "shasum": ""
804 | },
805 | "require": {
806 | "doctrine/instantiator": "^1.3.1",
807 | "ext-dom": "*",
808 | "ext-json": "*",
809 | "ext-libxml": "*",
810 | "ext-mbstring": "*",
811 | "ext-xml": "*",
812 | "ext-xmlwriter": "*",
813 | "myclabs/deep-copy": "^1.10.1",
814 | "phar-io/manifest": "^2.0.1",
815 | "phar-io/version": "^3.0.2",
816 | "php": ">=7.3",
817 | "phpspec/prophecy": "^1.12.1",
818 | "phpunit/php-code-coverage": "^9.2.3",
819 | "phpunit/php-file-iterator": "^3.0.5",
820 | "phpunit/php-invoker": "^3.1.1",
821 | "phpunit/php-text-template": "^2.0.3",
822 | "phpunit/php-timer": "^5.0.2",
823 | "sebastian/cli-parser": "^1.0.1",
824 | "sebastian/code-unit": "^1.0.6",
825 | "sebastian/comparator": "^4.0.5",
826 | "sebastian/diff": "^4.0.3",
827 | "sebastian/environment": "^5.1.3",
828 | "sebastian/exporter": "^4.0.3",
829 | "sebastian/global-state": "^5.0.1",
830 | "sebastian/object-enumerator": "^4.0.3",
831 | "sebastian/resource-operations": "^3.0.3",
832 | "sebastian/type": "^2.3",
833 | "sebastian/version": "^3.0.2"
834 | },
835 | "require-dev": {
836 | "ext-pdo": "*",
837 | "phpspec/prophecy-phpunit": "^2.0.1"
838 | },
839 | "suggest": {
840 | "ext-soap": "*",
841 | "ext-xdebug": "*"
842 | },
843 | "bin": [
844 | "phpunit"
845 | ],
846 | "type": "library",
847 | "extra": {
848 | "branch-alias": {
849 | "dev-master": "9.5-dev"
850 | }
851 | },
852 | "autoload": {
853 | "classmap": [
854 | "src/"
855 | ],
856 | "files": [
857 | "src/Framework/Assert/Functions.php"
858 | ]
859 | },
860 | "notification-url": "https://packagist.org/downloads/",
861 | "license": [
862 | "BSD-3-Clause"
863 | ],
864 | "authors": [
865 | {
866 | "name": "Sebastian Bergmann",
867 | "email": "sebastian@phpunit.de",
868 | "role": "lead"
869 | }
870 | ],
871 | "description": "The PHP Unit Testing framework.",
872 | "homepage": "https://phpunit.de/",
873 | "keywords": [
874 | "phpunit",
875 | "testing",
876 | "xunit"
877 | ],
878 | "funding": [
879 | {
880 | "url": "https://phpunit.de/donate.html",
881 | "type": "custom"
882 | },
883 | {
884 | "url": "https://github.com/sebastianbergmann",
885 | "type": "github"
886 | }
887 | ],
888 | "time": "2020-12-04T05:05:53+00:00"
889 | },
890 | {
891 | "name": "sebastian/cli-parser",
892 | "version": "1.0.1",
893 | "source": {
894 | "type": "git",
895 | "url": "https://github.com/sebastianbergmann/cli-parser.git",
896 | "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2"
897 | },
898 | "dist": {
899 | "type": "zip",
900 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2",
901 | "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2",
902 | "shasum": ""
903 | },
904 | "require": {
905 | "php": ">=7.3"
906 | },
907 | "require-dev": {
908 | "phpunit/phpunit": "^9.3"
909 | },
910 | "type": "library",
911 | "extra": {
912 | "branch-alias": {
913 | "dev-master": "1.0-dev"
914 | }
915 | },
916 | "autoload": {
917 | "classmap": [
918 | "src/"
919 | ]
920 | },
921 | "notification-url": "https://packagist.org/downloads/",
922 | "license": [
923 | "BSD-3-Clause"
924 | ],
925 | "authors": [
926 | {
927 | "name": "Sebastian Bergmann",
928 | "email": "sebastian@phpunit.de",
929 | "role": "lead"
930 | }
931 | ],
932 | "description": "Library for parsing CLI options",
933 | "homepage": "https://github.com/sebastianbergmann/cli-parser",
934 | "funding": [
935 | {
936 | "url": "https://github.com/sebastianbergmann",
937 | "type": "github"
938 | }
939 | ],
940 | "time": "2020-09-28T06:08:49+00:00"
941 | },
942 | {
943 | "name": "sebastian/code-unit",
944 | "version": "1.0.8",
945 | "source": {
946 | "type": "git",
947 | "url": "https://github.com/sebastianbergmann/code-unit.git",
948 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120"
949 | },
950 | "dist": {
951 | "type": "zip",
952 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120",
953 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120",
954 | "shasum": ""
955 | },
956 | "require": {
957 | "php": ">=7.3"
958 | },
959 | "require-dev": {
960 | "phpunit/phpunit": "^9.3"
961 | },
962 | "type": "library",
963 | "extra": {
964 | "branch-alias": {
965 | "dev-master": "1.0-dev"
966 | }
967 | },
968 | "autoload": {
969 | "classmap": [
970 | "src/"
971 | ]
972 | },
973 | "notification-url": "https://packagist.org/downloads/",
974 | "license": [
975 | "BSD-3-Clause"
976 | ],
977 | "authors": [
978 | {
979 | "name": "Sebastian Bergmann",
980 | "email": "sebastian@phpunit.de",
981 | "role": "lead"
982 | }
983 | ],
984 | "description": "Collection of value objects that represent the PHP code units",
985 | "homepage": "https://github.com/sebastianbergmann/code-unit",
986 | "funding": [
987 | {
988 | "url": "https://github.com/sebastianbergmann",
989 | "type": "github"
990 | }
991 | ],
992 | "time": "2020-10-26T13:08:54+00:00"
993 | },
994 | {
995 | "name": "sebastian/code-unit-reverse-lookup",
996 | "version": "2.0.3",
997 | "source": {
998 | "type": "git",
999 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
1000 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5"
1001 | },
1002 | "dist": {
1003 | "type": "zip",
1004 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
1005 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
1006 | "shasum": ""
1007 | },
1008 | "require": {
1009 | "php": ">=7.3"
1010 | },
1011 | "require-dev": {
1012 | "phpunit/phpunit": "^9.3"
1013 | },
1014 | "type": "library",
1015 | "extra": {
1016 | "branch-alias": {
1017 | "dev-master": "2.0-dev"
1018 | }
1019 | },
1020 | "autoload": {
1021 | "classmap": [
1022 | "src/"
1023 | ]
1024 | },
1025 | "notification-url": "https://packagist.org/downloads/",
1026 | "license": [
1027 | "BSD-3-Clause"
1028 | ],
1029 | "authors": [
1030 | {
1031 | "name": "Sebastian Bergmann",
1032 | "email": "sebastian@phpunit.de"
1033 | }
1034 | ],
1035 | "description": "Looks up which function or method a line of code belongs to",
1036 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
1037 | "funding": [
1038 | {
1039 | "url": "https://github.com/sebastianbergmann",
1040 | "type": "github"
1041 | }
1042 | ],
1043 | "time": "2020-09-28T05:30:19+00:00"
1044 | },
1045 | {
1046 | "name": "sebastian/comparator",
1047 | "version": "4.0.6",
1048 | "source": {
1049 | "type": "git",
1050 | "url": "https://github.com/sebastianbergmann/comparator.git",
1051 | "reference": "55f4261989e546dc112258c7a75935a81a7ce382"
1052 | },
1053 | "dist": {
1054 | "type": "zip",
1055 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382",
1056 | "reference": "55f4261989e546dc112258c7a75935a81a7ce382",
1057 | "shasum": ""
1058 | },
1059 | "require": {
1060 | "php": ">=7.3",
1061 | "sebastian/diff": "^4.0",
1062 | "sebastian/exporter": "^4.0"
1063 | },
1064 | "require-dev": {
1065 | "phpunit/phpunit": "^9.3"
1066 | },
1067 | "type": "library",
1068 | "extra": {
1069 | "branch-alias": {
1070 | "dev-master": "4.0-dev"
1071 | }
1072 | },
1073 | "autoload": {
1074 | "classmap": [
1075 | "src/"
1076 | ]
1077 | },
1078 | "notification-url": "https://packagist.org/downloads/",
1079 | "license": [
1080 | "BSD-3-Clause"
1081 | ],
1082 | "authors": [
1083 | {
1084 | "name": "Sebastian Bergmann",
1085 | "email": "sebastian@phpunit.de"
1086 | },
1087 | {
1088 | "name": "Jeff Welch",
1089 | "email": "whatthejeff@gmail.com"
1090 | },
1091 | {
1092 | "name": "Volker Dusch",
1093 | "email": "github@wallbash.com"
1094 | },
1095 | {
1096 | "name": "Bernhard Schussek",
1097 | "email": "bschussek@2bepublished.at"
1098 | }
1099 | ],
1100 | "description": "Provides the functionality to compare PHP values for equality",
1101 | "homepage": "https://github.com/sebastianbergmann/comparator",
1102 | "keywords": [
1103 | "comparator",
1104 | "compare",
1105 | "equality"
1106 | ],
1107 | "funding": [
1108 | {
1109 | "url": "https://github.com/sebastianbergmann",
1110 | "type": "github"
1111 | }
1112 | ],
1113 | "time": "2020-10-26T15:49:45+00:00"
1114 | },
1115 | {
1116 | "name": "sebastian/complexity",
1117 | "version": "2.0.2",
1118 | "source": {
1119 | "type": "git",
1120 | "url": "https://github.com/sebastianbergmann/complexity.git",
1121 | "reference": "739b35e53379900cc9ac327b2147867b8b6efd88"
1122 | },
1123 | "dist": {
1124 | "type": "zip",
1125 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88",
1126 | "reference": "739b35e53379900cc9ac327b2147867b8b6efd88",
1127 | "shasum": ""
1128 | },
1129 | "require": {
1130 | "nikic/php-parser": "^4.7",
1131 | "php": ">=7.3"
1132 | },
1133 | "require-dev": {
1134 | "phpunit/phpunit": "^9.3"
1135 | },
1136 | "type": "library",
1137 | "extra": {
1138 | "branch-alias": {
1139 | "dev-master": "2.0-dev"
1140 | }
1141 | },
1142 | "autoload": {
1143 | "classmap": [
1144 | "src/"
1145 | ]
1146 | },
1147 | "notification-url": "https://packagist.org/downloads/",
1148 | "license": [
1149 | "BSD-3-Clause"
1150 | ],
1151 | "authors": [
1152 | {
1153 | "name": "Sebastian Bergmann",
1154 | "email": "sebastian@phpunit.de",
1155 | "role": "lead"
1156 | }
1157 | ],
1158 | "description": "Library for calculating the complexity of PHP code units",
1159 | "homepage": "https://github.com/sebastianbergmann/complexity",
1160 | "funding": [
1161 | {
1162 | "url": "https://github.com/sebastianbergmann",
1163 | "type": "github"
1164 | }
1165 | ],
1166 | "time": "2020-10-26T15:52:27+00:00"
1167 | },
1168 | {
1169 | "name": "sebastian/diff",
1170 | "version": "4.0.4",
1171 | "source": {
1172 | "type": "git",
1173 | "url": "https://github.com/sebastianbergmann/diff.git",
1174 | "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d"
1175 | },
1176 | "dist": {
1177 | "type": "zip",
1178 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d",
1179 | "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d",
1180 | "shasum": ""
1181 | },
1182 | "require": {
1183 | "php": ">=7.3"
1184 | },
1185 | "require-dev": {
1186 | "phpunit/phpunit": "^9.3",
1187 | "symfony/process": "^4.2 || ^5"
1188 | },
1189 | "type": "library",
1190 | "extra": {
1191 | "branch-alias": {
1192 | "dev-master": "4.0-dev"
1193 | }
1194 | },
1195 | "autoload": {
1196 | "classmap": [
1197 | "src/"
1198 | ]
1199 | },
1200 | "notification-url": "https://packagist.org/downloads/",
1201 | "license": [
1202 | "BSD-3-Clause"
1203 | ],
1204 | "authors": [
1205 | {
1206 | "name": "Sebastian Bergmann",
1207 | "email": "sebastian@phpunit.de"
1208 | },
1209 | {
1210 | "name": "Kore Nordmann",
1211 | "email": "mail@kore-nordmann.de"
1212 | }
1213 | ],
1214 | "description": "Diff implementation",
1215 | "homepage": "https://github.com/sebastianbergmann/diff",
1216 | "keywords": [
1217 | "diff",
1218 | "udiff",
1219 | "unidiff",
1220 | "unified diff"
1221 | ],
1222 | "funding": [
1223 | {
1224 | "url": "https://github.com/sebastianbergmann",
1225 | "type": "github"
1226 | }
1227 | ],
1228 | "time": "2020-10-26T13:10:38+00:00"
1229 | },
1230 | {
1231 | "name": "sebastian/environment",
1232 | "version": "5.1.3",
1233 | "source": {
1234 | "type": "git",
1235 | "url": "https://github.com/sebastianbergmann/environment.git",
1236 | "reference": "388b6ced16caa751030f6a69e588299fa09200ac"
1237 | },
1238 | "dist": {
1239 | "type": "zip",
1240 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac",
1241 | "reference": "388b6ced16caa751030f6a69e588299fa09200ac",
1242 | "shasum": ""
1243 | },
1244 | "require": {
1245 | "php": ">=7.3"
1246 | },
1247 | "require-dev": {
1248 | "phpunit/phpunit": "^9.3"
1249 | },
1250 | "suggest": {
1251 | "ext-posix": "*"
1252 | },
1253 | "type": "library",
1254 | "extra": {
1255 | "branch-alias": {
1256 | "dev-master": "5.1-dev"
1257 | }
1258 | },
1259 | "autoload": {
1260 | "classmap": [
1261 | "src/"
1262 | ]
1263 | },
1264 | "notification-url": "https://packagist.org/downloads/",
1265 | "license": [
1266 | "BSD-3-Clause"
1267 | ],
1268 | "authors": [
1269 | {
1270 | "name": "Sebastian Bergmann",
1271 | "email": "sebastian@phpunit.de"
1272 | }
1273 | ],
1274 | "description": "Provides functionality to handle HHVM/PHP environments",
1275 | "homepage": "http://www.github.com/sebastianbergmann/environment",
1276 | "keywords": [
1277 | "Xdebug",
1278 | "environment",
1279 | "hhvm"
1280 | ],
1281 | "funding": [
1282 | {
1283 | "url": "https://github.com/sebastianbergmann",
1284 | "type": "github"
1285 | }
1286 | ],
1287 | "time": "2020-09-28T05:52:38+00:00"
1288 | },
1289 | {
1290 | "name": "sebastian/exporter",
1291 | "version": "4.0.3",
1292 | "source": {
1293 | "type": "git",
1294 | "url": "https://github.com/sebastianbergmann/exporter.git",
1295 | "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65"
1296 | },
1297 | "dist": {
1298 | "type": "zip",
1299 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65",
1300 | "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65",
1301 | "shasum": ""
1302 | },
1303 | "require": {
1304 | "php": ">=7.3",
1305 | "sebastian/recursion-context": "^4.0"
1306 | },
1307 | "require-dev": {
1308 | "ext-mbstring": "*",
1309 | "phpunit/phpunit": "^9.3"
1310 | },
1311 | "type": "library",
1312 | "extra": {
1313 | "branch-alias": {
1314 | "dev-master": "4.0-dev"
1315 | }
1316 | },
1317 | "autoload": {
1318 | "classmap": [
1319 | "src/"
1320 | ]
1321 | },
1322 | "notification-url": "https://packagist.org/downloads/",
1323 | "license": [
1324 | "BSD-3-Clause"
1325 | ],
1326 | "authors": [
1327 | {
1328 | "name": "Sebastian Bergmann",
1329 | "email": "sebastian@phpunit.de"
1330 | },
1331 | {
1332 | "name": "Jeff Welch",
1333 | "email": "whatthejeff@gmail.com"
1334 | },
1335 | {
1336 | "name": "Volker Dusch",
1337 | "email": "github@wallbash.com"
1338 | },
1339 | {
1340 | "name": "Adam Harvey",
1341 | "email": "aharvey@php.net"
1342 | },
1343 | {
1344 | "name": "Bernhard Schussek",
1345 | "email": "bschussek@gmail.com"
1346 | }
1347 | ],
1348 | "description": "Provides the functionality to export PHP variables for visualization",
1349 | "homepage": "http://www.github.com/sebastianbergmann/exporter",
1350 | "keywords": [
1351 | "export",
1352 | "exporter"
1353 | ],
1354 | "funding": [
1355 | {
1356 | "url": "https://github.com/sebastianbergmann",
1357 | "type": "github"
1358 | }
1359 | ],
1360 | "time": "2020-09-28T05:24:23+00:00"
1361 | },
1362 | {
1363 | "name": "sebastian/global-state",
1364 | "version": "5.0.2",
1365 | "source": {
1366 | "type": "git",
1367 | "url": "https://github.com/sebastianbergmann/global-state.git",
1368 | "reference": "a90ccbddffa067b51f574dea6eb25d5680839455"
1369 | },
1370 | "dist": {
1371 | "type": "zip",
1372 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a90ccbddffa067b51f574dea6eb25d5680839455",
1373 | "reference": "a90ccbddffa067b51f574dea6eb25d5680839455",
1374 | "shasum": ""
1375 | },
1376 | "require": {
1377 | "php": ">=7.3",
1378 | "sebastian/object-reflector": "^2.0",
1379 | "sebastian/recursion-context": "^4.0"
1380 | },
1381 | "require-dev": {
1382 | "ext-dom": "*",
1383 | "phpunit/phpunit": "^9.3"
1384 | },
1385 | "suggest": {
1386 | "ext-uopz": "*"
1387 | },
1388 | "type": "library",
1389 | "extra": {
1390 | "branch-alias": {
1391 | "dev-master": "5.0-dev"
1392 | }
1393 | },
1394 | "autoload": {
1395 | "classmap": [
1396 | "src/"
1397 | ]
1398 | },
1399 | "notification-url": "https://packagist.org/downloads/",
1400 | "license": [
1401 | "BSD-3-Clause"
1402 | ],
1403 | "authors": [
1404 | {
1405 | "name": "Sebastian Bergmann",
1406 | "email": "sebastian@phpunit.de"
1407 | }
1408 | ],
1409 | "description": "Snapshotting of global state",
1410 | "homepage": "http://www.github.com/sebastianbergmann/global-state",
1411 | "keywords": [
1412 | "global state"
1413 | ],
1414 | "funding": [
1415 | {
1416 | "url": "https://github.com/sebastianbergmann",
1417 | "type": "github"
1418 | }
1419 | ],
1420 | "time": "2020-10-26T15:55:19+00:00"
1421 | },
1422 | {
1423 | "name": "sebastian/lines-of-code",
1424 | "version": "1.0.3",
1425 | "source": {
1426 | "type": "git",
1427 | "url": "https://github.com/sebastianbergmann/lines-of-code.git",
1428 | "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc"
1429 | },
1430 | "dist": {
1431 | "type": "zip",
1432 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc",
1433 | "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc",
1434 | "shasum": ""
1435 | },
1436 | "require": {
1437 | "nikic/php-parser": "^4.6",
1438 | "php": ">=7.3"
1439 | },
1440 | "require-dev": {
1441 | "phpunit/phpunit": "^9.3"
1442 | },
1443 | "type": "library",
1444 | "extra": {
1445 | "branch-alias": {
1446 | "dev-master": "1.0-dev"
1447 | }
1448 | },
1449 | "autoload": {
1450 | "classmap": [
1451 | "src/"
1452 | ]
1453 | },
1454 | "notification-url": "https://packagist.org/downloads/",
1455 | "license": [
1456 | "BSD-3-Clause"
1457 | ],
1458 | "authors": [
1459 | {
1460 | "name": "Sebastian Bergmann",
1461 | "email": "sebastian@phpunit.de",
1462 | "role": "lead"
1463 | }
1464 | ],
1465 | "description": "Library for counting the lines of code in PHP source code",
1466 | "homepage": "https://github.com/sebastianbergmann/lines-of-code",
1467 | "funding": [
1468 | {
1469 | "url": "https://github.com/sebastianbergmann",
1470 | "type": "github"
1471 | }
1472 | ],
1473 | "time": "2020-11-28T06:42:11+00:00"
1474 | },
1475 | {
1476 | "name": "sebastian/object-enumerator",
1477 | "version": "4.0.4",
1478 | "source": {
1479 | "type": "git",
1480 | "url": "https://github.com/sebastianbergmann/object-enumerator.git",
1481 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71"
1482 | },
1483 | "dist": {
1484 | "type": "zip",
1485 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71",
1486 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71",
1487 | "shasum": ""
1488 | },
1489 | "require": {
1490 | "php": ">=7.3",
1491 | "sebastian/object-reflector": "^2.0",
1492 | "sebastian/recursion-context": "^4.0"
1493 | },
1494 | "require-dev": {
1495 | "phpunit/phpunit": "^9.3"
1496 | },
1497 | "type": "library",
1498 | "extra": {
1499 | "branch-alias": {
1500 | "dev-master": "4.0-dev"
1501 | }
1502 | },
1503 | "autoload": {
1504 | "classmap": [
1505 | "src/"
1506 | ]
1507 | },
1508 | "notification-url": "https://packagist.org/downloads/",
1509 | "license": [
1510 | "BSD-3-Clause"
1511 | ],
1512 | "authors": [
1513 | {
1514 | "name": "Sebastian Bergmann",
1515 | "email": "sebastian@phpunit.de"
1516 | }
1517 | ],
1518 | "description": "Traverses array structures and object graphs to enumerate all referenced objects",
1519 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
1520 | "funding": [
1521 | {
1522 | "url": "https://github.com/sebastianbergmann",
1523 | "type": "github"
1524 | }
1525 | ],
1526 | "time": "2020-10-26T13:12:34+00:00"
1527 | },
1528 | {
1529 | "name": "sebastian/object-reflector",
1530 | "version": "2.0.4",
1531 | "source": {
1532 | "type": "git",
1533 | "url": "https://github.com/sebastianbergmann/object-reflector.git",
1534 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7"
1535 | },
1536 | "dist": {
1537 | "type": "zip",
1538 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
1539 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
1540 | "shasum": ""
1541 | },
1542 | "require": {
1543 | "php": ">=7.3"
1544 | },
1545 | "require-dev": {
1546 | "phpunit/phpunit": "^9.3"
1547 | },
1548 | "type": "library",
1549 | "extra": {
1550 | "branch-alias": {
1551 | "dev-master": "2.0-dev"
1552 | }
1553 | },
1554 | "autoload": {
1555 | "classmap": [
1556 | "src/"
1557 | ]
1558 | },
1559 | "notification-url": "https://packagist.org/downloads/",
1560 | "license": [
1561 | "BSD-3-Clause"
1562 | ],
1563 | "authors": [
1564 | {
1565 | "name": "Sebastian Bergmann",
1566 | "email": "sebastian@phpunit.de"
1567 | }
1568 | ],
1569 | "description": "Allows reflection of object attributes, including inherited and non-public ones",
1570 | "homepage": "https://github.com/sebastianbergmann/object-reflector/",
1571 | "funding": [
1572 | {
1573 | "url": "https://github.com/sebastianbergmann",
1574 | "type": "github"
1575 | }
1576 | ],
1577 | "time": "2020-10-26T13:14:26+00:00"
1578 | },
1579 | {
1580 | "name": "sebastian/recursion-context",
1581 | "version": "4.0.4",
1582 | "source": {
1583 | "type": "git",
1584 | "url": "https://github.com/sebastianbergmann/recursion-context.git",
1585 | "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172"
1586 | },
1587 | "dist": {
1588 | "type": "zip",
1589 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172",
1590 | "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172",
1591 | "shasum": ""
1592 | },
1593 | "require": {
1594 | "php": ">=7.3"
1595 | },
1596 | "require-dev": {
1597 | "phpunit/phpunit": "^9.3"
1598 | },
1599 | "type": "library",
1600 | "extra": {
1601 | "branch-alias": {
1602 | "dev-master": "4.0-dev"
1603 | }
1604 | },
1605 | "autoload": {
1606 | "classmap": [
1607 | "src/"
1608 | ]
1609 | },
1610 | "notification-url": "https://packagist.org/downloads/",
1611 | "license": [
1612 | "BSD-3-Clause"
1613 | ],
1614 | "authors": [
1615 | {
1616 | "name": "Sebastian Bergmann",
1617 | "email": "sebastian@phpunit.de"
1618 | },
1619 | {
1620 | "name": "Jeff Welch",
1621 | "email": "whatthejeff@gmail.com"
1622 | },
1623 | {
1624 | "name": "Adam Harvey",
1625 | "email": "aharvey@php.net"
1626 | }
1627 | ],
1628 | "description": "Provides functionality to recursively process PHP variables",
1629 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
1630 | "funding": [
1631 | {
1632 | "url": "https://github.com/sebastianbergmann",
1633 | "type": "github"
1634 | }
1635 | ],
1636 | "time": "2020-10-26T13:17:30+00:00"
1637 | },
1638 | {
1639 | "name": "sebastian/resource-operations",
1640 | "version": "3.0.3",
1641 | "source": {
1642 | "type": "git",
1643 | "url": "https://github.com/sebastianbergmann/resource-operations.git",
1644 | "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8"
1645 | },
1646 | "dist": {
1647 | "type": "zip",
1648 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
1649 | "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
1650 | "shasum": ""
1651 | },
1652 | "require": {
1653 | "php": ">=7.3"
1654 | },
1655 | "require-dev": {
1656 | "phpunit/phpunit": "^9.0"
1657 | },
1658 | "type": "library",
1659 | "extra": {
1660 | "branch-alias": {
1661 | "dev-master": "3.0-dev"
1662 | }
1663 | },
1664 | "autoload": {
1665 | "classmap": [
1666 | "src/"
1667 | ]
1668 | },
1669 | "notification-url": "https://packagist.org/downloads/",
1670 | "license": [
1671 | "BSD-3-Clause"
1672 | ],
1673 | "authors": [
1674 | {
1675 | "name": "Sebastian Bergmann",
1676 | "email": "sebastian@phpunit.de"
1677 | }
1678 | ],
1679 | "description": "Provides a list of PHP built-in functions that operate on resources",
1680 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
1681 | "funding": [
1682 | {
1683 | "url": "https://github.com/sebastianbergmann",
1684 | "type": "github"
1685 | }
1686 | ],
1687 | "time": "2020-09-28T06:45:17+00:00"
1688 | },
1689 | {
1690 | "name": "sebastian/type",
1691 | "version": "2.3.1",
1692 | "source": {
1693 | "type": "git",
1694 | "url": "https://github.com/sebastianbergmann/type.git",
1695 | "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2"
1696 | },
1697 | "dist": {
1698 | "type": "zip",
1699 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2",
1700 | "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2",
1701 | "shasum": ""
1702 | },
1703 | "require": {
1704 | "php": ">=7.3"
1705 | },
1706 | "require-dev": {
1707 | "phpunit/phpunit": "^9.3"
1708 | },
1709 | "type": "library",
1710 | "extra": {
1711 | "branch-alias": {
1712 | "dev-master": "2.3-dev"
1713 | }
1714 | },
1715 | "autoload": {
1716 | "classmap": [
1717 | "src/"
1718 | ]
1719 | },
1720 | "notification-url": "https://packagist.org/downloads/",
1721 | "license": [
1722 | "BSD-3-Clause"
1723 | ],
1724 | "authors": [
1725 | {
1726 | "name": "Sebastian Bergmann",
1727 | "email": "sebastian@phpunit.de",
1728 | "role": "lead"
1729 | }
1730 | ],
1731 | "description": "Collection of value objects that represent the types of the PHP type system",
1732 | "homepage": "https://github.com/sebastianbergmann/type",
1733 | "funding": [
1734 | {
1735 | "url": "https://github.com/sebastianbergmann",
1736 | "type": "github"
1737 | }
1738 | ],
1739 | "time": "2020-10-26T13:18:59+00:00"
1740 | },
1741 | {
1742 | "name": "sebastian/version",
1743 | "version": "3.0.2",
1744 | "source": {
1745 | "type": "git",
1746 | "url": "https://github.com/sebastianbergmann/version.git",
1747 | "reference": "c6c1022351a901512170118436c764e473f6de8c"
1748 | },
1749 | "dist": {
1750 | "type": "zip",
1751 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c",
1752 | "reference": "c6c1022351a901512170118436c764e473f6de8c",
1753 | "shasum": ""
1754 | },
1755 | "require": {
1756 | "php": ">=7.3"
1757 | },
1758 | "type": "library",
1759 | "extra": {
1760 | "branch-alias": {
1761 | "dev-master": "3.0-dev"
1762 | }
1763 | },
1764 | "autoload": {
1765 | "classmap": [
1766 | "src/"
1767 | ]
1768 | },
1769 | "notification-url": "https://packagist.org/downloads/",
1770 | "license": [
1771 | "BSD-3-Clause"
1772 | ],
1773 | "authors": [
1774 | {
1775 | "name": "Sebastian Bergmann",
1776 | "email": "sebastian@phpunit.de",
1777 | "role": "lead"
1778 | }
1779 | ],
1780 | "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1781 | "homepage": "https://github.com/sebastianbergmann/version",
1782 | "funding": [
1783 | {
1784 | "url": "https://github.com/sebastianbergmann",
1785 | "type": "github"
1786 | }
1787 | ],
1788 | "time": "2020-09-28T06:39:44+00:00"
1789 | },
1790 | {
1791 | "name": "squizlabs/php_codesniffer",
1792 | "version": "3.5.8",
1793 | "source": {
1794 | "type": "git",
1795 | "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
1796 | "reference": "9d583721a7157ee997f235f327de038e7ea6dac4"
1797 | },
1798 | "dist": {
1799 | "type": "zip",
1800 | "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4",
1801 | "reference": "9d583721a7157ee997f235f327de038e7ea6dac4",
1802 | "shasum": ""
1803 | },
1804 | "require": {
1805 | "ext-simplexml": "*",
1806 | "ext-tokenizer": "*",
1807 | "ext-xmlwriter": "*",
1808 | "php": ">=5.4.0"
1809 | },
1810 | "require-dev": {
1811 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
1812 | },
1813 | "bin": [
1814 | "bin/phpcs",
1815 | "bin/phpcbf"
1816 | ],
1817 | "type": "library",
1818 | "extra": {
1819 | "branch-alias": {
1820 | "dev-master": "3.x-dev"
1821 | }
1822 | },
1823 | "notification-url": "https://packagist.org/downloads/",
1824 | "license": [
1825 | "BSD-3-Clause"
1826 | ],
1827 | "authors": [
1828 | {
1829 | "name": "Greg Sherwood",
1830 | "role": "lead"
1831 | }
1832 | ],
1833 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
1834 | "homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
1835 | "keywords": [
1836 | "phpcs",
1837 | "standards"
1838 | ],
1839 | "time": "2020-10-23T02:01:07+00:00"
1840 | },
1841 | {
1842 | "name": "symfony/polyfill-ctype",
1843 | "version": "v1.20.0",
1844 | "source": {
1845 | "type": "git",
1846 | "url": "https://github.com/symfony/polyfill-ctype.git",
1847 | "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41"
1848 | },
1849 | "dist": {
1850 | "type": "zip",
1851 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f4ba089a5b6366e453971d3aad5fe8e897b37f41",
1852 | "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41",
1853 | "shasum": ""
1854 | },
1855 | "require": {
1856 | "php": ">=7.1"
1857 | },
1858 | "suggest": {
1859 | "ext-ctype": "For best performance"
1860 | },
1861 | "type": "library",
1862 | "extra": {
1863 | "branch-alias": {
1864 | "dev-main": "1.20-dev"
1865 | },
1866 | "thanks": {
1867 | "name": "symfony/polyfill",
1868 | "url": "https://github.com/symfony/polyfill"
1869 | }
1870 | },
1871 | "autoload": {
1872 | "psr-4": {
1873 | "Symfony\\Polyfill\\Ctype\\": ""
1874 | },
1875 | "files": [
1876 | "bootstrap.php"
1877 | ]
1878 | },
1879 | "notification-url": "https://packagist.org/downloads/",
1880 | "license": [
1881 | "MIT"
1882 | ],
1883 | "authors": [
1884 | {
1885 | "name": "Gert de Pagter",
1886 | "email": "BackEndTea@gmail.com"
1887 | },
1888 | {
1889 | "name": "Symfony Community",
1890 | "homepage": "https://symfony.com/contributors"
1891 | }
1892 | ],
1893 | "description": "Symfony polyfill for ctype functions",
1894 | "homepage": "https://symfony.com",
1895 | "keywords": [
1896 | "compatibility",
1897 | "ctype",
1898 | "polyfill",
1899 | "portable"
1900 | ],
1901 | "funding": [
1902 | {
1903 | "url": "https://symfony.com/sponsor",
1904 | "type": "custom"
1905 | },
1906 | {
1907 | "url": "https://github.com/fabpot",
1908 | "type": "github"
1909 | },
1910 | {
1911 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1912 | "type": "tidelift"
1913 | }
1914 | ],
1915 | "time": "2020-10-23T14:02:19+00:00"
1916 | },
1917 | {
1918 | "name": "theseer/tokenizer",
1919 | "version": "1.2.0",
1920 | "source": {
1921 | "type": "git",
1922 | "url": "https://github.com/theseer/tokenizer.git",
1923 | "reference": "75a63c33a8577608444246075ea0af0d052e452a"
1924 | },
1925 | "dist": {
1926 | "type": "zip",
1927 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a",
1928 | "reference": "75a63c33a8577608444246075ea0af0d052e452a",
1929 | "shasum": ""
1930 | },
1931 | "require": {
1932 | "ext-dom": "*",
1933 | "ext-tokenizer": "*",
1934 | "ext-xmlwriter": "*",
1935 | "php": "^7.2 || ^8.0"
1936 | },
1937 | "type": "library",
1938 | "autoload": {
1939 | "classmap": [
1940 | "src/"
1941 | ]
1942 | },
1943 | "notification-url": "https://packagist.org/downloads/",
1944 | "license": [
1945 | "BSD-3-Clause"
1946 | ],
1947 | "authors": [
1948 | {
1949 | "name": "Arne Blankerts",
1950 | "email": "arne@blankerts.de",
1951 | "role": "Developer"
1952 | }
1953 | ],
1954 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
1955 | "funding": [
1956 | {
1957 | "url": "https://github.com/theseer",
1958 | "type": "github"
1959 | }
1960 | ],
1961 | "time": "2020-07-12T23:59:07+00:00"
1962 | },
1963 | {
1964 | "name": "webmozart/assert",
1965 | "version": "1.9.1",
1966 | "source": {
1967 | "type": "git",
1968 | "url": "https://github.com/webmozart/assert.git",
1969 | "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389"
1970 | },
1971 | "dist": {
1972 | "type": "zip",
1973 | "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389",
1974 | "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389",
1975 | "shasum": ""
1976 | },
1977 | "require": {
1978 | "php": "^5.3.3 || ^7.0 || ^8.0",
1979 | "symfony/polyfill-ctype": "^1.8"
1980 | },
1981 | "conflict": {
1982 | "phpstan/phpstan": "<0.12.20",
1983 | "vimeo/psalm": "<3.9.1"
1984 | },
1985 | "require-dev": {
1986 | "phpunit/phpunit": "^4.8.36 || ^7.5.13"
1987 | },
1988 | "type": "library",
1989 | "autoload": {
1990 | "psr-4": {
1991 | "Webmozart\\Assert\\": "src/"
1992 | }
1993 | },
1994 | "notification-url": "https://packagist.org/downloads/",
1995 | "license": [
1996 | "MIT"
1997 | ],
1998 | "authors": [
1999 | {
2000 | "name": "Bernhard Schussek",
2001 | "email": "bschussek@gmail.com"
2002 | }
2003 | ],
2004 | "description": "Assertions to validate method input/output with nice error messages.",
2005 | "keywords": [
2006 | "assert",
2007 | "check",
2008 | "validate"
2009 | ],
2010 | "time": "2020-07-08T17:02:28+00:00"
2011 | },
2012 | {
2013 | "name": "wp-coding-standards/wpcs",
2014 | "version": "2.3.0",
2015 | "source": {
2016 | "type": "git",
2017 | "url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
2018 | "reference": "7da1894633f168fe244afc6de00d141f27517b62"
2019 | },
2020 | "dist": {
2021 | "type": "zip",
2022 | "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62",
2023 | "reference": "7da1894633f168fe244afc6de00d141f27517b62",
2024 | "shasum": ""
2025 | },
2026 | "require": {
2027 | "php": ">=5.4",
2028 | "squizlabs/php_codesniffer": "^3.3.1"
2029 | },
2030 | "require-dev": {
2031 | "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6",
2032 | "phpcompatibility/php-compatibility": "^9.0",
2033 | "phpcsstandards/phpcsdevtools": "^1.0",
2034 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
2035 | },
2036 | "suggest": {
2037 | "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
2038 | },
2039 | "type": "phpcodesniffer-standard",
2040 | "notification-url": "https://packagist.org/downloads/",
2041 | "license": [
2042 | "MIT"
2043 | ],
2044 | "authors": [
2045 | {
2046 | "name": "Contributors",
2047 | "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors"
2048 | }
2049 | ],
2050 | "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
2051 | "keywords": [
2052 | "phpcs",
2053 | "standards",
2054 | "wordpress"
2055 | ],
2056 | "time": "2020-05-13T23:57:56+00:00"
2057 | }
2058 | ],
2059 | "aliases": [],
2060 | "minimum-stability": "stable",
2061 | "stability-flags": [],
2062 | "prefer-stable": false,
2063 | "prefer-lowest": false,
2064 | "platform": [],
2065 | "platform-dev": [],
2066 | "plugin-api-version": "1.1.0"
2067 | }
2068 |
--------------------------------------------------------------------------------