Learning WardrobeCMS source code, how do they retrieve posts without db request? - laravel

Newbie here. I'm learning Laravel and WardrobeCMS is a good one to study IMO. Just wondering if you guys could point me how they retrieve posts with requesting db?
In homepage, the HomeController has this line.
$posts = $this->posts->active(Config::get('core::wardrobe.per_page'));
In WardrobeServiceProvider, they bind PostRepoitory with DbPostRepository and here is their 'active' method.
public function active($per_page)
{
$per_page = is_numeric($per_page) ? $per_page : 5;
\Debugbar::info('calling posts active method');
return Post::with(array('tags', 'user'))
->where('active', 1)
->where('publish_date', '<=', new DateTime)
->orderBy('publish_date', 'desc')
->paginate($per_page);
}
The return statement looks like the Eloquent command but I don't see any db request in Debugbar console. How does this work? Please advise.
I am a designer trying to learn coding and Laravel 'illuminates' me. In my current dev project, I have around 4-10 db calls in each page. My goal here is to reduce db calls as much as possible and I think WardrobeCMS source code is my starting point.

Post::with()->where()->paginate(); doesn't always 'call' database?
In short: Yes it does!
Post is an Eloquent ORM because, basically every model (i.e. Post) in Laravel extends the Eloquent/Model class and this Eloquent/Model class uses Query Builder (DB in your case) class along with other classes to query the database and in your example, the Post is something like this:
class Post extends Eloquent {
// ...
}
SInce the Post class extends the Eloquent class so Post have access (inherited from Eloquent) to all (protected and public only) methods of Eloquent class, so, if the Eloquent has a function/method like this (actually has):
public function with($relation)
{
//...
}
Then the Post class can call that function/method like this:
Post::with()
So, actually Post::with()->where()->paginate() call interact with database in this case but it's not necessary that every database interaction has to be using DB::table(), instead, it's a convenient way to query the database using an ORM and don't forget that, the ORM is just a wrapper over the query builder, behind the scene, the Post Eloquent Model is using the query builder.
You should the manual instead of reading the source code of another application, once you get the basic idea then you may read source code of other Laravel applications to get some ideas that other developers uses.
Update: If you are not seeing any queries in the debugger then the application is using the caching feature of Laravel to cache database queries for a certain period of time so it can use those later without interacting with the database to speed up the process.

Related

Is there any way to call multiple methods with one route in laravel?

I am trying to send some data to my admin dashboard page. The data is for two charts: the first displays the number of articles posted by users in the past week and the other displays the last five articles. However, each of these datas are returned from separate methods of my controller.
So far, I have fetched all the data I need from the database in one method and returned a view with all the data, In this way:
return view('admin', compact('lastUserPosts'))->with('week', json_encode($week))
->with('postNo', json_encode($postNo));
and a normal route like:
Route::get('/dashboard', [App\Http\Controllers\DashboardController::class, 'index'])->name('dashboard');
clearly I'm not following the single responsibility principle, so I'm wondering How can I write my code to fetch each set of data from its own method in controller and then call both of these methods in one route.
I would highly recommend that you watch Laracon EU conference there was a talk titled becoming a better developer by using the SOLID principles, aside from that what you can do is separate the logic of the contoller from formatting and fetching the data by creating a middle layer between it and the model something like a PostsRepository now this class should contain the fetching and ajax formating of the Model, import it in your contoller use App\Repository\PostsRepository and instead of the normal model that you enject to your controller method use the Repository instead
Public function getAllPosts( PostsRepository $post) {
.....
}
Now you have access to all the method of the Post model from a different class and you can also test it easily

Does Cache work in an API route and should we use it?

I am creating an API. In this API I am accessing a (permissions) table from a database multiple times, in middleware as well as in controllers. I was thinking, instead of accessing the database multiple times, why don't I call it once and use it multiple times. After calling it once, I could store it in the cache within a service provider. But I am not sure if it is a good way to go because API routes don't load all the services like session.
There are other ways like storing data into the config. Or create a class and make a facade for it and then call it when ever it is needed. But I am curious if the cache would work in API routes and would it be a good idea?
Okay with the advice of #lagbox I created a dead simple class.
namespace App\Helpers;
use App\Permission;
class Provide
{
public $permissions = [];
function __construct() {
$this->permissions = Permission::whereNotNull('route_name')->get();
}
}
This may vary, it's just a class that will keep some collection data in it. I named it provide to keep it generic, just in case that I could need other data than permission in the future. Of course this class could be more detailed but just for storing and returning permissions it is enough.
Then I bound it as a singleton in my AppServiceProvider to run it only once.
public function register()
{
$this->app->singleton('App\Helpers\Provide', function ($app) {
return new \App\Helpers\Provide();
});
}
and when I need it I call it like
$provide->permissions->toArray()
All the features of the collection are available everywhere from the beginning to the end. Yes that may look like an overkill or an abuse of IoC but this über simple approach is in my case a superb solution.

Where in Laravel 5.3 code to control content access based on published/unpublished status?

I have a guitar lessons site using Laravel 5.3. It has lessons that are then broken down into exercises.
I decided today to add in the backend the ability to mark lessons or exercises as published. I simply added a 'published' column in the respective tables which contains 0 or 1.
There are many places in my site where exercises or lessons are accessed in some shape or form, including a lesson view, exercise view, lessons partial view (a tabular listing), exercises partial view (also a tabular listing), search/query views. There are also routes that perform functions such as incrementing hit count for a lesson or exercise, adding a lesson or exercise to one's favorites.
Given above, I am not sure how to prevent access to unpublished lessons or exercises using minimal code edits. I started looking at the controller files but then realized the controller might not be a catch all, such as on query result pages. Also controller files contain multiple methods and I don't want to edit them separately. I suspect there is a "laravel way" to do what I need globally, without me having to modify a bunch of queries in multiple files. Maybe it amounts to middleware or something?
In any case, I am new to laravel and if there is a tried and true way to control routes for content that is marked as unpublished, I would be very interested to know about it.
thanks
Take a look at global scopes, laravelest way to do this
As an aside, I prefer to use timestamps for things like published states on models. It means I can set a future timestamp for that content to become available, i.e. if I’m going on holiday.
In terms of your actual problem, a query scope would be the way to go:
class Lesson extends Model
{
public function scopePublished($query)
{
return $query->wherePublished(true);
}
}
Alternatively, if you did use a timestamp instead, you could do:
class Lesson extends Model
{
public function scopePublished($query)
{
return $query->where('published', '<=', $this->freshTimestamp());
}
}
You will then need to update your front-end code to use this scope:
public function LessonController extends Controller
{
public function index()
{
$lessons = Lesson::published()->latest()->paginate();
return view('lesson.index', compact('lessons'));
}
}

Explanation needed for laravel avoid using static access

I would like to more in depth knowledge about using static methods . I'm using laravel 5.2 framework for my application.
In my application mostly i have used static functions For example i have model class name like post and method name is get_post() and its declared as static only if i missed static keyword in laravel it throws error
class Post extends Eloquent(){
public static function get_post(){
return DB::table('post')->get();
}
}
In my controller i will call this above method
Post::get_post()
How could i avoid to call this method as static ? as per the PHPMD 1.4.0 rule
Anyone please explain clearly.
Laravel's Eloquent is called via the static method, so I'm not sure how to avoid this. By the way, instead of the functions you wrote, you can of course write
Post::all();
Another abstraction possibility is to use the Repository Pattern, where the Controller doesn't call the Model's functions directly, but rather something like
$activePosts = $postRepository->getActiveAndApproved();
where the $postRepository would do some of the heavy lifting on Laravel's Eloquent model doing e.g. ->where('something', true) and stuff like that - Symfony has this already a bit stronger included in their framework.
See https://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5/ for more detailed instructions.
Seeing also that Laravel uses Facades a lot, which is a simplified way to access functions in the service container (e.g. see config/app.php or https://laravel.com/docs/5.2/facades for more infos), it might be difficult to avoid static function calls.

Symfony2 entityManager in model

I'm going to use entity_manager in my model. But entity_manager is only available in controller: throw $em = $this->get('doctrine.orm.entity_manager'). So, I have to define model methods with $em parameter. This is making phpUnit testing pretty difficult and violates application structure. For example:
class Settings
{
public static function getParam( $em, $key )
{
$em->createQuery("
SELECT s
FROM FrontendBundle:Settings s
WHERE s.param = {$key}
");
return $em->getResult();
}
}
Is there any approach to use entity_manager service in model section?
First, a starting note: by convention your Entity class should probably be singular. So, Setting, not Settings. You could argue that "settings" as a group of related settings could be seen as one entity. Still, something to bear in mind.
In Doctrine2, you would use a repository to make this type of query. In your code where you were going to call Settings::getParam, you would instead fetch the repository and query that. In symfony2, say:
// $em is your entitymanager, as you were going to pass to your method above
// $key is the key you were going to pass to your method above
$repository = $em->getRepository('\FrontendBundle\Settings');
$setting = $repository->getByParam($key);
By default, without writing any code, repositories define getByXXXX for each field in your entity.
If you have a more complicated query to make, you can extend the repository.
use Doctrine\ORM\EntityRepository;
class SettingsRepository extends EntityRepository
{
public function getBySomeComplicatedQuery() {
$sort_order = $this->getEntityManager()
->createQuery('SELECT count(s) FROM FrontendBundle\Settings s WHERE s.value > 32')
->getResult(Query::HYDRATE_SINGLE_SCALAR);
}
}
And then you'd call that method in the same way.
Others would advocate the use of a Manager object which would then not be tied to the Entity/ORM, but that's a needless complication in this case I think.
Doctrine2 is specifically designed to not let you use queries in your Entity file; Entities and EntityManagers are actually two aspects of the standard model layer, split apart to enforce best practices. See this article: http://symfony2basics.jkw.co.nz/get-symfony2-working/entities/
Queries in the Entity class
Putting queries in you entity seems odd to me. The same way as putting queries into your model class in Doctrine 1 it is not considered a good practice. Entity classes should be light.
I'm actually learning Doctrine2 and was thinking about similar problem: where to put queries?
In Doctrine 1 there are special Table classes and I was expecting something similar in Doctrine 2.
Repository Pattern
Today I learned that Doctrine 2 is using the Repository Pattern: http://www.doctrine-project.org/docs/orm/2.0/en/reference/working-with-objects.html#custom-repositories
However, to retrieve an instance of repository class you need to use Entity Manager. One way or another you need it.
Still, following the repository pattern seems a better choice.
In my opinion If you insist on having query method in your Entity class you have to pass an Entity Manager to it.
Testing
Why the need of passing entity manager makes it hard to test? From my experience explicit dependencies make testing easier as you can control them in the test (and mock them for example).
On the other hand passing the entity manager to every method is not right choice either. In such case I'd make the dependency obligatory and add it to the contructor.

Resources