Jump to content
marcus

wireshell - an extendable ProcessWire command line interface

Recommended Posts

The thing with Windows is that it doesn't automatically pick up the laravel command like *nix can, which is why a batch file needs to be created. However, because your wireshell file is looking for the vendor directory inside it's own, it doesn't work. As such, you'll need to change your request for autoload.php to this (the way Laravel's installer does it):

if (file_exists(__DIR__.'/../../autoload.php')) {
    require __DIR__.'/../../autoload.php';
} else {
    require __DIR__.'/vendor/autoload.php';
}

Then, the user can create a wireshell.bat file in a directory visible to the windows path containing this:

@echo off
php "%appdata%\Composer\vendor\wireshell\wireshell\wireshell" %*

This works on my side.

Update: If using mingw32 or cygwin, however, this isn't necessary - it's just a matter of adding %appdata%\Composer\vendor\wireshell\wireshell\wireshell to the path.

  • Like 1

Share this post


Link to post
Share on other sites

The thing with Windows is that it doesn't automatically pick up the laravel command like *nix can, which is why a batch file needs to be created. However, because your wireshell file is looking for the vendor directory inside it's own, it doesn't work. As such, you'll need to change your request for autoload.php to this (the way Laravel's installer does it):

if (file_exists(__DIR__.'/../../autoload.php')) {
    require __DIR__.'/../../autoload.php';
} else {
    require __DIR__.'/vendor/autoload.php';
}

Then, the user can create a wireshell.bat file in a directory visible to the windows path containing this:

@echo off
php "%appdata%\Composer\vendor\wireshell\wireshell\wireshell" %*

This works on my side.

Update: If using mingw32 or cygwin, however, this isn't necessary - it's just a matter of adding %appdata%\Composer\vendor\wireshell\wireshell\wireshell to the path.

Thanks for the support on this - I'll outline the cygwin scenario in the installation instructions.

/edit: Updated start post and WS to 0.3.1 :)

Share this post


Link to post
Share on other sites

Perfect - any time. Oh, and I made a mistake. When using cygwin/mingw32, the path is actually "%appdata%\Composer\vendor\wireshell\wireshell\". I added in an extra wireshell there...

Share this post


Link to post
Share on other sites

Big update! Version 0.3.0 comes with:

  • a new "NewCommand" provided by HariKT! Big thanks again. This contribution should lead to a better workflow with Wireshell since it opens up the possibility to install PW via command line in a convenient way
  • A command for creating fields
  • A command for assigning fields to existing templates
  • A generic backup command (DB dump)
  • Commands for en/disabling modules (downloading them via Wireshell is still on my bucket list)
  • A little command outputting the currently installed ProcessWire version
  • An unified approach to naming commands and classes: entity:verb, so for example user:create
  • I dropped the "(Experimental)" from the topic's title  ;)

Read more about the available new commands and their options in the readme.

If you have an older version of Wireshell installed, make sure you "$ composer update" it in order to get the new dependencies. And we're on packagist now: https://packagist.org/packages/wireshell/wireshell

So far so good :D .

for the command wireshell backup:db I suggest renaming it to db:backup 

so for example if you implement a db replace or db merge command in the future.

the command will became.

db:backup // Dumps an entire db
db:replace // Delete existing db and replace it with a backed one
db:merge // Merge the existing db with the data from a backed one

Again thanks for the great work.

Share this post


Link to post
Share on other sites

So far so good :D .

for the command wireshell backup:db I suggest renaming it to db:backup 

so for example if you implement a db replace or db merge command in the future.

the command will became.

db:backup // Dumps an entire db
db:replace // Delete existing db and replace it with a backed one
db:merge // Merge the existing db with the data from a backed one

Again thanks for the great work.

Thanks! The idea behind backup:db is that backup is the entity/namespace, and you can specify:

:db for database

:files for /site/assets/files

:scripts for all scripts (/site + /wire + root files)

:all for :scripts + :db

  • Like 3

Share this post


Link to post
Share on other sites

Marcus, this looks fantastic, thanks for all your hard work!

Not hard at all - fun, as I'm dealing with amazing tools (ProcessWire, Symfony, Composer packages) and learn a lot on the way :)

  • Like 7

Share this post


Link to post
Share on other sites

I've just started a new project and decided to test/use Wireshell.

After I had successfully created a new project I missed the opportunity to download modules. You've received a new pull request^_^ Maybe you have some time to test (and hopefully implement) it.

  • Like 9

Share this post


Link to post
Share on other sites

Just received the mail from GitHub! Nice! Trying it out over the weekend! Big thanks!

Share this post


Link to post
Share on other sites

This seems to gain some traction, great job @marcus :)

  • Like 2

Share this post


Link to post
Share on other sites

Finally I have had time to download it. Its simply fantastic and a lot of fun! :)

Regarding the windows users I share how I have set it up. Its only a bit slightly different than the very good explanation here from @marcus and @Mike_Anthony. I have done installation step 1 and 2, but not step 3. Instead of adding something to my path I simply created a single wireshell.bat file that I put somewhere into my already existing system path.

I also have no PHP directory accessible through the system path, because I use minimum 5 different PHP versions (3 for CLI and 2 with the local Apache). If there were one in the system path this can lead to weird behavior of PHP, at least with the old PHP 4 that I need for older CLI tasks. :)

My wireshell.bat looks like

@ECHO OFF
SET phpexe=C:\bin\php-54\php.exe
SET phpparams=-c C:\bin\php-54\wireshell\
SET wireshell=%appdata%\Composer\vendor\wireshell\wireshell\wireshell

TITLE WIRESHELL :: %CD%
"%phpexe%" %phpparams% "%wireshell%" %*
TITLE %CD%

With the phpparam -c I have specified a directory where the php interpreter has to pickup its php.ini. I have one setup that is different than I need with other CLI scripts. I also could have linked to the php directory what is running under apache. But unfortunately I switch this between php 5.3.8 and 5.4.x for modules testing currently. (and composer and wireshell needs minimum 5.4.0)

That with setting the title in the cli windows is nice if you have running several tasks. When hovering over the stacked icons on the taskbar, you can see which one is in "WIRESHELL mode" and which one is finished. :)

post-1041-0-89062800-1429395080_thumb.pn

post-1041-0-67908800-1429395092_thumb.pn

  • Like 5

Share this post


Link to post
Share on other sites

justb3a's great ModuleDownloadCommand has just hit the develop branch! Next, I'll try to incorporate Nico's module generator, and then both new Commands will be released as 0.4.0 :)

@horst: Thanks for sharing your approach! Since the Readme and this topic's start post is getting bigger and bigger I'll set up a dedicated microsite for wireshell doc and best practices like these.

  • Like 7

Share this post


Link to post
Share on other sites

marcus I really like where this is heading. keep up the great work!

  • Like 1

Share this post


Link to post
Share on other sites

Thanks, felix!

New on develop branch:
 

$ wireshell status

(Replacing ShowAdminUrlCommand, ShowVersionCommand)

wireshell-status.gif

Edited by marcus
  • Like 6

Share this post


Link to post
Share on other sites

Thank you for putting this together. This is absolutely great :)

I came over from Joomla some time ago and one of the many joomla devs have created joomla-console. They combine it with their joomla-vagrant box which is a great tool for development. I am actually still using it for quick setup of PW projects  ;) And I've been thinking for quite some time how great it would be to have a console tool for PW. And now it is here. So big thumbs up!

I see that there is some kind of naming convention for commands now. Have you ever considered renaming the 'new' to 'site:create' Thats what joomla-console uses and they also have a 'site:delete'.

Share this post


Link to post
Share on other sites

I see that there is some kind of naming convention for commands now. Have you ever considered renaming the 'new' to 'site:create' Thats what joomla-console uses and they also have a 'site:delete'.

I think the context may be wrong. I don't know Joomla at all, but, to me, site:create would imply a multi-site environment, especially considering the existence of site:delete. Or am I wrong?

Share this post


Link to post
Share on other sites

@marcus, when I have read this about status, it came to my mind that we already have those Diagnostic Tools. Do you already know them?

Maybe it is possible to integrate some of the submodules into wireshell by calling status:(submodule)?

post-1041-0-39532900-1429966323_thumb.jp

post-1041-0-25733900-1429966342_thumb.jp

Edited by horst
added screenshots
  • Like 4

Share this post


Link to post
Share on other sites

That's a good idea!

Instead of status:submodule I'd suggest to add it as options, like:
 

$ wireshell status --php --filesystem --image --webserver

...and output each block/topic as a separate table (see screenshot above).

Without options wireshell status would just return the PW and wireshell info.

Either way: I'll look into Diagnostic Tools as soon as I finish 0.4.0 and the project microsite. Of course pull requests for this, maybe from the Diagnostic Tools creators & contributors themselves, would be highly appreciated :)

  • Like 2

Share this post


Link to post
Share on other sites

I think the context may be wrong. I don't know Joomla at all, but, to me, site:create would imply a multi-site environment, especially considering the existence of site:delete. Or am I wrong?

In the joomla-vagrant context it makes perfect sense because with that command you can setup a new site in a subdomain so you can have multiple dev sites residing in one virtual machine. But I see your point when considering multi site environments.

Share this post


Link to post
Share on other sites

Of course pull requests for this, maybe from the Diagnostic Tools creators & contributors themselves, would be highly appreciated :)

Hehe, started! ;):biggrin:

post-1041-0-12706300-1429985194_thumb.pn

  • Like 4

Share this post


Link to post
Share on other sites

People, this is really awesome!  ^-^ 

When I started this little project I had a little hope for community contributions a) because of the vibrant PW community and b) the modular architecture of Symfony Console, but I would have never expected this growth within a month. Big thanks to all contributing and fixing commands and ideas! 

@horst: Bam! Delivered! Cheers!  :P I'll look into it, merge it soon and will establish a proper namespace for the growing number of helper classes.

One more thing: I hate to have hobby horse projects without at least a rudimentary logo  :biggrin: 

ws_draft.gif
 

  • Like 4

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By louisstephens
      Going through my long quest to get better with ajax and utilizing the api, I have hit yet another roadblock. I currently have a form with an image field (thanks to flydev for getting that sorted), "title" text input, and a select field set to multiple. In my ajax call, I added in:
      tags = $("#select-tags").val(); form_data.append('tags', tags); $.ajax({ type: 'POST', data: form_data, contentType: false, processData: false, url: '/ajax/upload-preview/', success: function(data) { console.log("Woo"); }, error: function(xhr, ajaxOptions, thrownError) { alert(xhr.responseText); } }); And in the ajax template: 
      $tags = $sanitizer->text($_POST['tags']); $image = $sanitizer->text($_POST['image']); $p = new Page(); $p->template = "preview"; $p->parent = $pages->get("/previews/"); $p->name = $title; $p->title = $title; $p->tags = $tags; $p->save(); If I select a "tag" from the select input and submit, it does indeed add it to the Page Reference field in the backend. However, this does not work with an array being passed to it of multiple options.

      So it does appear that my ajax call is trying to submit multiple options, but I am really just unsure how to get these two added in. I saw in other forums posts of add($page) and even add(array()). Do I need to handle this js array differently or do  I need to foreach through the $tags to add it like:
      foreach($tags as $tag) { $p->tags->add($tag); $p->save(); } I tried this approach, but apparently I am still missing something.
       
      Edit:
      I was doing some tweaking, and I know I can split the js array out like:
      for (i = 0, len = tags.length; i < len; i++) { console.log(tags[i]); } However, I am not sure then how to handle the POST in php if I were to split it out.
    • By louisstephens
      I have been messing around with creating pages from ajax requests, and it has gone swimmingly thus far. However, I am really struggling with creating a page and saving an image via ajax. 
      The form:
      <form action="./" role="form" method="post" enctype="multipart/form-data"> <div> <input type="text" id="preview" name="preview" placeholder="Image Title"> </div> <div> <input type="file" id="preview-name" name="preview-name"> </div> <div> <select id="select-tags" name="select-tags"> <?php $tags = $pages->find("template=tag"); ?> <option value="">Select Your Tags</option> <?php foreach ($tags as $tag) : ?> <option value="<?= $tag->name; ?>"><?= $tag->name; ?></option> <?php endforeach; ?> </select> </div> <div> <button type="button" id="submit-preview" name="submit" class="">Upload Images</button> </div> </form>  
      The ajax in my home template:
      $('#submit-preview').click(function(e) { e.preventDefault(); title = $("#preview").val(); image = $("input[name=preview-name]"); console.log(title); console.log(image); data = { title: title, image: image //not sure if this is actually needed }; $.ajax({ type: 'POST', data: data, url: '/development/upload-preview/', success: function(data) { console.log("Woo"); }, error: function(xhr, ajaxOptions, thrownError) { alert(xhr.responseText); } }); }); And finally in my ajax template:
      $imagePath = $config->paths->assets . "files/pdfs/"; //was from an older iteration $title = $sanitizer->text($_POST['title']); $image = $sanitizer->text($_POST['image']); $p = new Page(); $p->template = "preview"; $p->parent = $pages->get("/previews/"); $p->name = $title; $p->title = $title; $p->save(); $p->setOutputFormatting(false); $u = new WireUpload('preview_image'); $u->setMaxFiles(1); $u->setOverwrite(false); $u->setDestinationPath($p->preview_image->path()); $u->setValidExtensions(array('jpg', 'jpeg', 'gif', 'png', 'pdf')); foreach($u->execute() as $filename) { $p->preview_image->add($filename); } $p->save(); I can complete the file upload but just using a simple post to the same page and it it works well, but I was really trying to work out the ajax on this so I could utilize some modals for success on creation (and to keep my templates a little cleaner). When I do run the code I have, a new/blank folder is created under assets, and a new page is created with the correct title entered. However, no image is being processed. I do get a 200 status in my console. I have searched google for help, but everything seems to be slightly off from my needs. If anyone could help point me in the right direction I would greatly appreciate it. 
    • By louisstephens
      This might be a completely dumb question, but I cant seem to wrap my head around it. I have a page reference field that allows users to select "Tags". In the front end I would like to use the titles as class names for a single item. ie:
      <?php $previews = $pages->find("template=preview"); ?> <?php foreach($previews as $preview): ?> <div class="tagOne TagTwo tagThree"> <!-- use another foreach to output--> <img src="<?=$preview->preview_image->url; ?>" /> </div> <?php endforeach; ?> I am little stumped as I know I need a foreach loop to produce each tag title, but how do I insert them all into one corresponding div class with spaces?
      Whelp, that was the easiest thing, but my brain just didnt "get it". Just put the foreach in the "class" inside of the overall foreach. Ugh 😓
    • By schwarzdesign
      We recently rebuilt the Architekturführer Köln (architectural guide Cologne) as a mobile-first JavaScript web app, powered by VueJS in the frontend and ProcessWire in the backend. Concept, design and implementation by schwarzdesign!
      The Architekturführer Köln is a guidebook and now a web application about architectural highlights in Cologne, Germany. It contains detailled information about around 100 objects (architectural landmarks) in Cologne. The web app offers multiple ways to search through all available objects, including:
      An interactive live map A list of object near the user's location Filtering based on architect, district and category Favourites saved by the user The frontend is written entirely in JavaScript, with the data coming from a ProcessWire-powered API-first backend.
      Frontend
      The app is built with the Vue framework and compiled with Webpack 4. As a learning exercise and for greater customizability we opted to not use Vue CLI, and instead wrote our own Webpack config with individually defined dependencies.
      The site is a SPA (Single Page Application), which means all internal links are intercepted by the Vue app and the corresponding routes (pages) are generated by the framework directly in the browser, using data retrieved from the API. It's also a PWA (Progressive Web App), the main feature of which is that you can install it to your home screen on your phone and launch it from there like a regular app. It also includes a service worker which catches requests to the API and returns cached responses when the network is not available. The Architekturführer is supposed to be taken with you on a walk through the city, and will keep working even if you are completely offline.
      Notable mentions from the tech stack:
      Vue Vue Router for the SPA functionality VueX for state management and storage / caching of the data returned through the API Leaflet (with Mapbox tiles) for the interactive maps Webpack 4 for compilation of the app into a single distributable Babel for transpilation of ES6+ SASS & PostCSS with Autoprefixer as a convenience for SASS in SFCs Google Workbox to generate the service worker instead of writing lots of boilerplate code Bootstrap 4 is barely used here, but we still included it's reboot and grid system Backend
      The ProcessWire backend is API-only, there are no server-side rendered templates, which means the only PHP template is the one used for the API. For this API, we used a single content type (template) with a couple of pre-defined endpoints (url segments); most importantly we built entdpoints to get a list of all objects (either including the full data, or only the data necessary to show teaser tiles), as well as individual objects and taxonomies. The API template which acts as a controller contains all the necessary switches and selectors to serve the correct response in <100 lines of code.
      Since we wanted some flexibility regarding the format in which different fields were transmitted over the api, we wrote a function to extract arbitrary page fields from ProcessWire pages and return them as serializable standard objects. There's also a function that takes a Pageimage object, creates multiple variants in different sizes and returns an object containing their base path and an array of variants (identified by their basename and width). We use that one to generate responsive images in the frontend. Check out the code for both functions in this gist.
      We used native ProcessWire data wherever possible, so as to not duplicate that work in the frontend app. For example:
      Page names from the backend translate to URLs in the frontend in the form of route parameters for the Vue Router Page IDs from ProcessWire are included in the API responses, we use those to identify objects across the app, for example to store the user's favourites, and as render keys for object lists Taxonomies have their own API endpoints, and objects contain their taxonomies only as IDs (in the same way ProcessWire uses Page References) Finally, the raw JSON data is cached using the cache API and this handy trick by @LostKobrakai to store raw JSON strings over the cache API.
      Screenshots














    • By VeiJari
      Hello forum!
      I've yet again stumbled on a head-scratching situation. We have enabled the option on our articles template and events template that it skips the title adding part and goes straight to the form. This is what our customer wants. So when you add a new article or event it automatically names it temporary to "article-0000000" and same with event. Now the problem is that obviously after saving the form we want to change to page url or "name" to the title, like it's normally. 
      Now here's the code for the hook:
      wire()->addHookBefore("Pages::saved(template=tapahtuma|artikkeli)", function($hook) {
        $page = $hook->arguments(0);
        $newUrl = wire()->sanitizer->pageName($page->title); // give it a name used in the url for the page
        wire()->log->message($page->name);
        $page->setAndSave('name', $newUrl);
      });
      I get the correct page and the name and path changes when I log them, but when I try to save it. It just loads and then I get: 
      Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 262144 bytes) This happens in sanitizer.php
      and then another error: Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 262144 bytes) in Unknown on line 0
       
      What is happening? Am I not suppose to use sanitizer in this way? When we made a temporary page object in out other hook, the sanitizer worked perfectly.
      Thanks for the help!
×
×
  • Create New...