Jump to content
Larry Ullman's Book Forums

another_noob

Members
  • Posts

    60
  • Joined

  • Last visited

  • Days Won

    3

another_noob last won the day on December 7 2014

another_noob had the most liked content!

another_noob's Achievements

Newbie

Newbie (1/14)

7

Reputation

  1. You still with us? I haven't seen a post in awhile which is unusual. I miss your input. I learned a lot of cool "tricks of the trade" from your posts. I hope all is well and you are busy making $$.
  2. I decided to install Yii2 on my Ubuntu server I use for live demo's for clients. While trying to install Composer I ran into permissions problems with this line of code: curl -sS https://getcomposer.org/installer | php I would get these errors: Downloading... Could not create file //composer.phar: fopen(//composer.phar): failed to open stream: Permission denied Download failed: fopen(//composer.phar): failed to open stream: Permission denied fwrite() expects parameter 1 to be resource, boolean given I prefaced the command with "sudo" and received the same permissions output. After some poking around I found the problem to be I needed to add a "sudo" after the pipe also. Like this: sudo curl -sS https://getcomposer.org/installer | sudo php After that, Things worked as expected. Hopefully this will save someone some agony someday.
  3. Good eye Larry! I am impressed that you spotted that. No one can ever say you aren't paying attention. I made the change and it works as expected. I over thought (and over looked) that detail. Thanks.
  4. I have refactored this jQuery click handler several times over. It has became the basis, and heart & soul, of several practice "single page applications". Now it looks like this: $(document).ready(function () { //Flag variable to track state of clicked element var btnProcessing; //Event attached to the document object $(document).click(function(e){ //target is the element clicked. e is the event if ($(e.target).is('.js_button') || $(e.target).is('.js_list_item')){ //Get the id of clicked element to use for the switch cases var element_id = e.target.getAttribute("id"); //Do not submit a form with a <button> click e.preventDefault(); //Keep event bubbling from duplicating events e.stopImmediatePropagation(); //Get the clicked button's default text var initial_text = $(e.target).text(); //Get the html5 data attribute from the clicked element to select the php switch case in ajax_action.php var ajax_action = e.target.getAttribute("data-ajax_action"); //Get the html5 data attribute from the clicked element to use as data for PHP/MySQL processing var ajax_data = e.target.getAttribute("data-ajax_data"); //If form submission, collect form data with serialize() if(element_id == 'js_submit'){ ajax_data = $('.js_form').serialize(); } //If clicked element is of class ".js_button" and not currently processing another request, or is of class ".js_list_item" if (($(e.target).hasClass( "js_button" ) && !btnProcessing) || ($(e.target).is('.js_list_item'))) { //Flag to denote processing btnProcessing = true; //Set visual feedback on button or list item $(e.target).text('Processing...'); //Process the request $.post('ajax_action.php', {ajax_data : ajax_data, ajax_action : ajax_action}, function(ajax_response){ //ajax response returns whatever the called script is written to return $('.ajax_div').html(ajax_response); //Got the response...free up the buttons btnProcessing = false; //re-set the element text back to the original value $(e.target).text(initial_text); }); } } }) }); I refactored it to follow some very basic conventions. Buttons will all be of class js_button and use the following example for all HTML5 data attributes: <buttons class="js_button" data-ajax_action="someFunction" data-ajax_data="someData">Click Me</button> Forms follow a simple convention: <form class="js_form"> //form fields as usual <button class="js_button" id="js_submit" data-ajax_action="someAction">Submit</button> </form> The ajax_action attribute will relate to a case of the same name in the ajax_action.php script which will call a function of the same name: case 'someFunction': someFunction($ajax_data); break; I use a mysqli_connect.php as a "model" type of thinking. In this script I have database interaction functions: function someFunction($ajax_data){ //Do some database CRUD stuff } Of course the $ajax_data parameter could (and should) be named something that makes sense to the query, like perhaps $customer_id or $customer_data. That would make it easier to see at a glance the function's purpose. I can submit form data and I can pass a php array as JSON with the data-ajax_data attribute. This has given me a lot of flexibility for SPA development. Following the required conventions of the click handler and with the required simple file structure, I have set up a simple to use MVC SPA where the index.php is the view, the ajax_action.php is controller and the mysqli_connect is the model. The click_handler.js file is the router...sort of. it all may appear convoluted...as most code does, it is quite simple to use. It is a lot of fun to play with and the possibilities are endless.
  5. Okay, so I got this working. Here is how I did it, probably is an easier way, but I don't know one. To get the PK of the client, I send it from the clientController's actionView function when a user clicks the view icon on the index page: public function actionView($id) { return $this->render('view', [ 'model' => $this->findModel($id), 'client_id' => $id, ]); } In My client/view script that renders the list of projects belonging to the client, I now have the $client_id variable available to send as an argument to the projectController's actionCreate function. I had to use 'yii\helpers\url' to take advantage of "url creation" in my button code. So now the client/view script that renders the list of projects belonging to a client looks like this: <?php use yii\helpers\Html; use yii\helpers\Url; use yii\widgets\DetailView; /* @var $this yii\web\View */ /* @var $model app\models\Client */ $this->title = $model->client; $this->params['breadcrumbs'][] = ['label' => 'Clients', 'url' => ['index']]; $this->params['breadcrumbs'][] = $this->title; ?> <div class="client-view"> <h1><?= Html::encode($this->title) ?></h1> <h3>Client Projects</h3> <ul> <?php foreach($model->projects as $project):?> <a href="index.php?r=project/view&id=<?= $project['id'] ?>" > <li> <?= $project['proj_name']?> </li> </a><br /> <?php endforeach;?> </ul> <?= Html::a('Add A New Project', Url::to(['project/create', 'client_id' => $client_id]), ['class' => 'btn btn-success']) ?> </div> Now when the "Add A New Project" button is clicked, the $client_id is passed to the projectController's actionCreate function which I have changed to accept an argument of $client_id. So now the projectController's actionCreate function looks like this: public function actionCreate($client_id) { $model = new Project(); if ($model->load(Yii::$app->request->post()) && $model->save()): return $this->redirect(['view', 'id' => $model->id]); else: return $this->render('create', [ 'model' => $model, 'client_id' => $client_id, ]); endif; } So now I have passed the $model and $client_id variables to the views/project/create script that now looks like this: <?php use yii\helpers\Html; /* @var $this yii\web\View */ /* @var $model app\models\Project */ $this->title = 'Create New Project'; $this->params['breadcrumbs'][] = ['label' => 'Projects', 'url' => ['index']]; $this->params['breadcrumbs'][] = $this->title; ?> <div class="project-create"> <h1><?= Html::encode($this->title) ?></h1> <?= $this->render('_form', [ 'model' => $model, 'client_id' => $client_id, ]) ?> </div> Which basically just renders the html form script that now has access to the $model and $client_id variables. The _form view script now looks like this: <?php use yii\helpers\Html; use yii\widgets\ActiveForm; /* @var $this yii\web\View */ /* @var $model app\models\Project */ /* @var $form yii\widgets\ActiveForm */ ?> <div class="project-form"> <?php $form = ActiveForm::begin(); ?> <?= $form->field($model, 'client_id')->input('hidden', ['value' => $client_id])?> <?= $form->field($model, 'proj_num')->textInput(['maxlength' => 10]) ?> <?= $form->field($model, 'proj_name')->textInput(['maxlength' => 100]) ?> <?= $form->field($model, 'pm_id')->textInput(['maxlength' => 10]) ?> <?= $form->field($model, 'date_started')->textInput() ?> <?= $form->field($model, 'date_closed')->textInput() ?> <?= $form->field($model, 'status')->textInput() ?> <div class="form-group"> <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> </div> <?php ActiveForm::end(); ?> </div> I went with a hidden form field to get the $client_id back to the controller->model for insertion into the database. I had to use trial and error on the hidden form field syntax because I couldn't find a single example anywhere for that. It works as expected, and now I can do the same for client contacts and for any specific contacts associated with a specific project. If anybody has a better yii 2 implementation of this idea, I am all eyes. There must be a simple one line of code solution at the model level, but I can't figure it out with my limited experience with Yii2/MVC/OOP.
  6. Thank you for your time Jonathon. I see what you are getting at. I don't think I was very clear in what my confusion is. I will explain this further. Same scenario, client->one-to-many->project. My client/index route renders a gridview of client names. I can click on the view icon to open a client/view&id=3 (for example). This will render my view that codes like this: <?php use yii\helpers\Html; use yii\widgets\DetailView; /* @var $this yii\web\View */ /* @var $model app\models\Client */ $this->title = $model->client; $this->params['breadcrumbs'][] = ['label' => 'Clients', 'url' => ['index']]; $this->params['breadcrumbs'][] = $this->title; ?> <div class="client-view"> <h3>Client Projects</h3> <ul class="list-project"> <?php foreach($model->projects as $project):?> <a href="index.php?r=project/view&id=<?= $project['id'] ?>" class=""> <li class="project_list_item"> <?= $project['proj_name']?> </li> </a> <?php endforeach;?> </ul> <?= Html::a('Add A New Project', ['project/create'], ['class' => 'btn btn-success']) ?> </div> This view gives me a list of hyperlinks of the current projects for the client with the id of 3. I can click a project hyperlink and the project/view&id=1 route will render a view showing all the pertinent details about the project. With the data I manually entered into my database tables all of this works the way I want it to. My confusion is this: in that view I have a button to create a new project for the client: <?= Html::a('Add A New Project', ['project/create'], ['class' => 'btn btn-success']) ?> This line of code renders the _form to enter a new project via the project/create route. I don't know how to get the client model PK to have available to insert into the project table thus cementing the relationship of this new project to the client with the id of 3, in this example. The Gii generated views/project/form: <?php use yii\helpers\Html; use yii\widgets\ActiveForm; /* @var $this yii\web\View */ /* @var $model app\models\Project */ /* @var $form yii\widgets\ActiveForm */ ?> <div class="project-form"> <?php $form = ActiveForm::begin(); ?> <?= $form->field($model, 'client_id')->textInput(['maxlength' => 10]) ?> <?= $form->field($model, 'proj_num')->textInput(['maxlength' => 10]) ?> <?= $form->field($model, 'proj_name')->textInput(['maxlength' => 100]) ?> <?= $form->field($model, 'pm_id')->textInput(['maxlength' => 10]) ?> <?= $form->field($model, 'date_started')->textInput() ?> <?= $form->field($model, 'date_closed')->textInput() ?> <?= $form->field($model, 'status')->textInput() ?> <div class="form-group"> <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> </div> <?php ActiveForm::end(); ?> </div> From a user's perspective it has to as easy as this: The User sees a list of clients, Compuware U of M Baseball U of M Football U of M Hockey U of M School of Social Study Whirlpool User clicks a client choice (view icon) and is then presented the list of current projects for that client and and the end of the list has a button to add a new project to the list that is automatically linked to the client, without the use needing to remember anything about the client that they clicked. The dropdown idea would work, but my users will be able to add a football stadium project to Whirlpool instead of U of M Football as they intended. Sometimes it takes me a bit to explain the problem I am having in a coherent fashion because I don't completely understand what I am trying to say. I think this is a more lucid explanation than last night's ramblings.
  7. I hunkered down this winter to get a better grasp on OOP, MVC, frameworks, and then Yii. Now I am trying to apply all this new knowledge, or my lack of... which is about to become very obvious. I have a very simple application design concept that works flawlessly in procedural PHP. A simplified version looks like this: A database table of "client" and a table of "project". A one (client) to many (project) relationship with a "client_id" foreign key relating to "id" in client table. Couldn't be simpler. I use composer to spin up a Yii 2 skeleton, change the config/db file to my database settings. Now with Gii I spin up my models and CRUD. Gii even sets up the table relationships...magic I say! Here is what I don't get about all this: Gii spins up the necessary CRUD forms which is great, but the project form has no knowledge of the client model. If I go to "localhost/myapp/web/index.php?r=project/create" I get the project entry form, but the first form entry is client ID. That is fine if I know the "id" from the client model. I don't understand how I link a project model to a client model dynamically in code. If Gii knew about the one->many relationship of these two tables, why not give me the model link in code to allow adding a project to the client with some PK to FK linked forms. I am baffled by this. I don't see how to make this happen with the Gii generated code. This was incredibly simple in my procedural projects. I must have missed a tidbit of knowledge somewhere that explains how I do this simple thing with the Yii framework. I don't expet Yii or Gii to read my mind and do what I am thinking, I know I need to write code to get what I want and be gracious to Gii for all of the time saving boiler plate code. If anyone can enlighten me a tad or point me to the sentence I missed that makes this concept clear, I would greatly apprciate it. Oh, I am using Yii 2, but it shouldn't matter for this question.
  8. Thanks HartleySan for the reply. I got it to work with a variation of your suggestion. Before I posted for help, I did try exactly what you suggested, I got a newline, but I would get a "undefined variable $dbc" notice and $dbc would be blank in the generated string. I had to initialize $dbc to a string literal '$dbc' for it to show up as a variable in the generated string. Like this: function make_mysqli_connection_file($db_host,$db_user,$db_pass,$db_name){ $dbc='$dbc'; $mysqli_connect_file = fopen("includes/mysqli_connect.inc.php", "w") or die("Unable to open file!"); $conn_string = "<?php \r\n $dbc = mysqli_connect ('" . $db_host . "', '" . $db_user . "', '" .$db_pass . "', '" . $db_name . "') OR die('Could not connect to MySql: ' . mysqli_connect_error() )"; fwrite($mysqli_connect_file, $conn_string); fclose($mysqli_connect_file); } Now I get the output I need in my auto generated connection script. This is a fun little project that I have become obsessed with...too much time on my hands I guess. Oh well, even if it goes nowhere, I learned a lot. Thanks again.
  9. Perhaps this thread started by chop may be of some help: http://www.larryullman.com/forums/index.php?/topic/3568-e-mail-issues-related-to-php-mail-form/
  10. I am creating a basic application framework just for a challenging project. Things are going good except for this silly problem: function make_mysqli_connection_file($db_host,$db_user,$db_pass,$db_name){ $mysqli_connect_file = fopen("includes/mysqli_connect.inc.php", "w") or die("Unable to open file!"); $conn_string = '<?php $dbc = mysqli_connect ("' . $db_host . '", "' . $db_user . '", "' . $db_pass . '", "' . $db_name . '") OR die("Could not connect to MySql: " . mysqli_connect_error() );'; fwrite($mysqli_connect_file, $conn_string); fclose($mysqli_connect_file); } This function will create an "includes" directory and a "mysqli_connect.inc.php" file with the standard connection string, it works as expected. The problem is that I want a newline after the opening php tag. I have tried double quoting the string, single quoting and all the necessary concatenation combinations necessary to keep the variables correct. The current output of the function is this: <?php $dbc = mysqli_connect ("localhost", "root", "", "database_test") OR die("Could not connect to MySql: " . mysqli_connect_error() ); And what I want is this: <?php $dbc = mysqli_connect ("localhost", "root", "", "database_test") OR die("Could not connect to MySql: " . mysqli_connect_error() ); It seems so simple, but the solution is eluding me. If I can get this solved I can move forward on other parts of this script. Thanks for any advice!
  11. I had a similar complaint from a client recently. He was not receiving registration confirmation emails when his students registered for training. I used my several different email addresses in place of his and all worked fine. What I found was this: he had an AOL email account, AOL blacklisted the IP address from his shared hosting account at HostGator. I found this out by digging into the log file in his HostGator CPanel. Apparently, some knucklehead was sending oodles of spam mail from his shared host server, so... AOL blacklisted the IP, which probably affected a lot of website's email functionality. He created a gmail email account and all is well. That's all I got...
  12. I added a needed feature to the click handler. I need to select the "action" for the controller switch case, but some times I do need a database record id from the from the button click. So I came up with a generic data attribute I will call an "extra". In my HTML here is an example how I will do it: <button id="get_dmd_form" class="button" data-action="get_dmd_pdf" data-extra="'.$dmd_row['repair_id'].'">Get DMD Form</> Now if I keep this generic attitude in my handler like this: if(extra != null){ var data = 'action=' + action + '&extra=' + extra; }else{ var data = 'action=' + action; } Then in the PHP controller script: case 'get_dmd_pdf': $repair_id = isset($_POST['extra']) ? $_POST['extra'] : NULL; display_dmd_pdf($repair_id); break; In the controller is where I actually break from generic to specific by naming the variable to something meaningful. In this case the function sets up an fpdf document and outputs it for download. The handler in it's entirety now looks like this: $(document).ready(function(repair_id){ //Flag variable to track state of clicked button var btnProcessing; //Event attached to the document object $(document).click(function(e){ //target is the button clicked. e is the event if ($(e.target).is('.button')){ //Get the clicked button's default text var initial_text = $(e.target).text(); //Get the html data attribute from the clicked button to select the php switch case var action = e.target.getAttribute("data-action"); //Set up an additional data attribute here var extra = e.target.getAttribute("data-extra"); //Set up the ajax data variable to select the correct switch case in action.php, name and append the extra data to the action variable if needed if(extra != null){ var data = 'action=' + action + '&extra=' + extra; }else{ var data = 'action=' + action; } //If class of "button" and not currently processing another request if ($(e.target).hasClass( "button" ) && !btnProcessing) { //Flag to denote processing btnProcessing = true; //Visual feedback on button $(e.target).text('Processing...'); //Process the request $.post('modules/action.php', data, function(ajax_response){ //ajax response returns whatever the called script is written to return $('.placeholder_div').html(ajax_response); //Got want we wanted...free up the buttons btnProcessing = false; //re-set the button text back to the original value $(e.target).text(initial_text); });//$.post }//if ($(e.target).hasClass }//if ($(e.target).is('.button') })//$(document).click(function(e) });//ready Works great.
  13. I am glad I pursued this. I learned several big new things which will help me get to that ever elusive "next level", it's like a never ending ladder. Attaching the click event to the Document Object solved another issue for me. I was having trouble with dynamically created elements and attaching click events with one script. Sometimes I had to create another javascript file to attach click handlers to the dynamically created elements. I would then have to include that script in my PHP function or PHP script. It was getting confusing to keep things straight. This solved all those problems because the click handler works great on dynamically created content elements. The data-key="value" attribute is clearly explained in a HTML5 book I have, but the author was explaining how to set dimensions of pop-ups with it, so I wasn't interested in pop up windows and skipped over those few (now very important) pages. I gotta learn to pay better attention when reading. Thanks for the nudge in the right direction!
  14. Once again HartleySan, Thank you for you time! I couldn't just leave it the way it was knowing that you suggested a better way. With some sleep, time to think, research things a little, and comparing to your javascript example, I think I have it! It works perfectly. I monitored things closely each step in firebug console and confirmed values with console.log(). I clicked away like a madman and no problems. The flag variable allowed me to eliminate the functions and function calls previously used to toggle the text values...sweet! Here is my latest code: $(document).ready(function(){ //Flag variable to track state of clicked button var btnProcessing; //Event attached to the document object $(document).click(function(e){ //target is the button clicked. e is the event if ($(e.target).is('.button')){ //Get the clicked button's default text var initial_text = $(e.target).text(); //Get the html data attribute from the clicked button var action = e.target.getAttribute("data-action"); //Set up the ajax data variable to select the correct switch case in action.php var data = 'action=' + action; //If class of "button" and not currently processing another request if ($(e.target).hasClass( "button" ) && !btnProcessing) { //Flag to denote processing btnProcessing = true; //Visual feedback on button $(e.target).text('Processing...'); //Process the request $.post('modules/action.php', data, function(ajax_response){ //ajax response returns whatever the called script is written to return $('.placeholder_div').html(ajax_response); //Got want we wanted...free up the buttons btnProcessing = false; //re-set the button text back to the original value $(e.target).text(initial_text); });//$.post }//if ($(e.target).hasClass }//if ($(e.target).is('.button') })//$(document).click(function(e){ });//ready Now all I do is always use .button as the class name for a button (a no brainer) and use html data-key="value" to feed to the PHP ajax controller script and I never have to reinvent the wheel to process my ajax calls. I think I should be able modify this code to work more generically too. I am thinking about when I attach a click event to a list item. Thanks for your help! This is a cool piece of code! If you see anything that should be changed let me know.
  15. I spent some time with your suggestions and I am half way there. Here is the HTML: <script src="js/admin_dashboard.js"></script> <?php include('includes/mysqli_connect.inc.php'); //All button ids will correspond to the associated action called in the jquery click handler echo'<div class="admin_buttons_div"> <button id="get_user_table" data-action="get_user_table" class="button">View Users</button> <button id="get_dmd_info" data-action="get_dmd_info" class="button">Get DMD Report</button> <button id="get_dmd_entry" data-action="get_dmd_entry" class="button">DMD Entry</button> <button id="button_4" class="button">button_4</button> <button id="button_5" class="button">button_5</button> <button id="button_6" class="button">button_6</button> </div>'; //This is our place holder div to contain our ajax responses echo'<div class="placeholder_div"></div>'; And here is the refactored jquery: //admin_dashboard.js $(document).ready(function(){ $('.button').on('click',function(evt){ //disable the other buttons temporarily $('.button').prop( "disabled", true ); //Get a reference to the clicked button var button = this; //Get the data attribute from the clicked button var action = button.getAttribute("data-action"); //Set the ajax data and the action variable for the called php script - action.php var data = 'action=' + action; //Get the clicked button's default text var initial_text = $(this).text(); //Button was clicked...give the user some visual feedback processing(button); //Send the ajax data request to the action.php script $.post('modules/action.php', data, function(ajax_response){ //ajax response returns whatever the called script is written to return $('.placeholder_div').html(ajax_response); //re-enable the other buttons now $('.button').prop( "disabled", false ); //Set the button text back to it's default value $(button).text(initial_text); });//$.post });//End click function //Give the user some visual feedback after a button click function processing(button){ $(button).text('Processing...'); } //Reset the button text to the default static text set in the calling script function done_processing(initial_text){ $(button).text(initial_text); } });//ready I couldn't get the flag to work correctly for me, I could still click like a madman on the buttons and cause too much processing at once. I will revisit that when I have more time. For now, it works and I have to move on. I do really like the data-key="value" attribute concept. It gives us more flexibility when integrating ajax calls into the fold. I played around with it and see many places in my other code where it would have helped big-time. For instance in a case where I need to get the value from, say for example, a <li> which was generated from a mySQL fetch and is made clickable with jquery: <li id="part-num" class="part-num_422">122-12345AZS</li> And then I have to break down the class in jquery to extract the id of the part number, instead I can use this: <li id="part-num" class="whatever" data-part-id="'. $php_variable .'" >122-12345AZS</li> Now it is a snap to grab the id and process as needed. Or is this a bad practice to set the data-key="value" dynamically from a database with PHP?
×
×
  • Create New...