In order to consolidate some bulky code in a controller I have been able to do this inside function
public function myCustomFunction(Request $request){
include(app_path() . '/myFunctions/myCustomFunction1.php');
}
It does successfully work but by doing the include, I noticed it doesnt carry the namespace and/or other variables set in the controller.
If its just a simple model it needs I was able to add
Use \App\myModel;
to the top of the controller and it runs the code just fine as if its part of the controller.
What I am having issue with is when I want to run validation. I cant figure out what to "use" to work on the included page.
If I run my logic in the controller without doing include it works, but if put inside the include it does not, and I get NO errors either.
I tried this inside the include page to activate the validation from within
the include file
namespace App\Http\Controllers;
use Validator;
use Request;
which mimics the original controller, but still does not work. Is what I'm trying to do possible but I'm doing something wrong? Or am I doing something that will never work? If all else fails I can keep the code within the actual controller to make it work, but I'm trying to accomplish some sort of clarity on complex controllers. Such as...
public function myCustomFunction(Request $request){
if(request('value1')=='1'){
include(app_path() . '/myFunctions/myCustomFunction1.php');
}else{
include(app_path() . '/myFunctions/myCustomFunction2.php');
}
}
This structure is already working on anything that doesn't need validation so I'm hoping there is a simple way to hook the include page into the same set of validation tools the original controller has access to.
In the controller, so include the files incorrectly. It's best for you to create a Helpers folder in the app folder, in it create classes with your functions.
namespace App\Helpers;
class HelpersOne {
public function myFunctionOne(){.../*youre code*/}
public function myFunctionTwo(){.../*youre code*/}
}
And already in your controller you can call these classes.
use App\Helpers\HelpersOne;
...
public function myCustomFunction(Request $request){
if(request('value1')=='1'){
$myFunction = new HelpersOne();
$myFunction->myFunctionOne();
}else{
$myFunction = new HelpersTwo();
$myFunction->myFunctionTwo();
}
}
Related
for clarify next part: payU is the Internet payment operator
I have a serious problem with integration my Angular app with payU payments. I won't store or pass credit card's data (security reasons) so I choose widget.
The first problem is how to place the widget in the code. Documentation says that I should place script in the following way:
<script
src="https://secure.payu.com/front/widget/js/payu-bootstrap.js"
pay-button="#pay-button"
merchant-pos-id="145227"
shop-name="Nazwa sklepu"
total-amount="9.99"
currency-code="USD"
success-callback="test"
sig="250f5f53e465777b6fefb04f171a21b598ccceb2899fc9f229604ad529c69532">
</script>
How you probably know, you can't set script in your code in this way in Angular so I decided use little walkaround:
ngAfterViewInit(): void {
this.script = document.createElement('script');
this.script.setAttribute('src', 'https://secure.payu.com/front/widget/js/payu-bootstrap.js');
this.script.setAttribute('pay-button', '#pay-button');
this.script.setAttribute('merchant-pos-id', '145227');
this.script.setAttribute('total-amount', '9.99');
this.script.setAttribute('currency-code', 'USD');
this.script.setAttribute('success-callback', 'test');
this.script.setAttribute('sig', '4752ce2b163684a9c27cc0923ad46068c04da5d34329f5669ce73dcf96394558');
this.renderer.appendChild(this.el.nativeElement, this.script);
}
I know it's not a perfect solution (if you know better way to do this, please let me know in comment.
But the main problem is pass name of callback function to success-callback attribute. I prepared function in my component, like:
test(arg: any) {
console.log(arg);
}
But I can't get this name. I was trying:
this.script.setAttribute('success-callback', this.test.name);
but property name is empty. Is there a simple way to get real name of method (after typescipt translating) in my component?
BTW.
Adding simple js script to index.html and providing its name works, but i need to call service within my function.
I'm using Angular v7.
Explanation:
Ok, let's start by explaining the script. Since the script is being added in the global namespace, the success callback refers to a global function with the name 'test' in your above code.
So we need a reference to the angular component's 'test' function in the global namespace of your app, so that it can be accessed on success callback.
In your component:
import {NgZone} from '#angular/core';
constructor(private zone:NgZone){
window.callbackComponentRef = {
testFn: (args) => {
this.zone.run(() => { this.test(args); })
}
};
}
test() {
//Whatever code you want to run
}
Then use in script addition code
this.script.setAttribute('success-callback', 'callbackComponentRef.testFn');
I have been looking around for quite a time, But didn't got anything convening.
What will be the best approach and practice to implement Vue MPA architecture in laravel.
Searched for quite a bit. But there isn't anything which will give you a clear idea. Your answer will help alot, Please make it brief.
It will also be helpful to answer the point :
Is it a good idea to use just laravel as a data API, And keep Vue
separate from laravel ?
Best approach for implementing hybrid of SPA and MPA.
Some options that I've already used:
Use Laravel to render the "main view" + connect vue.js application.
Basically laravel will render the Vue application and every request goes throught an API.
Easy to setup
Authentication + user validation is easier (you can use laravel session manager for that - don't need to build/use tokens or whatever. "No need to worry about your application state".)
Easy to "disconnect" from Laravel - if you choose in the future to decouple the SPA application.
Use laravel (or lumen) only as an API, and on another server render a SPA.
This can take more time, since you'll need to setup an extra server, prepare cross-origin, etc.
Also easy to setup, but can take more time than option #1
You'll need to create something for user validation/state management, etc.
Easy to place into laravel, if you decide in the future to use "only one app".
Can be easier to maintain/scale (if you have a frontend team, they don't need to worry about laravel - same for your "laravel team", they "won't need to worry" about the frontend)
Laravel + Vue = "one application"
You can use Laravel to render all views + vuejs for components/elements in the page.
Easy to setup. You have laravel + vuejs, and they are already prepared to be used together. https://laravel.com/docs/5.5/frontend#writing-vue-components
Not so easy to decouple. In this case you'll need to create the same views for vue.js. This can take time.
This is the "traditional web development" (in my opinion). If I had to start a project like this today, I wouldn't create all pages in Vue.js + something in Laravel (Controller + new route) to render this view. If you do this (again - my opinion), it's just extra work. If you are worried about SEO, there are "fallbacks"/extra options.
--
All options are testable + scalable.
It also depends on how you start (Should I worry about how I'll decouple the app in the future? Laravel + Vue will be for good?), how your team will work (Does the frontend team really needs to setup laravel or they only need to worry about the frontend code?), etc.
Not sure if i answered your question, if not, please leave a comment.
You haven't found anything clear because there isn't really anything to talk about other than 'What feels right to your understanding and project needs'. If you found yourself very unsure, feel free to dive into doing whatever makes sense to you and then re-adjust the structure when you gain more experience.
Also, read books about system architecture, those will help a lot.
Is it a good idea to use just laravel as a data API, And keep Vue separate from Laravel?
By this, I'm assuming you mean a SPA? Honestly, if your application is small, then I see this is fine.
Larger applications tend to be difficult to maintain if they were SPA.
Read: https://medium.com/#NeotericEU/single-page-application-vs-multiple-page-application-2591588efe58
If you end up using Laravel as an API endpoint, then use the stripped down version of it, Lumen, because it comes without Blade and few other stuff. Lumen is stripped down version to act as an API-endpoint.
Best approach for implementing hybrid of SPA and MPA.
From my experience having attempted to build 4+ projects as hybrids, here's what I found the most optimal structure:
My example will be about an app that saves 'Posts'.
1. Use a repository design pattern.
This one will save you a lot of headache in maintaining your code and maintain a DRY (Don't Repeat Yourself) concept on your code.
Create a directory App\Repositories\
Make a new class PostsRepository. This one will be the one communicating with the database and contains most of the logic.
Create the directory App\Services\
Make a new class PostsService. This one will have the PostsRepository in its constructor.
The service class will be one handling taking user's input whether from the Web controller or the API controller.
<?php
namespace App\Service;
use App\Repositories\PostsRepository;
class PostsService;
{
protected $repository;
public function __construct(PostsRepository $repository)
{
$this->repository = $repository;
}
}
Make a seperation between Web and API controllers.
For web controllers, you create the controller like usual:
php artisan make:controller PostsController
For API controllers, you create the controller to be inside an Api folder.
php artisan make:controller Api\PostsController
The last command will create the directory App\Http\Controllers\Api and have the controller be placed in it.
Recapping
Now we have different controllers to return results appropriate to the startpoint (web / api).
We have services that both the (web / api) controllers send their data to be validated (and have the action taken by the repository).
Examples:
<?php
namespace App\Http\Controllers;
use App\Service\PostsService;
class PostsController extends Controller
{
protected $service;
public function __construct(PostsService $service)
{
$this->service = $service;
}
public function index()
{
/**
* Instead of returning a Blade view and
* sending the data to it like:
*
* $posts = $this->service->all();
* return views('posts.index', compact('posts'));
*
* We go ahead and just return the boilerplate of
* our posts page (Blade).
*/
return view('posts.index');
}
}
...
<?php
namespace App\Http\Controllers\Api;
use App\Service\PostsService;
class PostsController extends Controller
{
protected $service;
public function __construct(PostsService $service)
{
$this->service = $service;
}
/**
* Returns all posts.
*
* A vue component calls this action via a route.
*/
public function index()
{
$posts = $this->service->all();
return $posts;
}
/**
* Notice we don't have a store() in our
* Web controller.
*/
public function store()
{
return $this->service->store();
}
}
...
<?php
namespace App\Services;
use App\Repositories\PostsRepository;
class PostsService extends Controller
{
protected $repository;
public function __construct(PostsRepository $repository)
{
$this->repository = $repository;
}
public function all()
{
$posts = $this->repository->all();
return $posts;
}
public function store()
{
$request = request()->except('_token');
$this->validation($request)->validate();
return $this->repository->store($request);
}
public function validation(array $data)
{
return Validator::make($data, [
'content' => 'required|string|max:255',
//
]);
}
}
In our PostsRepository we actually call methods that save the data. E.g. Post::insert($request);.
2. Dedicate an API group
Route::prefix('api/v1')->middleware('auth')->group(function() {
Route::post('posts/store', 'Api\PostsController#store')->name('api.posts.store');
});
Giving API routes a ->name() helps when you make phpunit tests.
3. Blade views
Those are ought to be stripped-down simple.
views/posts/index.blade.php:
#extends('layouts.app', ['title' => trans('words.posts')])
#section('content')
<!-- Your usual grid columns and stuff -->
<div class="columns">
<div class="column is-6">
<!-- This comp. can have a modal included. -->
<new-post-button></new-post-button>
<div class="column is-6">
<posts-index-page></posts-index-page>
</div>
</div>
#endsection
4. Vue structure.
https://github.com/pablohpsilva/vuejs-component-style-guide
So those Vue components might live in resources/assets/js/components/posts/ where inside /posts/ I'd have folders titled for example IndexPage, CreateModal, EditModal with each folder having its .vue and README.md.
I'd use the <posts-index-page> in index.blade.php and drop in the <post-create-modal> and <edit-post-modal> whenever I want.
All the vue components will use the API endpoint we specified in our Routes file.
I have a MVC .NET application with AngularJS. In my route provider I use the controllers of mvc for retreiving the views as follows:
.when('/Units', {
templateUrl: 'Unit/Units'
})
.when('/UnitsDetail', {
templateUrl: 'Unit/UnitsDetail'
})
And my .NET UnitController has the following methods:
[Authorize]
public ActionResult Units()
{
return View();
}
[Authorize]
public ActionResult UnitsDetail()
{
ViewBag.reference = Guid.NewGuid().ToString().Substring(0, 6);
return View();
}
For the UnitsDetail view I need a reference that is generated in the UnitsDetail() method.
The problem comes when I go from Units to UnitsDetail several times. The first time the UnitsDetail() method is called and thus, the reference is generated but if I go back to Units and access again UnitsDetail the method is not called and the reference is the same. I need to generate one reference each time.
I know I could generate it using JS in the client or make an AJAX request from Angular to the server but what I really want to know is how to make Angular call the method UnitsDetail() every time I go to "#/UnitsDetail".
Thanks!
By default angular will cache all views in its template cache.
This is by design.
Angular expects the view to be just static HTML with the dynamic part marked using the {{ dynamicScopeVariable }} code. Angular will use scope objects to replaces the dynamic bit . But the static part will be shown from the cache.
The first time you execute the view , the view is cached.
You have 2 options here. Actually just one which is good from the Design point of you #2.
Option #1
Disable template caching in Angular as shown here
https://stackoverflow.com/a/27432167/2794980
This means that angular will call the HTML ACTION every time it needs the view.
This is not the best way to use angualar but it will work. You should also consider the performance side .. By far the most time consuming call on a ASP.NET MVC applications are Actions calls. This method means that while you are using a client side MVC framework , you are not utilizing one of its important benifits.
Options #2
Use a angualar service to get the GUID from back end . i.e. the code below.
ViewBag.reference = Guid.NewGuid().ToString().Substring(0, 6);
Preferably use a WebAPI if u can ( your request will be small ). The use angular to replace the GUID in ur VIEW.
It is not clear from the question why you need the GUID and if you could do with generating a random unique number using Javascript . If that is possible , it might be the best solution . But based on the info in the question you could use either of option 1 or 2.
Edit : Didn't realize that you have already tried option 2 , in that case Option 1 it is.
Edit 2 : If you want to remove a single element from the cache , you can do
$templateCache.remove("<Element Name>");
or you could use the
$cacheFactory.remove("Name")
Read more about cache factory here :
https://docs.angularjs.org/api/ng/service/$cacheFactory
The name is generally the page name , you can look at the template cache or cache factory object in debugger console to find the exact name.
Liked the nice CSV parser & unparser of PapaParse. Can any one help me to get this combine with Angular JS.
I like to make PapaParse work in Angular Way. Trying for a solution.
I actually didn't do anything fancy to load it. Just add it to html file and to my lib folder. In my case: /lib/papaparse.min.js
and to index.html. As usual script:
<script src="lib/papaparse.min.js"></script>
then I just used it in my Controller:
Papa.parse(data, {
complete: function(results) {
console.log("Finished:", results.data);
}
});
You can use value to provide self contained third party libraries.
angular.module('your.app')
.value('yourLib', yourLib);
Then in your controller, or service, you would bring it in the normal way using DI
angular.module('your.app')
.controller('YourController', YourController);
YourController.$inject = ['yourLib'];
function YourController(yourLib) {
//. . .
}
If the third party line is a constructor function, requires it be newed, you may want to create a factory or a provider that has a method that accepts the passes params to the constructor returns a new instance.
Edit
After looking at PapaParse, you would want to register it with the angular injector using value.
just use a front-end modularization tool like requirejs to load papaParser in the context and call the api in any of your controller or service.
Just inject the script url in your index.html & then in your controller, access it as - var Papa = window.Papa;. That's it! You are ready for further actions!
I'm using jsRoutes in my Play 2.1.x app. Part of my routes file looks the following way:
GET /assets/template/js/routes/admin.js controllers.Admin.jsRoutes
GET /assets/template/js/routes/salonManagement.js controllers.SalonManagement.jsRoutes
And I would like to use both references in my scala template (that is by design, one controller contains necessary api functions, the other one necessary form submission urls).
So in my scala template I have the following part:
<script type="text/javascript" src="#routes.Admin.jsRoutes()"></script>
<script type="text/javascript" src="#routes.SalonManagement.jsRoutes()"></script>
Unfortunately, each generated javascript file starts with var jsRoutes = {};. Therefore, #routes.SalonManagement.jsRoutes() overrides properties of #routes.Admin.jsRoutes() and I can use only the last jsRoutes object.
Now, I know only one workaround. After each jsRoutes declaration I can insert a script that copies old jsRoutes object to a temporary object and then extends new jsRoutes with itself. But that doesn't look like the right way to go.
Isn't there any better way?
There's nothing special about the "jsRoutes" name. You can keep the same method name for consistency among the various controllers, but just pass a different name to the Routes.javascriptRouter method.
Put this in your template. I put it in a main template that wraps the other pages.
<script src="#controllers.routes.Application.jsRoutes()" type="text/javascript"></script>
and put this in your routes file
#jsroutes for ajax calls
GET /assets/js/routes controllers.Application.jsRoutes()
And then in your Application controller, refer to whatever method in whatever controller you want by implementing this method
public Result jsRoutes()
{
response().setContentType("text/javascript");
return ok(Routes.javascriptRouter("jsRoutes",
routes.javascript.Signup.forgotPassword(),
routes.javascript.Customers.findByName(),
routes.javascript.Customers.findByNumber()
));
}
These correspond with routes like
GET /customerfind/:name controllers.Customers.findByName(name: String)
Note there is no need to include parameters for the calls configured in the jsroutes method. Keeping all of this in one place, the Application controller, seems reasonable as long as it refers to methods implemented in their appropriate controller. Like in this example, a find on customer is in the Customers controller. Also, is kindof nice just having to check the one controller (Application) to see all the methods available through javascript routes for ajax calls.